Como tornar o yasnippet e a empresa mais agradáveis?

22

No meu emacs, digamos, eu uso um "elisp"yasnippet para estender um bloco lisp no modo org. Mas antes que eu a estenda, a empresa é acionada primeiro, o que me dá um menu como "1. elisp1, 2. elisp2"sem opção "elisp". Agora, se eu uso tabpara estender o yasnippet, é sempre irritante que "elisp1"sempre seja exibido na tela. Portanto, preciso excluir "1"primeiro e fazer a extensão do snippet yasnippet.

Portanto, como solução, eu sempre uso a tecla de seta para a esquerda para desativar o menu de conclusão da empresa, mas o cursor agora é direcionado para "elis|p", então, novamente, uso a tecla de seta para a direita para mover o cursor até o final "elisp|"e estender o snippet.

Aí vem minha pergunta: como posso ligar a tabchave primeiro para ativar o yasnippet, mas não a empresa para me salvar a vida?

Leu_Grady
fonte
1
Estou usando tabpara companye C-opara yasnippet. Eu posso descrever mais se você estiver interessado.
abo-abo
@ abo-abo, obrigado resposta. Sei que posso fazer isso como você, mas vinculo Co a outro comando e mal treinei meu músculo da mão para se adaptar tab. Então, eu não gostaria de alterar a ligação.
31515 Leh_Grady
Foi por isso que perguntei :) Não faz sentido discutir como C-oexpandir abreviações, trechos e linhas abertas etc., se você não estiver interessado.
abo-abo
parece interessante, você pode descrever mais :)?
Leu_Grady

Respostas:

22

Foi isso que eu criei para mim mesmo, enfrentando o mesmo problema. É da página do Wiki do Emacs no modo da empresa , mas muito extensa:

(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)

Basicamente, isso faz <tab>a coisa certa na maioria das vezes. Pressionando a guia

  • Recuar a linha atual,
  • Se houver um yasnippet para expandir, expanda-o, mesmo que isso signifique abortar a conclusão de uma empresa (não uso muito as abreviações, portanto ainda não há suporte para abreviações),
  • Se a conclusão de uma empresa estiver em andamento, complete com o item selecionado,
  • Caso contrário, tente usar a empresa para iniciar o preenchimento automático,
  • Se não houver nada para ser preenchido automaticamente e estivermos em um espaço reservado de yasnippet, pule para o próximo espaço reservado.

Observe que, se houver uma oportunidade de preenchimento automático e você estiver editando atualmente em um espaço reservado para trecho, a situação é ambígua. Como compromisso, C-<tab>pulei diretamente para o próximo espaço reservado.

O fato de o nome do snippet não aparecer no menu da empresa e a existência de um snippet modificar silenciosamente o comportamento da tecla tab não é particularmente agradável, infelizmente ... Embora seja possível digitar <return>para obter a conclusão, pelo menos do trecho.

Kristóf Marussy
fonte
Isso parece interferir no magit. Faz com que a guia no magit aumente Buffer is read-only: #<buffer *magit: ~/.emacs.d/*>. Alguma idéia de como eu posso consertar isso?
zsquare 5/09
@zsquare Eu não uso o magit (eu sei, sou louco), então não posso testar isso para ter certeza, mas parece que o mapa de teclas do magit para TAB, que o vinculamagit-section-toggle , está em conflito com a linha (global-set-key [tab] 'tab-indent-or-complete)acima. Uma solução rápida e suja seria adicionar uma verificação no início da função tab-indent-or-completeacima para ver se estamos no modo magit, por exemplo, para uma variável global que é ativada magit-mode-hook.
Dodgethesteamroller
isso é incrível, obrigado! :) ponto de estilo pequeno, whené praticamente um if+progn
Matt Briggs
@zsquare Para suportar a guia no modo magit, adicione-o ao tab-indent-or-completecond `((modo derivado-p 'magit-mode) (magit-section-toggle (magit-current-section)))`
Bae
Para dar suporte ao ido em vez da conclusão padrão do minibuffer, substitua o cond por `((minibufferp) (ido-complete))`
Bae Bae
10

Aqui está o código que estou usando:

(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-linedo auto-yasnippet faz mais do que um simples open-line:

  • ele tenta expandir abreviações
  • ele tenta passar para o próximo campo do yasnippet
  • ele tenta expandir o yasnippet
  • finalmente, chama open-linese tudo mais falhar
abo-abo
fonte
obrigado pelo seu snippet. Muito bom. Mas o problema ainda existe. Quando o uso pela primeira vez C-o, basta fechar o menu da empresa, por isso preciso pressionar duas vezes para estender o yasnippet.
31515 Leu_Grady
Não tenho esse problema: C-ocom o menu da empresa ativo, o menu será fechado e será expandido.
abo-abo