Überschreiben Sie die Schlüsselbindung in Emacs global

100

Wie kann ich eine Schlüsselbindung festlegen, die global überschreibt und Vorrang vor allen anderen Bindungen für diesen Schlüssel hat? Ich möchte alle Karten im Haupt- / Nebenmodus überschreiben und sicherstellen, dass meine Bindung immer wirksam ist.

Das funktioniert natürlich nicht:

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

Es funktioniert in text-mode, aber wenn ich es benutze lisp-mode, C-iwird es zurückgeworfen lisp-indent-line.

Ich kann diese Bindung in lisp-modeund in jedem anderen Modus einzeln durchgehen und überschreiben , aber es muss einen einfacheren Weg geben. Jedes Mal, wenn ich einen neuen Modus für einen neuen Dateityp installiere, muss ich zurückgehen und überprüfen, ob alle meine Tastenkombinationen nicht vom neuen Modus überschrieben werden.

Ich möchte dies tun, weil ich Bindungen emulieren möchte, die ich bereits von anderen Editoren gelernt und verwurzelt habe.

Brian Carper
quelle

Antworten:

149

Ich verwende einen Nebenmodus für alle meine "Override" -Tastenbindungen:

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

Dies hat den zusätzlichen Vorteil, dass alle meine Änderungen auf einen Schlag deaktiviert werden können (deaktivieren Sie einfach den Nebenmodus), falls jemand anderes die Tastatur steuert oder wenn ich sehen muss, was eine Standardtastenbindung bewirkt.

Beachten Sie, dass Sie dies möglicherweise im Minibuffer deaktivieren müssen:

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

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
Scottfrazer
quelle
1
Das scheint eine gute Idee zu sein. Gibt es eine Möglichkeit, um sicherzustellen, dass Ihr Nebenmodus nicht mit anderen Nebenmodi kämpft?
Brian Carper
3
Stellen Sie sicher, dass Ihr Minor-Modus an erster Stelle in der Liste Minor-Mode-Map-Alist steht.
Trey Jackson
2
Trey hat recht. Normalerweise reicht es aus, dies gegen Ende Ihrer .emacs zu setzen. Außerdem sind die meisten Bindungen, die Sie überschreiben würden, diejenigen, die von Hauptmodi festgelegt werden ... Nebenmodi bleiben im Allgemeinen aus dem Weg.
Scottfrazer
Ich folgte diesem Ansatz, aber dann wurde mir klar, dass alles, was ich an Ci binde, auch an den TAB-Schlüssel gebunden wird. Irgendwelche Vorschläge?
Steve
3
Brian Carper: Hier ist eine Verbesserung für später geladene Nebenmodi
phils
30

Als Ergänzung zu Scottfrazers Antwort habe ich Folgendes geschrieben, damit meine Tastenkombinationen Vorrang haben, auch wenn nachträglich geladene Bibliotheken eigene neue Keymaps einfügen.

Da Keymaps zur Kompilierungszeit generiert werden können, loadschien dies der beste Ort dafür zu sein.

