Il male: mappare le combinazioni di tasti in modo vim?


13

Sto cercando di far funzionare il Male evil-jump-to-tag, C-]comportandomi come il legame di Emacs M-..

Il comportamento normale va bene per sfogliare i file Tag, ma voglio che funzioni anche per Slime slime-edit-definition, Elisps elisp-slime-nav-find-elisp-thing-at-point, Clojures cider-jump-to-var, ecc ...

Queste principali modalità e molte altre hanno associato alcuni equivalenti di jump-to-definition al keybinding M-..

Per ottenere lo stesso comportamento per la modalità Evil, devo associare localmente un keybinding per ognuna di queste modalità, oppure è possibile prendere un keybinding e dire a Emacs che ogni volta che si preme questo tasto, usare la funzione associata a quel tasto in modalità Emacs?


Correlato (un approccio più diretto simile a vim): emacs.stackexchange.com/q/12287/8283
idbrii,

Risposte:


10

Ho funzionato ora, grazie alle tue risposte:

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

Questo imposterà lo stato malvagio su "Emacs", chiamerà la funzione associata a M-. E tornerà allo stato precedente di emacs nell'altro buffer. L'ho provato con elisp, melma e go e funziona per tutti loro.


1
Quello che uso è più semplice e sembra funzionare perfettamente: (define-key evil-normal-state-map (kbd "C-]") (kbd "\\ M-.")(dove "\" è associato evil-execute-in-emacs-state).
shosti,

@shosti: Sì, anche questo dovrebbe funzionare. L'ho provato in questo modo, ma non ho incluso lo spazio tra il secondo \ e M.
martin

3

Prova qualcosa del genere

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

oppure, se evilutilizza già questa combinazione di tasti, potrebbe essere necessario fare qualcosa del genere.

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

Questo annullerà completamente il comportamento di C-], se vuoi mantenere il comportamento del male a seconda dell'attuale modalità principale, la soluzione di @ Tyler è più appropriata perché puoi avere una funzione che decide se chiamare M-.o fare qualcosa di esle.

questo aiuta?


2

Non capisco eville mappe dei tasti, ma la seguente funzione fa tutto ciò che M-.è legato al momento:

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

Associare questo alla evilkeymap appropriata dovrebbe fare quello che vuoi. Potrebbe esserci un modo più evilspecifico per farlo.

evilsi lega C-]a evil-motion-state-map, in modo da provare quanto segue:

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

Non vedo come questo potrebbe funzionare in questo modo, perché la modalità malvagia si lega M-.a evil-repeat-pop-next. Se cambi la tua funzione in questo: (defun my-tag-jump () (interattivo) (evil-emacs-state) (call-interattivamente (key binding (kbd "M-."))) (Evil-normal- stato))
martin

Come ho detto, non conosco le keymap malvagie. Forse la soluzione migliore è trovare la keymap dove evil-jump-to-tagè definita e ricollegarla alla mia funzione lì.
Tyler,

2

In generale, non è possibile.

Il motivo è che potrebbero esserci diverse mappe che definiscono la stessa associazione e non c'è modo di capire automaticamente quale si desidera. (nel tuo esempio, elisp-slime-nav-modeè una modalità minore). Quindi l'unico approccio veramente affidabile è per te capire esattamente quale definizione desideri.

Detto questo ... c'è un possibile hack (non c'è sempre ...) Parte di ciò che lo rende difficile è che l'associazione che si desidera rimappare è potenzialmente già mascherata da una keymap attiva malvagia, quindi ottenere l'attuale associazione di M-.è inutile.

(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 non uso affatto il male, quindi potrebbero esserci delle modifiche necessarie (vedi commenti incorporati)

Inoltre, un approccio più pulito sarebbe quello di cercare i binding una volta (ad esempio in un hook di modalità), invece di cercare dinamicamente ogni volta che si preme il tasto. Ma non sono sicuro di quale uncino malvagio usare, quindi questo è lasciato come un esercizio;) (e a seconda dell'ordine che usi per le tue modalità secondarie, o se le commuti in modo dinamico, potrebbe non essere corretto)


2

La soluzione accettata da @severin funziona quasi per me, ma, quando il tag non viene trovato, il buffer non torna alla modalità normale. Questa alternativa funziona per me in tutti i casi:

(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

Penso che il modo più pulito sia

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

(e aggiungi anche ogni altra mappa che ti interessa)

xref-find-definitionsè la funzione associata a M-.emacs, come puoi vedere usando il comando C-h k.


1

Alcune funzioni di associazione tasti in stile vim.

Ecco alcune funzioni che ho definito per consentire l'associazione in stile vim nella mappa globale e in vari stati malvagi, nonché due funzioni generali che accettano una mappa di tasti arbitraria o una funzione di associazione arbitraria. Ho messo queste funzioni in sostanza .

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

In generale, è meglio usare queste funzioni solo per le associazioni in stile macro-tastiera (come il caso d'uso nella domanda) e usare la rilegatura in stile emacs per tutto il resto.

Appunti

  • La bind-keymacro dal use-packagepacchetto è un'eccellente e versatile funzione di associazione dei tasti.
  • Se vuoi sostituire un comando con un altro, puoi usare i comandi di rimappatura di Emacs .
  • Se le usi per le associazioni di tasti regolari, tieni presente che non esistono versioni "noremap", quindi se le associazioni nella tua definizione cambiano, così cambieranno anche le associazioni definite dall'utente.

Legando C-]a M-..

Nota che nello stato normale, ti consigliamo di collegarti \M-.per accedere all'associazione emacs, poiché lo stato normale si lega M-.a 'evil-repeat-pop-next. Quindi un binding di stato normale può essere definito con:

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

oppure (ricollegando qualsiasi evil-jump-to-tagchiave in stato normale:

(nmap [remap evil-jump-to-tag] "\\ M-.")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.