Esegui l'override globale dell'associazione dei tasti in Emacs


100

Come posso impostare un'associazione di tasti che sostituisca globalmente e abbia la precedenza su tutte le altre associazioni per quella chiave? Voglio sovrascrivere tutte le mappe in modalità maggiore / minore e assicurarmi che il mio binding sia sempre attivo.

Questo ovviamente non funziona:

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

Funziona text-mode, ma quando lo uso lisp-mode, C-iè rimbalzato su lisp-indent-line.

Posso eseguire e ignorare questo collegamento in lisp-modee in ogni altra modalità individualmente, ma deve esserci un modo più semplice. Ogni volta che installo una nuova modalità per un nuovo tipo di file, dovrei tornare indietro e verificare che tutte le mie associazioni di tasti non vengano sovrascritte dalla nuova modalità.

Voglio farlo perché voglio emulare associazioni che ho già imparato e radicato da altri editor.

Risposte:


149

Uso una modalità minore per tutte le mie associazioni di tasti "override":

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

Questo ha l'ulteriore vantaggio di poter disattivare tutte le mie modifiche in un colpo solo (basta disabilitare la modalità minore) nel caso in cui qualcun altro stia guidando la tastiera o se ho bisogno di vedere cosa fa un'associazione di tasti predefinita.

Tieni presente che potresti dover disattivare questa opzione nel minibuffer:

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

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)

1
Sembra una buona idea. C'è un modo per assicurarti che la tua modalità minore non combatta con altre modalità minori?
Brian Carper

3
Assicurati che la tua modalità minore sia la prima nell'elenco minor-mode-map-alist.
Trey Jackson

2
Trey ha ragione. Di solito è sufficiente metterlo vicino alla fine del tuo .emacs. Inoltre, la maggior parte delle associazioni che ignoreresti sarebbero quelle impostate dalle modalità principali ... le modalità secondarie generalmente rimangono fuori mano.
scottfrazer

Ho seguito questo approccio, ma poi mi sono reso conto che tutto ciò che associo a Ci viene associato anche al tasto TAB. Eventuali suggerimenti?
Steve

3
Brian Carper: Ecco un miglioramento di trattare con modalità secondarie successivamente-caricati: stackoverflow.com/questions/683425/...
PHILS

30

In aggiunta alla risposta di scottfrazer , ho scritto quanto segue in modo che le mie associazioni di tasti mantengano la precedenza, anche se le librerie caricate successivamente introducono nuove mappe di tasti proprie.

Poiché le mappe dei tasti possono essere generate in fase di compilazione, loadsembrava il posto migliore per farlo.

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

Ho incollato il tuo script ma non ha avuto alcun effetto :(
alper

@alper Ti suggerisco di pubblicare una domanda con tutti i dettagli rilevanti, incluso il codice che stai effettivamente utilizzando e un esempio / ricetta specifico per riprodurre il problema.
phils

21

Installa use-package, valuta e il gioco è fatto:

(require 'bind-key)
(bind-key* "C-i" 'some-function)

5
Installare solo bind-key è sufficiente per il caso d'uso, sebbene use-package dipenda da bind-key.
xuchunyang

2
Questo (pacchetto "bind-key") sembra essere la soluzione più conveniente; grazie per la condivisione.
oligilo

Non sono riuscito a trovare una corrispondenza per use-package:Install package: use-package [No Match]
alper

14

Ho trovato questa domanda durante la ricerca di "emacs undefine org mode keybindings", perché volevo svincolare il comportamento Cc Cb esistente per consentire alla mia mappa globale di bury-buffer di funzionare in un buffer org.

Questa ha finito per essere la soluzione più semplice per me:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))

1
Questo è specifico della modalità e non affronta il quadro più ampio anche se funziona per il tuo caso d'uso singolo.
RichieHH

12

Sebbene la risposta di Scottfrazer sia esattamente ciò che hai chiesto, menzionerò per i posteri un'altra soluzione.

Dal manuale di Emacs :

"Non definire la lettera Cc come chiave nei programmi Lisp. Le sequenze composte da Cc e una lettera (maiuscola o minuscola) sono riservate agli utenti; sono le uniche sequenze riservate agli utenti, quindi non bloccarle."

Se leghi i tuoi vincoli globali personali a Cc più una lettera, "dovresti" essere al sicuro. Tuttavia, questa è solo una convenzione e qualsiasi modalità è ancora in grado di sovrascrivere le tue associazioni.


3
Non mi aspettavo che la modalità org, di tutte le modalità, infrangesse questa regola. "Cc Ch" mi dice che Cc a, b, c e l sono legati rispettivamente a org-agenda, org-iswitchb, org-capture e org-store-link.
Nate Parsons

7
Inoltre, associarli è il primo passo che la modalità org suggerisce per usarlo, ma l'utente deve definirli lui stesso (cioè non è fatto di default), e può scegliere qualsiasi altro mentre lo fa. (inoltre, è perché queste associazioni dovrebbero essere globali, non legate alla modalità principale
dell'org

3

Se vuoi "usare sempre le combinazioni di tasti nella mappa, a meno che io non le sovrascriva esplicitamente per una specifica modalità di mappa", e supponendo che tu stia usando l'approccio di scottfrazier , vuoi:

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

Così

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

dovrebbe rimuovere l'associazione "\ Ci" dalla modalità secondaria solo nel buffer corrente. Attenzione: questo è completamente non testato, ma sembra l'approccio giusto. Lo scopo di impostare il genitore piuttosto che semplicemente copiare il valore globale di my-keys-minor-mode-map è che qualsiasi modifica successiva al valore globale si rifletta automaticamente nel valore locale.


2

Non credo che tu possa. Ciò equivale all'incirca a dire che si desidera definire una variabile globale che non può essere nascosta dalle dichiarazioni di variabili locali nelle funzioni. Scope semplicemente non funziona in questo modo.

Tuttavia, potrebbe esserci un modo per scrivere una funzione elisp per scorrere l'elenco delle modalità e riassegnarla in ogni singola funzione per te.


Questa idea di scoping è tecnicamente corretta, ma overriding-local-mapè progettata specificamente per sovrascrivere tutte le altre mappe. Tuttavia è pericoloso usarlo.
event_jr

2

A meno che tu non voglia davvero farlo da solo, dovresti controllare in giro e vedere se qualcun altro lo ha già fatto.

Esiste un pacchetto per Emacs che fornisce combinazioni di tasti simili a quelle di Windows. Dovresti essere in grado di trovarlo tramite google.


4
Il pacchetto a cui stai pensando è probabilmente cua-mode.
Drew

1
Sì, questo è il pacchetto.
JesperE
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.