(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
quelle
Ich habe Ihr Skript eingefügt, aber es hat keine Auswirkungen :(
Alper
@alper Ich schlage vor, dass Sie eine Frage mit allen relevanten Details, einschließlich des tatsächlich verwendeten Codes, und einem bestimmten Beispiel / Rezept zur Reproduktion des Problems posten.
Phils
20

Installieren use-package, bewerten und fertig:

(require 'bind-key)
(bind-key* "C-i" 'some-function)
Mirzhan Irkegulov
quelle
5
Für den Anwendungsfall reicht es aus, nur den Bindeschlüssel zu installieren, obwohl das Anwendungspaket vom Bindeschlüssel abhängt.
Xuchunyang
2
Dieses ('Bind-Key'-Paket) scheint die bequemste Lösung zu sein. danke für das Teilen.
Oligilo
Ich konnte keine Übereinstimmung finden für use-package:Install package: use-package [No Match]
am
14

Ich habe diese Frage bei der Suche nach "emacs undefine org mode keybindings" gefunden, weil ich das vorhandene Cc Cb-Verhalten aufheben wollte, damit meine globale Map-Bury-Buffer in einem Org-Puffer funktioniert.

Dies war für mich die einfachste Lösung:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))
Jay Doane
quelle
1
Dies ist modusspezifisch und spricht nicht das Gesamtbild an, obwohl es für Ihren einzelnen Anwendungsfall funktioniert.
RichieHH
12

Obwohl die Antwort von Scottfrazer genau das ist, wonach Sie gefragt haben, werde ich für die Nachwelt eine andere Lösung erwähnen.

Aus dem Emacs-Handbuch :

"Definieren Sie Cc-Buchstaben nicht als Schlüssel in Lisp-Programmen. Sequenzen, die aus Cc und einem Buchstaben (entweder in Groß- oder Kleinbuchstaben) bestehen, sind für Benutzer reserviert. Sie sind die einzigen Sequenzen, die für Benutzer reserviert sind. Blockieren Sie sie daher nicht."

Wenn Sie Ihre persönlichen globalen Bindungen an Cc plus einen Brief binden, sollten Sie "sicher" sein. Dies ist jedoch nur eine Konvention, und jeder Modus kann Ihre Bindungen weiterhin überschreiben.

Kirkland
quelle
3
Ich habe nicht erwartet, dass ausgerechnet der Organisationsmodus gegen diese Regel verstößt. `Cc Ch 'sagt mir, dass Cc a, b, c und l an org-Agenda, org-iswitchb, org-capture bzw. org-store-link gebunden sind.
Nate Parsons
7
Afaik, das Binden dieser ist der erste Schritt, den der Organisationsmodus vorschlägt, um es zu verwenden, aber der Benutzer muss sie selbst definieren (dh es wird nicht standardmäßig ausgeführt) und kann dabei eine andere auswählen. (auch, weil diese Bindungen global sein sollen und nicht an den Org-Major-Modus gebunden sind)
Nikana Reklawyks
3

Wenn Sie "immer die Tastenkombinationen in der Karte verwenden möchten, es sei denn, ich überschreibe sie explizit für eine bestimmte Moduszuordnung " und davon ausgehen möchten , dass Sie den Ansatz von scottfrazier verwenden , möchten Sie:

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

So

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

sollte die "\ Ci" -Bindung nur im aktuellen Puffer aus dem Nebenmodus entfernen. Warnung: Dies ist völlig ungetestet, scheint aber der richtige Ansatz zu sein. Der Punkt, an dem das übergeordnete Element festgelegt wird, anstatt nur den globalen Wert von my-keys-minor-mode-map zu kopieren, besteht darin, dass spätere Änderungen des globalen Werts automatisch im lokalen Wert berücksichtigt werden.

gbrunick
quelle
2

Ich glaube nicht, dass du kannst. Dies entspricht in etwa der Aussage, dass Sie eine globale Variable definieren möchten, die von lokalen Variablendeklarationen in Funktionen nicht ausgeblendet werden kann. Scope funktioniert einfach nicht so.

Es kann jedoch eine Möglichkeit geben, eine Elisp-Funktion zu schreiben, um die Modusliste zu durchlaufen und sie in jeder einzelnen für Sie neu zuzuweisen.

TED
quelle
Diese Idee des Scoping ist technisch korrekt, wurde jedoch overriding-local-mapspeziell entwickelt, um alle anderen Karten zu überschreiben. Es ist jedoch gefährlich, es zu benutzen.
event_jr
2

Wenn Sie dies nicht wirklich selbst tun möchten, sollten Sie nachsehen, ob es bereits jemand anderes getan hat.

Es gibt ein Paket für Emacs, das Ihre Windows-ähnlichen Tastenkombinationen enthält. Sie sollten es über Google finden können.

JesperE
quelle
4
Das Paket, an das Sie denken, ist wahrscheinlich cua-mode.
Drew
1
Ja, das ist das Paket.
JesperE