Evil: memetakan keybindings dengan cara vim?

13

Saya mencoba untuk membuat fungsi Evil evil-jump-to-tag, C-]berperilaku seperti ikatan Emacs M-..

Perilaku normal baik untuk menelusuri file Tag, tapi saya ingin itu berfungsi juga untuk Slime slime-edit-definition, Elisps elisp-slime-nav-find-elisp-thing-at-point, Clojures cider-jump-to-var, dll ...

Mode-mode utama ini dan banyak lagi lainnya telah terikat beberapa setara dengan melompat-ke-definisi ke keybinding M-..

Untuk mendapatkan perilaku yang sama untuk mode-Jahat, apakah saya harus mengikat ikatan tombol secara lokal untuk setiap mode ini, atau apakah mungkin untuk mengambil ikatan kunci dan memberi tahu Emacs, bahwa setiap kali tombol ini ditekan, gunakan fungsi terikat untuk tombol itu dalam mode Emacs?

martin
sumber
Terkait (pendekatan vim-like yang lebih langsung): emacs.stackexchange.com/q/12287/8283
idbrii

Jawaban:

10

Saya sudah membuatnya bekerja sekarang, terima kasih atas jawaban Anda:

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

Ini akan mengatur status jahat ke "Emacs", memanggil fungsi terikat ke M-., Dan mengubah kembali ke status emacs sebelumnya di buffer lain. Saya sudah mencobanya dengan elisp, lendir dan pergi dan itu bekerja untuk mereka semua.

martin
sumber
1
Apa yang saya gunakan lebih sederhana, dan tampaknya berfungsi dengan baik: (define-key evil-normal-state-map (kbd "C-]") (kbd "\\ M-.")(di mana "\" terikat evil-execute-in-emacs-state).
shosti
@shosti: Ya, ini setidaknya harus bekerja. Saya sudah mencobanya seperti ini, tetapi tidak termasuk ruang antara yang kedua \ dan M.
martin
3

Coba sesuatu seperti

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

atau, jika evilsudah menggunakan keybind ini, Anda mungkin perlu melakukan sesuatu seperti.

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

Ini akan sepenuhnya mengesampingkan perilaku C-], jika Anda ingin menjaga perilaku jahat tergantung pada mode-utama saat ini, solusi @ Tyler lebih tepat karena Anda dapat memiliki fungsi yang memutuskan apakah akan memanggil M-.atau melakukan sesuatu yang lain.

Apakah ini membantu?

Malabarba
sumber
2

Saya tidak mengerti evilkeymaps, tetapi fungsi berikut melakukan apa pun M-.yang terikat saat ini:

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

Mengikat ini ke evilkeymap yang sesuai harus melakukan apa yang Anda inginkan. Mungkin ada cara yang lebih evilspesifik untuk melakukan ini.

evilmengikat C-]di evil-motion-state-map, jadi coba berikut ini:

(eval-after-load "evil-maps"
    '(define-key evil-motion-state-map "\C-]" 'my-tag-jump))
Tyler
sumber
Saya tidak melihat bagaimana ini bisa bekerja seperti ini, karena kejahatan-mode mengikat M-.untuk evil-repeat-pop-next. Jika Anda mengubah fungsi Anda menjadi ini: (defun my-tag-jump () (interaktif) (evil-emacs-state) (panggil-interaktif (pengikat-kunci (kbd "M-."))) (Jahat-normal- state))
martin
Seperti yang saya katakan, saya tidak tahu keymaps jahat. Mungkin solusi yang lebih baik adalah menemukan keymap di mana evil-jump-to-tagdidefinisikan, dan rebind ke fungsi saya di sana.
Tyler
2

Secara umum, itu tidak mungkin.

Alasannya adalah bahwa mungkin ada beberapa peta yang mendefinisikan ikatan yang sama, dan tidak ada cara untuk mencari tahu secara otomatis mana yang Anda inginkan. (dalam contoh Anda, elisp-slime-nav-modeadalah mode minor). Jadi satu-satunya pendekatan yang benar-benar dapat diandalkan adalah Anda mengetahui dengan tepat definisi yang Anda inginkan.

Yang mengatakan ... ada kemungkinan peretasan (tidak selalu ada ...) Bagian dari apa yang membuatnya rumit adalah bahwa pengikatan yang ingin Anda remap berpotensi telah ditutup-tutupi oleh keymap aktif jahat, sehingga mendapatkan pengikatan saat ini dari M-.tidak berguna.

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

Saya biasanya tidak menggunakan kejahatan sama sekali, jadi mungkin ada penyesuaian yang diperlukan (lihat komentar yang disertakan)

Juga, pendekatan yang lebih bersih adalah dengan mencari binding sekali (dalam mode hook misalnya), daripada melihat secara dinamis setiap kali ikatan tombol ditekan. Tapi saya tidak yakin apa hook jahat yang digunakan, jadi ini dibiarkan sebagai latihan;) (dan tergantung pada urutan yang Anda gunakan untuk mode minor Anda, atau jika Anda mengaktifkannya secara dinamis, itu mungkin salah)

Sigma
sumber
2

Solusi yang diterima oleh @severin hampir berfungsi untuk saya, tetapi, ketika tag tidak ditemukan, buffer tidak kembali ke mode normal. Alternatif ini berfungsi untuk saya dalam semua kasus:

(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
sumber
1

Saya pikir cara paling bersih adalah

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

(dan juga tambahkan setiap peta lain yang Anda minati)

xref-find-definitionsadalah fungsi yang diikat ke M-.dalam emacs, seperti yang Anda lihat menggunakan perintah C-h k.

bodoh
sumber
1

Beberapa fungsi pengikat tombol gaya vim.

Berikut adalah beberapa fungsi yang telah saya definisikan untuk memungkinkan pengikatan gaya vim di peta global dan berbagai kondisi jahat, serta dua fungsi umum yang mengambil baik peta kunci sewenang-wenang atau fungsi pengikatan sewenang-wenang. Saya telah menempatkan fungsi-fungsi ini di intinya .

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

Secara umum, lebih baik hanya menggunakan fungsi-fungsi ini untuk binding keyboard-macro-style (seperti case-use dalam pertanyaan), dan menggunakan pengikat kunci gaya emacs untuk yang lainnya.

catatan

  • The bind-keymakro dari use-packagepaket adalah sangat baik dan serbaguna fungsi tombol-mengikat.
  • Jika Anda ingin mengganti satu perintah dengan yang lain, Anda dapat menggunakan perintah remapping Emacs .
  • Jika Anda menggunakan ini untuk binding kunci reguler, ingatlah bahwa tidak ada versi "noremap", jadi jika binding dalam definisi Anda berubah, maka binding yang ditentukan pengguna Anda juga.

Mengikat C-]ke M-..

Perhatikan bahwa dalam normal negara, Anda akan ingin mengikat \M-.untuk mengakses emacs mengikat, karena mengikat normal negara M-.untuk 'evil-repeat-pop-next. Jadi pengikatan normal-negara dapat didefinisikan dengan:

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

atau (membatalkan evil-jump-to-tagkunci apa pun dalam kondisi normal:

(nmap [remap evil-jump-to-tag] "\\ M-.")
pyrocrasty
sumber