Jak powiązać klucze z mapami klawiszy, które nie zostały jeszcze załadowane?

9

Używam use-packagedo zarządzania zainstalowanymi pakietami i bind-keyprzypisywania akcji niestandardowym kluczom, które lubię.

Zastępuję większość domyślnych skrótów klawiszowych Emacsa (np. C-nStaje się M-k, C-pstaje się M-i), ale nie mam nic przeciwko innym trybom zastępującym mój schemat przypisywania klawiszy. Czasami chcę jednak, aby moje skróty klawiszowe trwały. Chcę mieć na M-kmyśli coś innego niż domyślny Gnus lub Hełm.

Jednak wszystkie one powodują konflikty podczas uruchamiania Emacsa, ponieważ nie mogę dodać powiązania do mapy klawiszy, jeśli nie istnieje (ponieważ use-packageczasami odkłada ładowanie pakietu). Na przykład następujące polecenia generują błędy (np. (void-variable helm-map)), Ponieważ Helm i Gnus nie są jeszcze w pełni załadowane.

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

Mam wszystkie moje use-packagewywołania w jednym pliku, a bind-keyniestandardowe skróty klawiszowe w innym pliku. Nie chcę wstawiać powiązań do use-packagewywołań, ponieważ być może chcę opublikować własny niestandardowy schemat przypisywania klawiszy jako samodzielny pakiet. Co zrobić, jeśli chcę, aby ktoś instalujący mój schemat miał również nadpisane lokalne skróty klawiszowe Helm i Gnus?

Jak zarządzać lokalnymi trybami bind-keyskrótów klawiszowych , aby wszystkie klucze były ustawione, nawet jeśli ostatnio ładowane są pakiety, a wszystkie ustawienia kluczy znajdują się w jednym pliku?

Mirzhan Irkegulov
źródło

Odpowiedzi:

20

Możesz użyć, with-eval-after-loadaby odroczyć powiązanie klawiszy, aż do załadowania określonego modułu (a tym samym zdefiniowania mapy klawiszy):

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

Służy C-h v helm-mapdo znajdowania modułu, w którym zdefiniowano mapę klawiszy, a co za tym idzie, co umieścić w ciągu w pierwszym wierszu.


with-eval-after-loadzostał wprowadzony w Emacs 24.4. Jeśli masz wcześniejszą wersję Emacsa, musisz użyć eval-after-loadzamiast tego i umieścić pojedynczy cytat przed bind-keyrozmową:

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

Jeśli chcesz wykonać kilka bind-keypołączeń w tym formularzu, with-eval-after-loadpo prostu umieść je jeden po drugim, ale eval-after-loadmusisz zawinąć je wszystkie w 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
źródło
9

Rozwiązanie

W celu realizacji rzeczy po dany pakiet jest załadowany, należy umieścić, że po :configw use-package.

Oto przykład użycia fragmentu kodu w pytaniu:

Fragment nr 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))

Wyjaśnienie

Można mieć poniżej 2 fragmentów w różnych miejscach emacsa init.ellub w dowolnym załadowanym / wymaganym pliku zagnieżdżonym.

Fragment nr 2

(use-package gnus)

Fragment nr 3

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

Powodem jest to, że nie ma znaczenia, który z powyższych 2 fragmentów zostanie wykonany jako pierwszy.

Oto dlaczego .. poniżej znajduje się opis rozszerzenia Snippet # 3.

Poniższe czynności można wykonać, M-x pp-macroexpand-last-sexpgdy punkt (kursor) znajduje się po ostatnim nawiasie zamykającym tego fragmentu.

Fragment nr 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)

Powyższy fragment w zasadzie to oznacza

  • gnusjest wymagane najpierw, a następnie bind-keyformularz jest wykonywany.
  • Jeśli gnusnie zostanie znaleziony, zobaczysz komunikat w buforze * Messages * informujący, że nie można załadować tego pakietu.
  • Zgłasza błąd, jeśli występuje problem z wykonaniem (bind-key "M-s" #'other-window gnus-summary-mode-map)

Również jeśli gnusjest już wymagany przez Snippet # 2 powyżej i jest wymagany ponownie przez Snippet # 3 , nie ma to znaczenia, ponieważ requirenie ładuje pakietu ponownie, jeśli jest już załadowany.


Odniesienie

Od use-packagepodstaw na githubie,

:configmoże być użyty do wykonania kodu po załadowaniu pakietu. W przypadkach, w których ładowanie odbywa się leniwie (więcej informacji o automatycznym ładowaniu znajduje się poniżej), wykonywanie to jest odraczane do momentu wystąpienia automatycznego ładowania:

Fragment nr 5

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

Powyżej wykonuje :initsekcję ( (setq foo-variable t)) przed foo załadowaniem pakietu. Ale (foo-mode 1)w :configsekcji jest wykonywany po foo załadowaniu.

Kaushal Modi
źródło
3

W przeciwieństwie do innych odpowiedzi, zawsze użyłem do tego haków:

(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
źródło
Ja też myślałem, że to preferowany sposób.
Znacząca nazwa użytkownika
2

Ponieważ używasz już klucza powiązania, bezpośrednio z dokumentacji bind-key.el:

Jeśli chcesz, aby przypisanie klawiszy zastąpiło wszystkie pomniejsze tryby, które mogą również powiązać ten sam klucz, użyj formularza `bind-key * ':

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

Aby usunąć powiązanie klucza w mapie klawiszy (na przykład, aby zatrzymać ulubiony tryb główny przed zmianą powiązania, którego nie chcesz zastępować wszędzie), użyj polecenia unbind-key:

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

Ostatni formularz ulega awarii, jeśli mapa klawiszy jest obecnie niezdefiniowana, ponieważ definicja pliku some-other-mode-mapnie została jeszcze załadowana. Możesz więc umieścić to w use-packagefor some-other-mode(definiowanie pakietu some-other-mode-map) lub używając with-eval-after-load:

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

Inną alternatywą byłoby zdefiniowanie własnego trybu podrzędnego zawierającego wszystkie wiązania, których nie powinny zastępować główne tryby:

(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
źródło