Globalnie nadpisuj przypisanie klawiszy w Emacsie

100

Jak ustawić powiązanie klucza, które globalnie zastępuje i ma pierwszeństwo przed wszystkimi innymi powiązaniami dla tego klucza? Chcę przesłonić wszystkie mapy w trybie głównym / pomocniczym i upewnić się, że moje powiązanie zawsze działa.

To oczywiście nie działa:

(global-set-key "\C-i" 'some-function)

Działa w text-mode, ale kiedy używam lisp-mode, C-ijest odbijany lisp-indent-line.

Mogę przejść przez to powiązanie i nadpisać go lisp-modeindywidualnie w każdym innym trybie, ale musi istnieć łatwiejszy sposób. Za każdym razem, gdy instaluję nowy tryb dla nowego typu pliku, musiałbym wrócić i sprawdzić, czy wszystkie moje powiązania klawiszy nie są zastępowane przez nowy tryb.

Chcę to zrobić, ponieważ chcę naśladować wiązania, których już nauczyłem się i zakorzeniłem od innych edytorów.

Brian Carper
źródło

Odpowiedzi:

149

Używam trybu pomocniczego dla wszystkich moich „zastąpień” powiązań klawiszy:

(defvar my-keys-minor-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "C-i") 'some-function)
    map)
  "my-keys-minor-mode keymap.")

(define-minor-mode my-keys-minor-mode
  "A minor mode so that my key settings override annoying major modes."
  :init-value t
  :lighter " my-keys")

(my-keys-minor-mode 1)

Ma to dodatkową zaletę, że mogę wyłączyć wszystkie moje modyfikacje za jednym zamachem (po prostu wyłącz tryb pomocniczy) na wypadek, gdyby ktoś inny sterował klawiaturą lub gdy potrzebowałem zobaczyć, co robi domyślne powiązanie klawiszy.

Pamiętaj, że może być konieczne wyłączenie tego w minibuforze:

(defun my-minibuffer-setup-hook ()
  (my-keys-minor-mode 0))

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
scottfrazer
źródło
1
Wydaje się, że to dobry pomysł. Czy jest jakiś sposób, aby upewnić się, że twój tryb pomocniczy nie będzie walczył z innymi trybami pomocniczymi?
Brian Carper,
3
Upewnij się, że twój tryb pomocniczy jest pierwszy na liście list-map-trybów pomocniczych.
Trey Jackson,
2
Trey ma rację. Zwykle wystarczy umieścić to pod koniec swojego .emacs. Ponadto większość powiązań, które można by przesłonić, to te, które ustawiają główne tryby ... tryby pomocnicze generalnie pozostają na uboczu.
scottfrazer,
Podążyłem za tym podejściem, ale potem zdałem sobie sprawę, że wszystko, co powiążę z Ci, zostanie również powiązane z klawiszem TAB. Jakieś sugestie?
Steve
3
Brian Carper: Oto ulepszenie radzenia sobie z później ładowanymi trybami pomocniczymi: stackoverflow.com/questions/683425/…
phils
30

Jako dodatek do odpowiedzi scottfrazera , napisałem co następuje, aby moje skróty klawiszowe zachowały pierwszeństwo, nawet jeśli później ładowane biblioteki wprowadzają nowe własne mapy klawiszy.

Ponieważ mapy klawiszy można generować w czasie kompilacji, loadwydawało się , że jest to najlepsze miejsce do zrobienia tego.

(add-hook 'after-load-functions 'my-keys-have-priority)

