Das Böse: Keybindings auf die vim Art abbilden?

13

Ich versuche, das Böse zum Funktionieren zu bringen evil-jump-to-tagund mich C-]wie der Emacs zu verhalten M-..

Das normale Verhalten ist für das Durchsuchen von Tags-Dateien in Ordnung, aber ich möchte, dass es auch für slime-edit-definitionSlimes elisp-slime-nav-find-elisp-thing-at-point, Elisps cider-jump-to-var, Clojures usw. funktioniert .

Diese und viele weitere Hauptmodi haben ein Äquivalent zum Sprung zur Definition an die Tastenbelegung gebunden M-..

Um das gleiche Verhalten für den Evil-Modus zu erzielen, muss ich für jeden dieser Modi lokal eine Tastenzuordnung festlegen. Alternativ können Sie auch eine Tastenzuordnung vornehmen und Emacs mitteilen, dass bei jedem Drücken dieser Taste die für diese Taste festgelegte Funktion verwendet wird im Emacs-Modus?

martin
quelle
Verwandte (ein direkterer vim-ähnlicher Ansatz): emacs.stackexchange.com/q/12287/8283
idbrii

Antworten:

10

Ich habe es jetzt zum Laufen gebracht, dank Ihrer Antworten:

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

Dies setzt den bösen Zustand auf "Emacs", ruft die an M- gebundene Funktion auf und wechselt in den vorherigen Emacs-Zustand im anderen Puffer zurück. Ich habe es mit Elisp, Slime and Go versucht und es funktioniert für alle.

martin
quelle
1
Was ich benutze, ist einfacher und scheint völlig in Ordnung zu sein: (define-key evil-normal-state-map (kbd "C-]") (kbd "\\ M-.")(wobei "\" gebunden ist evil-execute-in-emacs-state).
Shosti
@shosti: Ja, das sollte mindestens genauso gut funktionieren. Ich habe es so probiert, aber enthielt nicht den Raum zwischen dem zweiten \ und M.
martin
3

Versuchen Sie etwas wie

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

oder, wenn Sie evildiese Tastenkombination bereits verwenden, müssen Sie möglicherweise etwas wie tun.

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

Dadurch wird das Verhalten von C-]@ Tyler vollständig außer Kraft gesetzt . Wenn Sie das Verhalten des Bösen in Abhängigkeit vom aktuellen M-.Hauptmodus beibehalten möchten, ist die Lösung von @ Tyler besser geeignet, da Sie eine Funktion haben können, die entscheidet, ob Sie etwas anderes aufrufen oder tun möchten.

Hilft das?

Malabarba
quelle
2

Ich verstehe evildie Keymaps von 's nicht, aber die folgende Funktion macht alles, was M-.im Moment gebunden ist:

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

evilWenn Sie dies an die entsprechende Tastaturbelegung binden, sollten Sie das tun, was Sie möchten. Möglicherweise gibt es eine evilspezifischere Möglichkeit, dies zu tun.

evilbindet C-]in evil-motion-state-map, versuchen so die folgende:

(eval-after-load "evil-maps"
    '(define-key evil-motion-state-map "\C-]" 'my-tag-jump))
Tyler
quelle
Ich sehe nicht , wie dies könnte so funktionieren, weil das Böse-Modus bindet M-.an evil-repeat-pop-next. Wenn Sie Ihre Funktion folgendermaßen ändern: (defun my-tag-jump () (interaktiv) (evil-emacs-state) (aufrufinteraktiv (key-binding (kbd "M-"))) (evil-normal- state))
martin
Wie gesagt, ich kenne keine bösen Keymaps. Vielleicht ist es die bessere Lösung, die Keymap zu finden, in der sie evil-jump-to-tagdefiniert ist, und sie dort an meine Funktion zu binden.
Tyler
2

Im Allgemeinen ist es nicht möglich.

Der Grund dafür ist, dass es möglicherweise mehrere Maps gibt, die dieselbe Bindung definieren, und es nicht möglich ist, automatisch herauszufinden, welche Sie möchten. (In Ihrem Beispiel elisp-slime-nav-modeist dies ein untergeordneter Modus). Der einzig wirklich zuverlässige Ansatz besteht darin, dass Sie genau herausfinden, welche Definition Sie möchten.

Das heißt, es gibt einen möglichen Hack (gibt es nicht immer ...). Ein Teil der Schwierigkeit besteht darin, dass die Bindung, die Sie neu zuordnen möchten, möglicherweise bereits durch eine böse aktive Keymap maskiert ist, sodass die aktuelle Bindung von abgerufen wird M-.ist nutzlos.

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

Normalerweise benutze ich überhaupt kein Böses, daher sind möglicherweise Anpassungen erforderlich (siehe eingebettete Kommentare).

Ein sauberer Ansatz wäre auch, die Bindungen einmal nachzuschlagen (z. B. in einem Modus-Hook), anstatt bei jedem Drücken der Tastenkombination dynamisch nachzuschlagen. Aber ich bin mir nicht sicher, welchen bösen Haken ich verwenden soll, daher bleibt dies als Übung übrig;) (und abhängig von der Reihenfolge, die Sie für Ihre Nebenmodi verwenden, oder wenn Sie sie dynamisch umschalten, ist dies möglicherweise falsch.)

Sigma
quelle
2

Die von @severin akzeptierte Lösung funktioniert bei mir fast, aber wenn das Tag nicht gefunden wird, kehrt der Puffer nicht in den normalen Modus zurück. Diese Alternative funktioniert für mich in allen Fällen:

(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)
Zak King
quelle
1

Ich denke, dass der sauberste Weg ist

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

(und füge auch jede andere Karte hinzu, die dich interessiert)

xref-find-definitionsist die Funktion, an die M-.in Emacs gebunden ist , wie Sie anhand des Befehls sehen können C-h k.

mookid
quelle
1

Einige vim-artige Tastenbelegungsfunktionen.

Hier sind einige Funktionen, die ich definiert habe, um eine Bindung im Vim-Stil in der globalen Karte und in verschiedenen bösen Zuständen zu ermöglichen, sowie zwei allgemeine Funktionen, die entweder eine beliebige Tastenkarte oder eine beliebige Bindungsfunktion übernehmen. Ich habe diese Funktionen zusammengefasst .

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

Im Allgemeinen ist es besser, diese Funktionen nur für Tastaturmakrobindungen zu verwenden (wie im vorliegenden Anwendungsfall) und für alle anderen Funktionen die Tastaturbindung im Emacs-Stil zu verwenden.

Anmerkungen

  • Das bind-keyMakro aus dem use-packagePaket ist eine hervorragende und vielseitige Funktion für die Tastenbindung.
  • Wenn Sie einen Befehl durch einen anderen ersetzen möchten, können Sie die Remapping-Befehle von Emacs verwenden .
  • Wenn Sie diese für reguläre Schlüsselbindungen verwenden, beachten Sie, dass es keine "Noremap" -Versionen gibt. Wenn sich die Bindungen in Ihrer Definition ändern, ändern sich auch Ihre benutzerdefinierten Bindungen.

Bindung C-]an M-..

Beachten Sie, dass Sie im Normalzustand eine Bindung herstellen möchten, um auf \M-.die Emacs-Bindung zuzugreifen, da im Normalzustand eine Bindung hergestellt werden M-.soll 'evil-repeat-pop-next. So kann eine Normalzustandsbindung definiert werden mit:

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

oder (erneutes Binden eines evil-jump-to-tagSchlüssels im Normalzustand:

(nmap [remap evil-jump-to-tag] "\\ M-.")
Pyrokrastie
quelle