如何使yasnippet和公司更好地工作?


22

假设在我的emacs中,我使用"elisp"yasnippet扩展了组织模式下的lisp块。但是在我扩展它之前,首先会触发公司,这给了我一个菜单,就像"1. elisp1, 2. elisp2"没有选项"elisp"。现在,如果我tab用来扩展yasnippet,"elisp1"总是首先出现在屏幕上总是很烦人。所以我需要先删除"1",然后再扩展yasnippet片段。

因此,作为解决方案,我总是使用左箭头键先关闭公司完成菜单,但现在光标将移至"elis|p",因此再次使用右箭头键将光标移到的末尾"elisp|"并扩展代码段。

我的问题来了:我该如何tab首先绑定密钥才能触发yasnippet,但不触发公司挽救生命?


1
我使用tabfor companyC-ofor yasnippet。如果您有兴趣,我可以进一步描述。
abo-abo

@ abo-abo,谢谢回复。我知道我可以像您一样做,但是我将Co绑定到其他命令,并且很糟糕,我训练了我的手部肌肉以适应tab。所以我不想更改绑定。
Leu_Grady'2

这就是为什么我问:)毫无意义的是,C-o如果您不感兴趣的话,如何扩展缩写词和摘要以及空白行等。
abo-abo

似乎很有趣,您能描述更多吗?:)
Leu_Grady

Answers:


22

这是我为自己创建的,面临同样的问题。它来自公司模式的Emacs Wiki页面,但进行了大量扩展:

(defun check-expansion ()
  (save-excursion
    (if (looking-at "\\_>") t
      (backward-char 1)
      (if (looking-at "\\.") t
    (backward-char 1)
    (if (looking-at "->") t nil)))))

(defun do-yas-expand ()
  (let ((yas/fallback-behavior 'return-nil))
    (yas/expand)))

(defun tab-indent-or-complete ()
  (interactive)
  (cond
   ((minibufferp)
    (minibuffer-complete))
   (t
    (indent-for-tab-command)
    (if (or (not yas/minor-mode)
        (null (do-yas-expand)))
    (if (check-expansion)
        (progn
          (company-manual-begin)
          (if (null company-candidates)
          (progn
            (company-abort)
            (indent-for-tab-command)))))))))

(defun tab-complete-or-next-field ()
  (interactive)
  (if (or (not yas/minor-mode)
      (null (do-yas-expand)))
      (if company-candidates
      (company-complete-selection)
    (if (check-expansion)
      (progn
        (company-manual-begin)
        (if (null company-candidates)
        (progn
          (company-abort)
          (yas-next-field))))
      (yas-next-field)))))

(defun expand-snippet-or-complete-selection ()
  (interactive)
  (if (or (not yas/minor-mode)
      (null (do-yas-expand))
      (company-abort))
      (company-complete-selection)))

(defun abort-company-or-yas ()
  (interactive)
  (if (null company-candidates)
      (yas-abort-snippet)
    (company-abort)))

(global-set-key [tab] 'tab-indent-or-complete)
(global-set-key (kbd "TAB") 'tab-indent-or-complete)
(global-set-key [(control return)] 'company-complete-common)

(define-key company-active-map [tab] 'expand-snippet-or-complete-selection)
(define-key company-active-map (kbd "TAB") 'expand-snippet-or-complete-selection)

(define-key yas-minor-mode-map [tab] nil)
(define-key yas-minor-mode-map (kbd "TAB") nil)

(define-key yas-keymap [tab] 'tab-complete-or-next-field)
(define-key yas-keymap (kbd "TAB") 'tab-complete-or-next-field)
(define-key yas-keymap [(control tab)] 'yas-next-field)
(define-key yas-keymap (kbd "C-g") 'abort-company-or-yas)

基本上,这使大多数时间<tab>做正确的事情。按选项卡将

  • 缩进当前行
  • 如果有要扩展的Yasnippet,请展开它,即使这意味着中止公司完成(我并没有使用太多缩写,因此尚无缩写支持),
  • 如果正在进行公司完成,请填写所选项目,
  • 否则,请尝试使用公司开始自动完成,
  • 如果没有要自动完成的内容,并且我们位于yasnippet占位符中,请跳至下一个占位符。

请注意,如果有机会自动完成,并且您当前正在代码段占位符中进行编辑,则情况就很模糊了。作为一种妥协,我必须C-<tab>直接跳到下一个占位符。

不幸的是,该片段的名称未出现在公司菜单中,并且该片段的存在以无提示方式修改了Tab键的行为,这一事实并不是特别好,尽管至少可以键入<return>以获取完成内容的摘要。


这似乎干扰了magit。使magit中的tab升高Buffer is read-only: #<buffer *magit: ~/.emacs.d/*>。知道我该如何解决吗?
zsquare 2015年

@zsquare我不使用magit(我知道,我很疯狂),因此无法确定是否进行测试,但这听起来像magit的TAB键盘映射(将其绑定到magit-section-toggle)与(global-set-key [tab] 'tab-indent-or-complete)上面的行冲突。一个快速而肮脏的解决方法是在上述函数的开头添加一个检查,tab-indent-or-complete以查看我们是否处于magit模式,例如,设置为的全局变量magit-mode-hook
dodgethesteamroller 2015年

这太棒了,谢谢!:)风格小点,when几乎是if+progn
Matt Briggs

@zsquare要在magit模式下支持选项卡,请将其添加到cond` tab-indent-or-complete(((derived-mode-p'magit-mode)(magit-section-toggle(magit-current-section))))
Bae

要支持ido而不是默认的minibuffer完成,请用`((minibufferp)(ido-complete))`替换cond
Bae

10

这是我正在使用的代码:

(global-set-key "\C-o" 'aya-open-line)

(defun aya-open-line ()
  "Call `open-line', unless there are abbrevs or snippets at point.
In that case expand them.  If there's a snippet expansion in progress,
move to the next field. Call `open-line' if nothing else applies."
  (interactive)
  (cond ((expand-abbrev))

        ((yas--snippets-at-point)
         (yas-next-field-or-maybe-expand))

        ((ignore-errors
           (yas-expand)))

        (t
         (open-line 1))))

aya-open-line来自auto-yasnippet的功能不只是简单的open-line

  • 它试图扩大缩写
  • 它尝试移动到yasnippet的下一个字段
  • 它试图扩大yasnippet
  • 最后,open-line如果其他所有方法都失败,它将调用

谢谢你的摘录。非常好。但是问题仍然存在。第一次使用时C-o,它只是关闭公司菜单,因此我需要按两次以扩展yasnippet。
Leu_Grady'2

我没有这样的问题:C-o公司菜单处于活动状态时,将关闭菜单扩展代码段。
abo-abo 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.