(defun my-keys-have-priority (_file)
  "Try to ensure that my keybindings retain priority over other minor modes.

Called via the `after-load-functions' special hook."
  (unless (eq (caar minor-mode-map-alist) 'my-keys-minor-mode)
    (let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
      (assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
      (add-to-list 'minor-mode-map-alist mykeys))))
phils
źródło
Wkleiłem twój skrypt, ale nie miało to żadnego wpływu :(
alper
@alper Sugeruję, aby zadać pytanie ze wszystkimi istotnymi szczegółami, w tym kodem, którego faktycznie używasz, oraz konkretnym przykładem / przepisem na odtworzenie problemu.
phils
21

Zainstaluj use-package, oceń i gotowe:

(require 'bind-key)
(bind-key* "C-i" 'some-function)
Mirzhan Irkegulov
źródło
5
Zainstaluj tylko bind-key w przypadku użycia, chociaż use-package zależy od bind-key.
xuchunyang
2
Ten (pakiet „bind-key”) wydaje się być najwygodniejszym rozwiązaniem; dzięki za udostępnienie.
oligilo
Nie udało mi się znaleźć dopasowania dla use-package:Install package: use-package [No Match]
alper
14

Znalazłem to pytanie podczas wyszukiwania „emacs undefine org mode keybindings”, ponieważ chciałem usunąć istniejące zachowanie Cc Cb, aby umożliwić mojej mapie globalnej zakopanie bufora w buforze organizacyjnym.

To było dla mnie najprostsze rozwiązanie:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))
Jay Doane
źródło
1
Jest to specyficzne dla trybu i nie odnosi się do szerszego obrazu, mimo że działa w przypadku jednorazowego użycia.
RichieHH
12

Chociaż odpowiedź Scottfrazera jest dokładnie tym, o co prosiłeś, dla potomności wspomnę o innym rozwiązaniu.

Z podręcznika Emacsa :

„Nie definiuj litery Cc jako klucza w programach Lisp. Sekwencje składające się z Cc i litery (wielkiej lub małej) są zarezerwowane dla użytkowników; są to jedyne sekwencje zarezerwowane dla użytkowników, więc ich nie blokuj”.

Jeśli powiążesz swoje osobiste powiązania globalne z Cc i literą, wtedy „powinieneś” być bezpieczny. Jest to jednak tylko konwencja, a każdy tryb nadal może przesłonić twoje powiązania.

Kirkland
źródło
3
Nie spodziewałem się, że tryb org, ze wszystkich trybów, złamie tę zasadę. `Cc Ch 'mówi mi, że Cc a, b, c i l są powiązane odpowiednio z elementami org-agenda, org-iswitchb, org-capture i org-store-link.
Nate Parsons
7
Afaik, powiązanie ich jest pierwszym krokiem, który sugeruje tryb org, aby z niego skorzystać, ale użytkownik musi sam je zdefiniować (tj. Nie jest to zrobione domyślnie) i może wybrać inny, robiąc to. (również dlatego, że te powiązania mają być globalne, a nie powiązane z trybem org major)
Nikana Reklawyks
3

Jeśli chcesz "zawsze używać skrótów klawiszowych na mapie, chyba że jawnie nadpisuję je dla określonej mapy trybu" i zakładając, że używasz podejścia scottfraziera , chcesz:

(defun locally-override (key cmd)
  (unless (local-variable-p 'my-keys-minor-mode-map)
    (set (make-variable-buffer-local 'my-keys-minor-mode-map)
         (make-sparse-keymap))
    (set-keymap-parent my-keys-minor-mode-map 
                       (default-value 'my-keys-minor-mode-map)))
  (define-key my-keys-minor-mode-map key cmd))

Więc

(locally-override "\C-i" nil)

powinien usunąć powiązanie "\ Ci" z trybu pomocniczego tylko w bieżącym buforze. Ostrzeżenie: to jest całkowicie niesprawdzone, ale wydaje się być właściwym podejściem. Celem ustawienia rodzica, a nie tylko radzenia sobie z globalną wartością mapy my-keys-minor-mode-map, jest to, że wszelkie późniejsze zmiany wartości globalnej są automatycznie odzwierciedlane w wartości lokalnej.

gbrunick
źródło
2

Myślę, że nie możesz. Jest to z grubsza równoważne stwierdzeniu, że chcesz zdefiniować zmienną globalną, której nie można ukryć za pomocą lokalnych deklaracji zmiennych w funkcjach. Zakres po prostu nie działa w ten sposób.

Jednak może istnieć sposób na napisanie funkcji elisp, która przejdzie przez listę trybów i ponownie przypisze ją w każdym z nich za Ciebie.

PRZETRZĄSAĆ
źródło
Ten pomysł określania zakresu jest technicznie poprawny, ale overriding-local-mapzostał specjalnie zaprojektowany, aby zastąpić wszystkie inne mapy. Jednak używanie go jest niebezpieczne.
event_jr
2

O ile naprawdę nie chcesz to zrobić sam, powinieneś sprawdzić, czy ktoś inny już to zrobił.

Istnieje pakiet dla Emacsa, który daje przypisania klawiszy w stylu Windows. Powinieneś być w stanie go znaleźć przez Google.

JesperE
źródło
4
Prawdopodobnie pakiet, o którym myślisz cua-mode.
Drew
1
Tak, to jest pakiet.
JesperE,