Remplacer globalement la liaison de clé dans Emacs

100

Comment puis-je définir une liaison de clé qui remplace globalement et a priorité sur toutes les autres liaisons pour cette clé? Je veux remplacer toutes les cartes de mode majeur / mineur et m'assurer que ma liaison est toujours en vigueur.

Cela ne fonctionne bien sûr pas:

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

Ca marche dedans text-mode, mais quand je l'utilise lisp-mode, C-ic'est rebondir lisp-indent-line.

Je peux passer et remplacer cette liaison dans lisp-modeet dans tous les autres modes individuellement, mais il doit y avoir un moyen plus simple. Chaque fois que j'installe un nouveau mode pour un nouveau type de fichier, je devrais revenir en arrière et vérifier que toutes mes combinaisons de touches ne sont pas remplacées par le nouveau mode.

Je veux faire cela parce que je veux émuler des liaisons que j'ai déjà apprises et enracinées auprès d'autres éditeurs.

Brian Carper
la source

Réponses:

149

J'utilise un mode mineur pour toutes mes raccourcis clavier:

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

Cela a l'avantage supplémentaire de pouvoir désactiver toutes mes modifications d'un seul coup (désactivez simplement le mode mineur) au cas où quelqu'un d'autre conduirait le clavier ou si j'ai besoin de voir ce que fait une liaison de touche par défaut.

Notez que vous devrez peut-être désactiver cette option dans le mini-tampon:

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

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
Scottfrazer
la source
1
Cela semble être une bonne idée. Existe-t-il un moyen de s'assurer que votre mode mineur ne se bat pas avec d'autres modes mineurs?
Brian Carper
3
Assurez-vous que votre mode mineur est le premier sur la liste minor-mode-map-alist.
Trey Jackson
2
Trey a raison. En général, il suffit de mettre cela à la fin de votre .emacs. De plus, la plupart des liaisons que vous remplaceriez seraient celles que les modes principaux définissent ... les modes mineurs restent généralement à l'écart.
scottfrazer
J'ai suivi cette approche, mais j'ai ensuite réalisé que tout ce que je lie à Ci est également lié à la touche TAB. Aucune suggestion?
Steve
3
Brian Carper: Voici une amélioration pour gérer les modes mineurs chargés ultérieurement: stackoverflow.com/questions/683425
...
30

En complément de la réponse de Scottfrazer , j'ai écrit ce qui suit afin que mes raccourcis clavier conservent la priorité, même si les bibliothèques chargées par la suite apportent leurs propres keymaps.

Parce que les keymaps peuvent être générés au moment de la compilation, cela loadsemblait être le meilleur endroit pour le faire.

(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
la source
J'ai collé votre script mais cela n'a eu aucun effet :(
alper
@alper Je vous suggère de poster une question avec tous les détails pertinents, y compris le code que vous utilisez réellement, et un exemple / recette spécifique pour reproduire le problème.
phils
21

Installez use-package, évaluez et vous avez terminé:

(require 'bind-key)
(bind-key* "C-i" 'some-function)
Mirzhan Irkegulov
la source
5
Installer uniquement bind-key est suffisant pour le cas d'utilisation, bien que use-package dépende de bind-key.
xuchunyang
2
Ce (package 'bind-key') semble être la solution la plus pratique; Merci d'avoir partagé.
oligilo
Je n'ai pas trouvé de match pour use-package:Install package: use-package [No Match]
alper
14

J'ai trouvé cette question en cherchant "emacs undefine org mode keybindings", parce que je voulais dissocier le comportement Cc Cb existant pour permettre à ma carte globale de bury-buffer de fonctionner dans un buffer org.

Cela a fini par être la solution la plus simple pour moi:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))
Jay Doane
la source
1
Ceci est spécifique au mode et n'aborde pas la situation dans son ensemble, même si cela fonctionne pour votre cas d'utilisation unique.
RichieHH le
12

Bien que la réponse de Scottfrazer soit exactement ce que vous avez demandé, je mentionnerai pour la postérité une autre solution.

À partir du manuel Emacs :

"Ne définissez pas la lettre Cc comme une clé dans les programmes Lisp. Les séquences composées de Cc et d'une lettre (majuscule ou minuscule) sont réservées aux utilisateurs; ce sont les seules séquences réservées aux utilisateurs, ne les bloquez donc pas."

Si vous liez vos liaisons globales personnelles à Cc plus une lettre, alors vous «devriez» être en sécurité. Cependant, il ne s'agit que d'une convention et n'importe quel mode est toujours capable de remplacer vos liaisons.

Kirkland
la source
3
Je ne m'attendais pas à ce que le mode org, de tous les modes, enfreigne cette règle. `Cc Ch 'me dit que Cc a, b, c et l sont respectivement liés à org-agenda, org-iswitchb, org-capture et org-store-link.
Nate Parsons
7
Afaik, lier ceux-ci est la première étape suggérée par le mode org pour l'utiliser, mais l'utilisateur doit les définir lui-même (c'est-à-dire que ce n'est pas fait par défaut), et peut en choisir un autre en le faisant. (aussi, c'est parce que ces liaisons sont censées être globales, non liées au mode majeur de l'org)
Nikana Reklawyks
3

Si vous voulez "toujours utiliser les raccourcis clavier dans la carte, à moins que je ne les remplace explicitement pour une carte de mode spécifique", et en supposant que vous utilisez l'approche de scottfrazier , vous voulez:

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

Alors

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

devrait supprimer la liaison "\ Ci" du mode mineur dans le tampon courant uniquement. Attention: ceci n'a pas été testé, mais semble être la bonne approche. Le point de définir le parent plutôt que de simplement copier la valeur globale de my-keys-minor-mode-map est que toute modification ultérieure de la valeur globale est automatiquement reflétée dans la valeur locale.

gbrunick
la source
2

Je ne pense pas que vous puissiez. Cela revient à peu près à dire que vous voulez définir une variable globale qui ne peut pas être masquée par les déclarations de variables locales dans les fonctions. La portée ne fonctionne tout simplement pas de cette façon.

Cependant, il peut y avoir un moyen d'écrire une fonction elisp pour parcourir la liste des modes et la réaffecter dans chacun d'eux pour vous.

TED
la source
Cette idée de portée est techniquement correcte, mais overriding-local-mapest spécifiquement conçue pour remplacer toutes les autres cartes. Cependant, il est dangereux de l'utiliser.
event_jr
2

À moins que vous ne vouliez vraiment le faire vous-même, vous devriez vérifier et voir si quelqu'un d'autre l'a déjà fait.

Il existe un package pour Emacs qui donne à vos raccourcis clavier de type Windows. Vous devriez pouvoir le trouver via google.

JesperE
la source
4
Le package auquel vous pensez est probablement cua-mode.
Tiré
1
Oui, c'est le package.
JesperE