¿Cómo hacer que yasnippet y compañía funcionen mejor?

22

En mis emacs, digamos, uso un "elisp"yasnippet para extender un bloque lisp en modo org. Pero antes de extenderlo, la compañía se activa primero, lo que me da un menú como "1. elisp1, 2. elisp2"sin opción "elisp". Ahora, si uso tabpara extender yasnippet, siempre es molesto que "elisp1"siempre aparezca primero en la pantalla. Por lo tanto "1", primero debo eliminar y hacer la extensión del fragmento de yasnippet.

Entonces, como solución, siempre uso la tecla de flecha izquierda para desactivar primero el menú de finalización de la empresa, pero el cursor ahora irá a "elis|p", así que nuevamente uso la tecla de flecha derecha para mover el cursor al final "elisp|"y extender el fragmento.

Aquí viene mi pregunta: ¿cómo puedo vincular la tabclave en primer lugar yasnippet pero no la compañía para salvarme la vida?

Leu_Grady
fuente
1
Estoy usando tabpara companyy C-opara yasnippet. Puedo describir más si estás interesado.
abo-abo
@ abo-abo, gracias respuesta. Sé que puedo hacerlo como tú, pero ato a Co a otro comando, y mal he entrenado el músculo de mi mano para adaptarme tab. Por lo tanto, no me gustaría cambiar el enlace.
Leu_Grady
Es por eso que pregunté :) No tiene sentido C-ohablar sobre cómo podría ampliar abreviaturas y fragmentos y líneas abiertas, etc., si no está interesado.
abo-abo
parece interesante, ¿puedes describir más? :)
Leu_Grady

Respuestas:

22

Esto es lo que creé para mí, enfrentando el mismo problema. Es de la página Wiki de Emacs del modo empresa , pero muy extendida:

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

Básicamente, esto hace <tab>hacer lo correcto la mayor parte del tiempo. Al presionar la pestaña

  • Sangrar la línea actual,
  • Si hay un yasnippet para expandir, amplíelo, incluso si esto significa abortar la finalización de una empresa (no uso muchas abreviaturas, por lo que todavía no hay soporte para abreviaturas),
  • Si la finalización de una empresa está en curso, complete con el elemento seleccionado,
  • De lo contrario, intente utilizar la compañía para iniciar el autocompletado,
  • Si no hay nada que completar automáticamente y estamos en un marcador de posición yasnippet, salte al siguiente marcador de posición.

Tenga en cuenta que si existe la oportunidad de autocompletar y está editando actualmente en un marcador de posición de fragmento, la situación es ambigua. Como compromiso, estoy obligado C-<tab>a saltar directamente al siguiente marcador de posición.

El hecho de que el nombre del fragmento no aparezca en el menú de la empresa y la existencia de un fragmento que modifique en silencio el comportamiento de la tecla de tabulación no es particularmente agradable, desafortunadamente ... Aunque al menos es posible escribir en su <return>lugar para completarlo. del fragmento.

Kristóf Marussy
fuente
Esto parece interferir con el magit. Provoca el aumento de la pestaña en magit Buffer is read-only: #<buffer *magit: ~/.emacs.d/*>. ¿Alguna idea de cómo puedo arreglar eso?
zsquare
@zsquare No uso magit (lo sé, estoy loco), así que no puedo probar esto para estar seguro, pero parece que el mapa de teclas de magit para TAB, que lo unemagit-section-toggle , está en conflicto con la línea (global-set-key [tab] 'tab-indent-or-complete)anterior. Una solución rápida y sucia sería agregar una marca al comienzo de la función tab-indent-or-completeanterior para ver si estamos en modo magit, por ejemplo, para una variable global que se activa magit-mode-hook.
dodgethesteamroller
esto es genial, gracias! :) pequeño punto de estilo, whenes prácticamente un if+progn
Matt Briggs
@zsquare Para admitir la pestaña en modo magit, agregue esto a la tab-indent-or-completecondición `((deriva-mode-p 'magit-mode) (magit-section-toggle (magit-current-section)))`
Bae
Para admitir ido en lugar de la finalización predeterminada del minibúfer, reemplace el cond con `((minibufferp) (ido-completo))`
Bae
10

Aquí está el código que estoy 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-linefrom auto-yasnippet hace más que un simple open-line:

  • trata de expandir abreviaturas
  • intenta pasar al siguiente campo de yasnippet
  • trata de expandir yasnippet
  • finalmente, llama open-linesi todo lo demás falla
abo-abo
fuente
Gracias por tu fragmento. Bastante bueno. Pero el problema aún existe. Cuando lo uso por primera vez C-o, solo cierra el menú de la compañía, por lo que necesito presionar dos veces para extender yasnippet.
Leu_Grady
No tengo ese problema: C-ocon el menú de la empresa activo cerrará el menú y expandirá el fragmento.
abo-abo