Как сделать так, чтобы яснипет и компания работали лучше?

22

В моем emacs, скажем, я использую "elisp"yasnippet для расширения блока lisp в режиме org. Но прежде чем продлить его, сначала запускается компания, которая дает мне меню, как "1. elisp1, 2. elisp2"без опции "elisp". Теперь, если я использую tabдля расширения yasnippet, это всегда раздражает, что "elisp1"всегда сначала идет на экране. Поэтому мне нужно "1"сначала удалить и сделать фрагмент кода yasnippet.

Поэтому в качестве решения я всегда использую левую клавишу со стрелкой, чтобы сначала отключить меню завершения компании, но теперь курсор переместится на "elis|p", поэтому я снова использую правую клавишу со стрелкой, чтобы переместить курсор в конец "elisp|"и расширить фрагмент.

Здесь возникает мой вопрос: как я могу связать tabключ в первую очередь, вызвать Ясниппет, но не компанию, чтобы спасти мне жизнь?

Leu_Grady
источник
1
Я использую tabдля companyи C-oдля yasnippet. Я могу описать дальше, если вам интересно.
abo-abo
@ abo-abo, спасибо, ответ. Я знаю, что могу сделать это так же, как и вы, но я связываю Ко с другой командой, и плохо тренировал мышцу руки, чтобы адаптироваться tab. Поэтому я не хотел бы менять привязку.
Leu_Grady
Вот почему я спросил :) Нет смысла рассказывать, как C-oможно расширять аббревиатуры, фрагменты, открытые строки и т. Д., Если вам это не интересно.
abo-abo
кажется интересным, вы можете описать больше? :)
Leu_Grady

Ответы:

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>должен перейти непосредственно к следующему заполнителю.

Тот факт, что имя фрагмента не появляется в меню компании, а наличие фрагмента молча изменяет поведение клавиши табуляции, не очень приятно, к сожалению ... Хотя, по крайней мере, можно <return>вместо этого набрать, чтобы получить завершение вместо фрагмента.

Кристоф Марусси
источник
Это, кажется, мешает Magit. Заставляет вкладку магнита поднять Buffer is read-only: #<buffer *magit: ~/.emacs.d/*>. Есть идеи, как я могу это исправить?
zsquare
@zsquare Я не использую magit (я знаю, я чокнутый), поэтому я не могу проверить это, чтобы быть уверенным, но это звучит так, будто раскладка magit для TAB, к которой он привязанmagit-section-toggle , противоречит приведенной (global-set-key [tab] 'tab-indent-or-complete)выше строке . Быстрое и грязное исправление состоит в том, чтобы добавить проверку в начале функции tab-indent-or-completeвыше, чтобы увидеть, находимся ли мы в режиме magit, например, для глобальной переменной, которая включена magit-mode-hook.
dodgethesteamroller
это здорово, спасибо! :) маленькая точка стиля, whenв значительной степени if+progn
Мэтт Бриггс
@zsquare Для поддержки вкладки в режиме magit добавьте это в tab-indent-or-completecond `((производный-режим-p 'magit-mode) (magit-section-toggle (magit-current-section)))`
Bae
Чтобы поддерживать ido вместо завершения минибуфера по умолчанию, замените cond на `((minibufferp) (ido-complete))`
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от авто-yasnippet делает более простой open-line:

  • он пытается расширить аббревиатуры
  • он пытается перейти к следующему полю яснипета
  • он пытается расширить Яснипет
  • наконец, это вызывает, open-lineесли все остальное терпит неудачу
Або-або
источник
спасибо за ваш фрагмент. Вполне нормально. Но проблема все еще существует. Когда я в первый раз использую C-o, он просто закрывает меню компании, поэтому мне нужно дважды нажать, чтобы расширить yasnippet.
Leu_Grady
У меня нет такой проблемы: C-oпри активном меню компании закроет меню и развернет фрагмент.
abo-abo