Comment lier vos clés à des keymaps qui ne sont pas encore chargés?

9

J'utilise use-packagepour gérer les packages installés et bind-keyattribuer des actions aux clés personnalisées que j'aime.

Je remplace la plupart des raccourcis clavier Emacs par défaut (par exemple C-ndevient M-k, C-pdevient M-i), mais je suis OK avec d'autres modes remplaçant mon schéma de raccourcis clavier. Parfois, cependant, je veux que ma liaison de touches persiste. Je veux M-kdire autre chose que Gnus ou Helm par défaut.

Cependant, ils entrent tous en conflit les uns avec les autres au démarrage d'Emacs, car je ne peux pas ajouter de liaison à une image clé, si elle n'existe pas (car use-packageparfois diffère le chargement d'un package). Par exemple, les commandes suivantes génèrent des erreurs (par exemple (void-variable helm-map)), car Helm et Gnus ne sont pas encore complètement chargés.

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

J'ai toutes mes use-packageinvocations dans un fichier et bind-keypour les raccourcis clavier personnalisés dans un autre fichier. Je ne veux pas mettre de liaisons dans les use-packageappels, car je veux peut-être publier mon schéma de liaison de touches personnalisé en tant que package autonome. Que se passe-t-il si je veux que quelqu'un qui installe mon système se fasse remplacer les raccourcis clavier locaux de Helm et Gnus?

Comment gérer les raccourcis clavier en mode local à l'aide de bind-key, de sorte que toutes les clés soient définies même si les packages sont chargés récemment et que tous les paramètres de clés se trouvent dans un seul fichier?

Mirzhan Irkegulov
la source

Réponses:

20

Vous pouvez utiliser with-eval-after-loadpour différer la liaison de touches jusqu'à ce qu'un certain module ait été chargé (et ainsi défini le clavier):

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

Utilisez C-h v helm-mappour trouver dans quel module le clavier est défini, et donc ce qu'il faut mettre dans la chaîne sur la première ligne.


with-eval-after-loada été introduit dans Emacs 24.4. Si vous avez une version Emacs antérieure, vous devez utiliser à la eval-after-loadplace et mettre un guillemet simple devant l' bind-keyappel:

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

Si vous souhaitez passer plusieurs bind-keyappels dans ce formulaire, with-eval-after-loadvous n'avez qu'à les placer l'un après l'autre, mais avec eval-after-loadvous devez les envelopper tous dans un 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
la source
9

Solution

Pour exécuter des choses après un paquet donné est chargé, vous devez mettre cela après :configen use-package.

Voici un exemple d'utilisation de l'extrait de code dans votre question:

Extrait # 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))

Explication

Il est correct d'avoir les 2 extraits ci-dessous à différents endroits dans votre emacs init.elou dans l'un des fichiers imbriqués chargés / requis.

Extrait # 2

(use-package gnus)

Extrait # 3

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

La raison en est que peu importe lequel des 2 extraits ci-dessus est exécuté en premier.

Voici pourquoi .. ci-dessous est l'extrait de l'extrait # 3.

Vous obtenez ce qui suit en faisant M-x pp-macroexpand-last-sexplorsque le point (curseur) se trouve après la dernière parenthèse fermante de cet extrait.

Extrait # 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)

L'extrait ci-dessus signifie essentiellement que

  • gnusest requis d'abord, puis le bind-keyformulaire est exécuté.
  • S'il gnusn'est pas trouvé, vous verrez un message dans le tampon * Messages * indiquant que ce paquet n'a pas pu être chargé.
  • Il générera une erreur en cas de problème lors de l'exécution (bind-key "M-s" #'other-window gnus-summary-mode-map)

De plus, s'il gnusest déjà requis par l' extrait de code n ° 2 ci-dessus et qu'il est à nouveau requis par l' extrait de code n ° 3 , cela n'a pas d'importance car requireil ne charge pas à nouveau un package s'il est déjà chargé.


Référence

De l' use-packageessentiel sur son github,

:configpeut être utilisé pour exécuter du code après le chargement d'un package. Dans les cas où le chargement est effectué paresseusement (voir plus d'informations sur le chargement automatique ci-dessous), cette exécution est différée jusqu'à ce que le chargement automatique se produise:

Extrait # 5

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

Ci-dessus exécute la :initsection ( (setq foo-variable t)) avant le foo chargement du package. Mais (foo-mode 1)dans la :configsection est exécutée après le foo chargement.

Kaushal Modi
la source
3

À l'opposé des autres réponses, j'ai toujours utilisé des crochets pour cela:

(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
la source
Moi aussi, je pensais que c'était la façon préférée de le faire.
Nom d'utilisateur significatif
2

Puisque vous utilisez déjà bind-key, directement à partir de la documentation de bind-key.el:

Si vous voulez que le raccourci clavier remplace tous les modes mineurs qui peuvent également lier la même clé, utilisez le formulaire `bind-key * ':

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

Pour dissocier une clé dans une image clé (par exemple, pour empêcher votre mode principal préféré de modifier une liaison que vous ne voulez pas remplacer partout), utilisez unbind-key:

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

Le dernier formulaire tombe en panne si le clavier n'est pas défini actuellement car la définition du fichier some-other-mode-mapn'a pas encore été chargée. Vous pouvez donc mettre cela dans un use-packagefor some-other-mode(le paquet définissant some-other-mode-map), ou en utilisant with-eval-after-load:

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

Une autre alternative serait de définir votre propre mode mineur contenant toutes les liaisons qui ne devraient pas être remplacées par les modes majeurs:

(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
la source