Mal: asignaciones de teclas del mapa a la manera vim?


13

Estoy tratando de hacer que la función del Mal evil-jump-to-tag, C-]se comportan como los Emacs vinculante M-..

El comportamiento normal está bien para explorar archivos de etiquetas, pero quiero que funcione también para Slime's slime-edit-definition, Elisps ' elisp-slime-nav-find-elisp-thing-at-point, Clojures cider-jump-to-var, etc.

Estos modos principales y muchos más han vinculado algún equivalente de salto a definición a la combinación de teclas M-..

Para obtener el mismo comportamiento para el modo Evil, ¿necesito vincular una combinación de teclas localmente para cada uno de estos modos, o es posible tomar una combinación de teclas y decirle a Emacs que cada vez que se presiona esta tecla, use la función asociada a esa tecla? en modo Emacs?


Relacionado (un enfoque más directo similar a vim): emacs.stackexchange.com/q/12287/8283
idbrii

Respuestas:


10

Lo tengo funcionando ahora, gracias a tus respuestas:

(defun my-jump-to-tag ()
  (interactive)
  (evil-emacs-state)
  (call-interactively (key-binding (kbd "M-.")))
  (evil-change-to-previous-state (other-buffer))
  (evil-change-to-previous-state (current-buffer)))

(define-key evil-normal-state-map (kbd "C-]") 'my-jump-to-tag)

Esto establecerá el estado maligno en "Emacs", llamará a la función vinculada a M- y volverá al estado anterior de emacs en el otro búfer. Lo probé con elisp, slime and go y funciona para todos ellos.


1
Lo que uso es más simple y parece funcionar totalmente bien: (define-key evil-normal-state-map (kbd "C-]") (kbd "\\ M-.")(donde "\" está obligado a evil-execute-in-emacs-state).
shosti

@shosti: Sí, esto debería funcionar al menos también. Lo intenté así, pero no incluí el espacio entre la segunda \ y la M.
martin

3

Intenta algo como

(global-set-key "\C-]" "\M-.")

o, si evilya usa esta combinación de teclas, es posible que deba hacer algo como esto.

(define-key evil-mode-map "\C-]" "\M-.")

Esto anulará por completo el comportamiento de C-], si desea mantener el comportamiento del mal dependiendo del modo principal actual, la solución de @ Tyler es más apropiada porque puede tener una función que decida si llama M-.o hace algo mal.

¿Esto ayuda?


2

No entiendo evillos mapas de teclas, pero la siguiente función hace todo lo que M-.está obligado en este momento:

(defun my-tag-jump ()
    (interactive)
    (call-interactively (key-binding (kbd "M-."))))

Vincular esto al evilmapa de teclas apropiado debería hacer lo que desea. Puede haber una forma más evilespecífica de hacer esto.

evilSe liga C-]en evil-motion-state-map, a fin de tratar lo siguiente:

(eval-after-load "evil-maps"
    '(define-key evil-motion-state-map "\C-]" 'my-tag-jump))

No veo cómo esto podría trabajar así, porque se une de modo mal M-.a evil-repeat-pop-next. Si cambia su función a esto: (defun my-tag-jump () (interactivo) (evil-emacs-state) (call-interactively (key-binding (kbd "M-."))) (Evil-normal- estado))
Martin

Como dije, no conozco mapas de teclas malvados. Quizás la mejor solución es encontrar el mapa de teclas donde evil-jump-to-tagestá definido y volver a vincularlo a mi función allí.
Tyler

2

En general, no es posible.

La razón es que puede haber varios mapas que definen el mismo enlace, y no hay forma de averiguar automáticamente cuál desea. (en su ejemplo, elisp-slime-nav-modees un modo menor). Entonces, el único enfoque realmente confiable es que usted descubra exactamente qué definición desea.

Dicho esto ... hay un posible hack (no siempre existe ...) Parte de lo que lo hace difícil es que el enlace que desea reasignar ya está potencialmente enmascarado por un mapa de teclas activo malvado, por lo que obtener el enlace actual de M-.es inútil

(defun lookup-no-evil (key)
  ;; excluding evil maps from the lookup. not sure if 
  ;; anything more than evail-normal-state-map is needed
  (let* ((evil-maps (list evil-normal-state-map))
         (bindings
          (remq nil
                (mapcar
                 (lambda (map)
                   (unless (memq map evil-maps)
                     (lookup-key map key)))
                 (current-active-maps)))))
    (when bindings
      ;; let's assume the first one is the right one. 
      ;; Given that minor modes are at the beginning 
      ;; (although this is *not* documented so should not 
      ;; be relied upon), it might be what we would have 
      ;;without evil-mode indeed
      (car bindings))))

