Зло: сопоставить сочетания клавиш в Vim?

13

Я пытаюсь заставить Зло функционировать evil-jump-to-tag, C-]вести себя как привязка Emacs M-..

Нормальное поведение подходит для просмотра файлов тегов, но я хочу, чтобы оно работало также для Slime slime-edit-definition, Elisps elisp-slime-nav-find-elisp-thing-at-point, Clojures cider-jump-to-varи т. Д.

Эти основные режимы и многие другие связывают некоторый эквивалент перехода к определению с привязкой клавиш M-..

Чтобы получить такое же поведение для режима Evil, нужно ли привязывать привязку клавиш локально для каждого из этих режимов, или можно взять привязку клавиш и сообщить Emacs, что при каждом нажатии этой клавиши используйте функцию, привязанную к этой клавише? в режиме Emacs?

Мартин
источник
Связанный (более прямой vim-подобный подход): emacs.stackexchange.com/q/12287/8283
idbrii

Ответы:

10

У меня это работает сейчас, благодаря вашим ответам:

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

Это установит злое состояние на «Emacs», вызовет функцию, связанную с M-, и вернется к предыдущему состоянию emacs в другом буфере. Я попробовал это с elisp, slime и go, и это работает для всех них.

Мартин
источник
1
То, что я использую, проще, и, кажется, работает совершенно нормально: (define-key evil-normal-state-map (kbd "C-]") (kbd "\\ M-.")(где «\» связано evil-execute-in-emacs-state).
Шости
@shosti: Да, это должно работать, по крайней мере, так же. Я попробовал это так, но не включил пробел между вторым \ и М.
Мартин
3

Попробуйте что-то вроде

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

или, если evilуже используется эта привязка клавиш, вам может потребоваться сделать что-то вроде.

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

Это полностью переопределит поведение: C-]если вы хотите сохранить поведение зла в зависимости от текущего основного режима, решение @ Tyler более уместно, потому что вы можете иметь функцию, которая решает, вызывать ли M-.или делать что-то еще.

Это помогает?

Malabarba
источник
2

Я не понимаю evilраскладки клавиш, но следующая функция делает все, что M-.связано в данный момент:

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

Привязка этого к соответствующей evilраскладке клавиш должна делать то, что вы хотите. Там может быть более evilконкретный способ сделать это.

evilсвязывается C-]в evil-motion-state-map, так что попробуйте следующее:

(eval-after-load "evil-maps"
    '(define-key evil-motion-state-map "\C-]" 'my-tag-jump))
Тайлер
источник
Я не понимаю, как это может работать так, потому что злой режим связан M-.с этим evil-repeat-pop-next. Если вы измените свою функцию следующим образом: (defun my-tag-jump () (интерактивный) (evil-emacs-state) (call-интерактивно (связывание ключей (kbd "M-."))) (Evil-normal- состояние))
мартин
Как я уже сказал, я не знаю злых клавишных карт. Возможно, лучшее решение состоит в том, чтобы найти evil-jump-to-tagсхему ключей, где она определена, и привязать ее к моей функции там.
Тайлер
2

В общем, это невозможно.

Причина в том, что может быть несколько карт, которые определяют одну и ту же привязку, и нет способа автоматически определить, какую вы хотите. (в вашем примере elisp-slime-nav-modeтакой второстепенный режим). Таким образом, единственный действительно надежный подход для вас - выяснить, какое именно определение вы хотите.

Тем не менее ... есть возможность взломать (не всегда ...) Часть того, что делает его хитрым, состоит в том, что привязка, которую вы хотите переназначить, потенциально уже замаскирована злой активной картой ключей, поэтому получение текущей привязки M-.бесполезно.

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

Обычно я вообще не использую зла, поэтому могут потребоваться корректировки (см. Встроенные комментарии)

Кроме того, более понятный подход заключается в том, чтобы искать привязки один раз (например, в хуке режима) вместо динамического поиска при каждом нажатии связывания клавиш. Но я не уверен, какой злой крючок использовать, так что это оставлено в качестве упражнения;) (и в зависимости от порядка, который вы используете для своих второстепенных режимов, или если вы переключаете их динамически, это может быть неправильно)

Сигма
источник
2

Принятое @severin решение почти работает для меня, но, когда тег не найден, буфер не возвращается в нормальный режим. Эта альтернатива работает для меня во всех случаях:

(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

Я думаю, что самый чистый путь

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

(а также добавьте любую другую карту, которая вас интересует)

xref-find-definitionsэто функция, связанная с M-.Emacs, как вы можете видеть, используя команду C-h k.

mookid
источник
1

Некоторые функции связывания клавиш в стиле vim.

Вот некоторые функции, которые я определил, чтобы разрешить привязку в стиле vim на глобальной карте и в различных злых состояниях, а также две общие функции, которые принимают либо произвольную карту ключей, либо произвольную функцию привязки. Я поместил эти функции в суть .

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

В общем, лучше использовать эти функции только для привязок в стиле макросов клавиатуры (например, в примере использования в вопросе) и использовать привязку клавиш в стиле emacs для всего остального.

Примечания

  • bind-keyМакрос из use-packageпакета является отличным и универсальным ключом функции связывания.
  • Если вы хотите заменить одну команду другой, вы можете использовать команды переназначения Emacs .
  • Если вы используете их для регулярных привязок клавиш, имейте в виду, что версий «noremap» не существует, поэтому, если привязки в вашем определении изменятся, изменятся и ваши пользовательские привязки.

Привязка C-]к M-..

Обратите внимание, что в нормальном состоянии вы захотите привязаться к, \M-.чтобы получить доступ к привязке emacs, поскольку нормальное состояние связывается M-.с 'evil-repeat-pop-next. Таким образом, привязка нормального состояния может быть определена с помощью:

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

или (повторное связывание любого evil-jump-to-tagключа в нормальном состоянии:

(nmap [remap evil-jump-to-tag] "\\ M-.")
pyrocrasty
источник