Wie binde ich meine Schlüssel an noch nicht geladene Keymaps?

9

Ich verwende use-package, um installierte Pakete zu verwalten und bind-keybenutzerdefinierten Schlüsseln Aktionen zuzuweisen, die mir gefallen.

Ich überschreibe die meisten Standard-Emacs-Tastenkombinationen (z. B. C-nwird M-k, C-pwird M-i), aber ich bin mit anderen Modi einverstanden, die mein Tastenkombinationsschema überschreiben. Manchmal möchte ich jedoch, dass meine Tastenkombination erhalten bleibt. Ich möchte M-ketwas anderes bedeuten als in Standard-Gnus oder Helm.

Sie alle stehen jedoch beim Start von Emacs in Konflikt miteinander, da ich einer Keymap keine Bindung hinzufügen kann, wenn sie nicht vorhanden ist (da use-packagemanchmal das Laden eines Pakets verzögert wird ). Die folgenden Befehle werfen beispielsweise Fehler aus (z. B. (void-variable helm-map)), da Helm und Gnus noch nicht vollständig geladen sind.

(bind-key "M-Y" 'helm-end-of-buffer helm-map)
(bind-key "M-k" 'helm-next-line helm-find-files-map)
(bind-key "M-s" 'other-window gnus-summary-mode-map)

Ich habe alle meine use-packageAufrufe in einer Datei und bind-keyfür benutzerdefinierte Tastenkombinationen in einer anderen Datei. Ich möchte keine Bindungen in use-packageAufrufe einfügen, da ich möglicherweise mein benutzerdefiniertes Schlüsselbindungsschema als eigenständiges Paket veröffentlichen möchte. Was ist, wenn ich möchte, dass jemand, der mein Schema installiert, auch die lokalen Tastenkombinationen von Helm und Gnus überschreibt?

Wie verwalte ich mode-lokale Tastenkombinationen mit bind-key, sodass alle Schlüssel festgelegt werden, auch wenn Pakete in letzter Zeit geladen wurden und alle Tasteneinstellungen in einer Datei enthalten sind?

Mirzhan Irkegulov
quelle

Antworten:

20

Sie können with-eval-after-loaddie Schlüsselbindung verschieben, bis ein bestimmtes Modul geladen wurde (und somit die Keymap definiert wurde):

(with-eval-after-load "helm"
  (bind-key "M-Y" #'helm-end-of-buffer helm-map))

Verwenden C-h v helm-mapSie diese Option, um herauszufinden, in welchem ​​Modul die Keymap definiert ist und was in die Zeichenfolge in der ersten Zeile eingefügt werden soll.


with-eval-after-loadwurde in Emacs 24.4 eingeführt. Wenn Sie eine frühere Emacs-Version haben, müssen Sie eval-after-loadstattdessen Folgendes verwenden und ein einfaches Anführungszeichen vor den bind-keyAnruf setzen:

(eval-after-load "helm"
  '(bind-key "M-Y" #'helm-end-of-buffer helm-map))

Wenn Sie mehrere bind-keyAnrufe in diesem Formular tätigen möchten, setzen with-eval-after-loadSie sie einfach nacheinander ein, aber eval-after-loadSie müssen sie alle in ein progn:

(eval-after-load "helm"
  '(progn
     (bind-key "M-Y" #'helm-end-of-buffer helm-map)
     (bind-key "M-k" #'helm-next-line helm-find-files-map)))
Legoscia
quelle
9

Lösung

Um Sachen auszuführen , nachdem ein bestimmtes Paket geladen wird, müssen Sie , dass nach setzen :configin use-package.

Hier ist ein Beispiel mit dem Snippet in Ihrer Frage:

Snippet # 1

(use-package helm
  :config
  (progn
    (bind-key "M-Y" #'helm-end-of-buffer helm-map)
    (bind-key "M-k" #'helm-next-line helm-find-files-map)))

(use-package gnus
  :config
  (bind-key "M-s" #'other-window gnus-summary-mode-map))

Erläuterung

Es ist in Ordnung, die folgenden 2 Snippets an verschiedenen Stellen in Ihrem Emacs init.eloder in einer der verschachtelten Dateien zu laden / erforderlich.

Snippet # 2

(use-package gnus)

Snippet # 3

(use-package gnus
  :config
  (bind-key "M-s" #'other-window gnus-summary-mode-map))

Der Grund ist, dass es keine Rolle spielt, welches der beiden obigen Snippets zuerst ausgeführt wird.

Hier ist der Grund, warum ... unten ist, worauf Snippet # 3 erweitert wird.

Sie erhalten Folgendes, M-x pp-macroexpand-last-sexpwenn der Punkt (Cursor) nach der letzten schließenden Klammer dieses Snippets steht.

Snippet # 4

(if (not (require 'gnus nil t))
    (ignore (message (format "Could not load %s" 'gnus)))
  (condition-case-unless-debug err
      (bind-key "M-s" #'other-window gnus-summary-mode-map)
    (error
     (ignore
      (display-warning 'use-package
                       (format "%s %s: %s" "gnus" ":config"
                               (error-message-string err))
                       :error))))
  t)

Das obige Snippet bedeutet im Grunde das

  • gnuswird zuerst benötigt und dann wird das bind-keyFormular ausgeführt.
  • Wenn gnuses nicht gefunden wird, wird im Puffer * Nachrichten * eine Meldung angezeigt, dass das Paket nicht geladen werden konnte.
  • Es wird ein Fehler ausgegeben, wenn bei der Ausführung ein Problem auftritt (bind-key "M-s" #'other-window gnus-summary-mode-map)

Auch wenn Snippet Nr. 2 oben gnusbereits benötigt und Snippet Nr. 3 es erneut benötigt , spielt es keine Rolle, da ein Paket nicht erneut geladen wird, wenn es bereits geladen ist.require


Referenz

Von den use-packageGrundlagen auf seinem Github,

:configkann verwendet werden, um Code auszuführen, nachdem ein Paket geladen wurde. In Fällen, in denen das Laden träge erfolgt (weitere Informationen zum automatischen Laden finden Sie weiter unten), wird diese Ausführung verschoben, bis das automatische Laden erfolgt:

Snippet # 5

(use-package foo
  :init
  (setq foo-variable t)
  :config
  (foo-mode 1))

Oben wird der :initAbschnitt ( (setq foo-variable t)) ausgeführt, bevor das foo Paket geladen wird. Aber (foo-mode 1)in dem :configAbschnitt wird ausgeführt, nachdem foo geladen wurde.

Kaushal Modi
quelle
3

Im Gegenteil zu den anderen Antworten habe ich immer Haken verwendet:

(defun my-company-maps()
  (define-key company-active-map "\C-x\M-h" 'company-show-doc-buffer)
  (define-key company-active-map "\C-n" 'company-select-next)
  (define-key company-active-map "\C-p" 'company-select-previous)
  (define-key company-active-map "\C-h" 'delete-backward-char))

(add-hook 'company-mode-hook 'my-company-maps)
Jesse
quelle
Ich auch, ich dachte, das wäre die bevorzugte Art, es zu tun.
Sinnvoller Benutzername
2

Da Sie bereits den Bindeschlüssel verwenden, direkt aus der Dokumentation von bind-key.el:

Wenn Sie möchten, dass die Tastenkombination alle Nebenmodi überschreibt, die möglicherweise auch denselben Schlüssel binden, verwenden Sie das Formular "Bindungsschlüssel *":

(bind-key* "<C-return>" 'other-window)

Verwenden Sie zum Aufheben der Bindung eines Schlüssels innerhalb einer Keymap (um beispielsweise zu verhindern, dass Ihr bevorzugter Hauptmodus eine Bindung ändert, die Sie nicht überall überschreiben möchten): Unbind-key:

(unbind-key "C-c x" some-other-mode-map)

Das letzte Formular wird unterbrochen, wenn die Keymap derzeit nicht definiert some-other-mode-mapist, da die Dateidefinition noch nicht geladen wurde. Sie können dies also in ein use-packagefor some-other-mode(das Paket, das definiert some-other-mode-map) einfügen oder Folgendes verwenden with-eval-after-load:

(with-eval-after-load 'some-other-mode
  (unbind-key "C-c x" some-other-mode-map))

Eine andere Alternative wäre, Ihren eigenen Nebenmodus zu definieren, der alle Bindungen enthält, die nicht durch Hauptmodi überschrieben werden sollten:

(defvar my-very-own-keymap (make-keymap) "my very own keymap.")

(define-key my-very-own-keymap (kbd "M-i") 'my-foo)

(define-minor-mode my-very-own-keys-minor-mode
  "Minor mode with my very own keybindings."
  t " my-own-keys" my-very-own-keymap)
cogsci
quelle