(defmacro evil-remap (from to)
  ;; assuming that we want to put it in the normal-state map.
  ;; not sure about that
  `(define-key evil-normal-state-map ,to
       (lambda ()
         (interactive)
         (call-interactively (lookup-no-evil ,from)))))

(evil-remap (kbd "M-.") (kbd "C-]"))

Normalmente no uso el mal en absoluto, por lo que podría ser necesario hacer ajustes (ver comentarios incrustados)

Además, un enfoque más limpio sería buscar los enlaces una vez (en un enlace de modo, por ejemplo), en lugar de buscar dinámicamente cada vez que se presiona el teclado. Pero no estoy seguro de qué gancho malvado usar, así que esto se deja como ejercicio;) (y dependiendo del orden que use para sus modos menores, o si los alterna dinámicamente, puede ser incorrecto)


2

La solución aceptada por @severin casi funciona para mí, pero, cuando no se encuentra la etiqueta, el búfer no vuelve al modo normal. Esta alternativa me funciona en todos los casos:

(defun my-jump-to-tag ()
    (interactive)
    (evil-execute-in-emacs-state)
    (call-interactively (key-binding (kbd "M-."))))
(define-key evil-normal-state-map (kbd "C-]") 'my-jump-to-tag)

1

Creo que la forma más limpia es

(define-key evil-normal-state-map (kbd "M-.") 'xref-find-definitions)

(y también agregue cualquier otro mapa que le interese)

xref-find-definitionses la función enlazada M-.en emacs, como puede ver usando el comando C-h k.


1

Algunas funciones de combinación de teclas de estilo vim.

Aquí hay algunas funciones que he definido para permitir el enlace de estilo vim en el mapa global y varios estados malvados, así como dos funciones generales que toman un mapa de teclas arbitrario o una función de enlace arbitrario. He puesto estas funciones en una esencia .

(defun kbd+ (keyrep &optional need-vector)
  (if (vectorp keyrep) keyrep (edmacro-parse-keys keyrep need-vector)))

(defun gmap (keyrep defstr)
  "Vim-style global keybinding. Uses the `global-set-key' binding function."
  (global-set-key (kbd+ keyrep) (edmacro-parse-keys defstr t)))

(defun fmap (keybind-fn keyrep defstr)
  "Vim-style keybinding using the key binding function KEYBIND-FN."
  (call keybind-fn (kbd+ keyrep) (edmacro-parse-keys defstr t)))

(defun xmap (keymap keyrep defstr)
  "Vim-style keybinding in KEYMAP. Uses the `define-key' binding function."
  (define-key keymap (kbd+ keyrep) (edmacro-parse-keys defstr t)))

(defun nmap (keyrep defstr) "Vim-style keybinding for `evil-normal-state.' Uses the `define-key' binding function."
      (xmap evil-normal-state-map keyrep defstr))
(defun imap (keyrep defstr) "Vim-style keybinding for `evil-insert-state'. Uses the `define-key' binding function."
      (xmap evil-insert-state-map keyrep defstr))
(defun vmap (keyrep defstr) "Vim-style keybinding for `evil-visual-state'. Uses the `define-key' binding function."
      (xmap evil-visual-state-map keyrep defstr))
(defun mmap (keyrep defstr) "Vim-style keybinding for `evil-motion-state'. Uses the `define-key' binding function."
      (xmap evil-motion-state-map keyrep defstr))

En general, es mejor usar estas funciones solo para enlaces de estilo macro de teclado (como el caso de uso en la pregunta), y usar la combinación de teclas de estilo emacs para todo lo demás.

notas

  • La bind-keymacro del use-packagepaquete es una excelente y versátil función de enlace de teclas.
  • Si desea reemplazar un comando con otro, puede usar los comandos de reasignación de Emacs .
  • Si los utiliza para las combinaciones de teclas regulares, tenga en cuenta que no hay versiones "noremap", por lo que si las vinculaciones en su definición cambian, también lo harán sus vinculaciones definidas por el usuario.

Enlace C-]a M-..

Tenga en cuenta que en estado normal, querrá vincularse \M-.para acceder al enlace emacs, ya que el estado normal se une M-.a 'evil-repeat-pop-next. Por lo tanto, un enlace de estado normal se puede definir con:

(nmap "C-]" "\\ M-.")

o (volver a vincular cualquier evil-jump-to-tagclave en estado normal:

(nmap [remap evil-jump-to-tag] "\\ M-.")
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.