Come sovrascrivere i binding della modalità principale


38

A volte le mie combinazioni di tasti globali sono sostituite da una modalità principale. Un semplice esempio è la seguente impostazione nel mio file init

(global-set-key (kbd "C-j") 'newline-and-indent)

Ma fastidiosamente questa combinazione di tasti è nascosta dalla modalità principale "Interazione Lisp", che è la modalità predefinita del buffer di memoria virtuale.

Quando mi trovo in una situazione in cui una modalità maggiore (o secondaria) nasconde il mio keybinding globale, come posso recuperarlo?

Nota: La mia domanda non è : "Come posso legano C-ja newline-and-indent'? Mode' in" Lisp Interaction Sono interessato a una risposta molto più generale su come gestire le keymap che si scontrano o le combinazioni di tasti dell'utente che vengono nascoste da una modalità maggiore / minore.


Risposte:


39

C'è anche un approccio "scorciatoia" per la stessa soluzione se non vuoi definire la tua modalità minore (di cui parlo nella mia prima risposta).

È possibile installare il use-packagepacchetto disponibile da Melpa e utilizzare bind-key*o bind-keys*macro che fa parte del bind-keypacchetto fornito use-package.

Dalla documentazione di bind-key.el:

;; If you want the keybinding to override all minor modes that may also bind
;; the same key, use the `bind-key*' form:
;;
;;   (bind-key* "<C-return>" 'other-window)

;; To bind multiple keys in a `bind-key*' way (to be sure that your bindings
;; will not be overridden by other modes), you may use `bind-keys*' macro:
;;
;;    (bind-keys*
;;     ("C-o" . other-window)
;;     ("C-M-n" . forward-page)
;;     ("C-M-p" . backward-page))

Nel caso qualcuno fosse curioso, nota che questo usa solo una modalità minore dietro le quinte. Adotta un approccio diverso ai conflitti con altre modalità minori, usando emulation-mode-map-alistsper imporre la precedenza).
phils,

Ho segnato questa come risposta per la sua semplicità. Sta essenzialmente facendo la stessa cosa di questa risposta , ma sta comodamente facendo la maggior parte del lavoro per te dietro le quinte.
nispio,

@nispio Hai ragione. Dalla mia esperienza, l'unica differenza è il metodo utilizzato per fare in modo che i vincoli delle modalità secondarie prevalgano su altre modalità a livello globale. Ma il vantaggio dell'altro approccio (di avere la tua modalità minore) è che puoi disattivarlo momentaneamente per provare gli attacchi emacs originali se mai dovessi (ho dovuto farlo alcune volte).
Kaushal Modi,

1
Aggiungi (bind-key* "C-M-&" 'override-global-mode), al tuo init, e di solito puoi rimuovere rapidamente i binding, se necessario. Poiché override-global-modenon è una modalità secondaria "globale", sarà comunque necessario disattivarla in base al buffer. Quindi, se ti trovi a disattivare frequentemente le chiavi di override globale, questa soluzione non è conveniente.
nispio,

25

Puoi definire la tua modalità minore e la sua mappa chiave e far sì che prevalgano su tutte le altre modalità (minore + maggiore). Questo è esattamente il motivo per cui ho scelto di scrivere la mia modalità minore.

I passaggi per fare in modo che i tuoi collegamenti chiave prevalgano su tutti i collegamenti:

  • Definire la propria modalità secondaria e la mappa dei tasti come mostrato di seguito.
  • Attiva la tua modalità secondaria a livello globale
  • (define-key my-mode-map (kbd "C-j") #'newline-and-indent)

Allo stesso modo le altre combinazioni di tasti impostate nella modalità secondaria avranno la precedenza su quelle delle altre modalità.

Consiglio vivamente di leggere il post sul blog di Christopher Wellons su come scrivere una modalità minore. Quel blog e il fastidio di dover impostare più combinazioni di tasti nilin più modalità principali e secondarie mi hanno ispirato a scrivere la mia modalità minore.

La parte migliore dell'uso di questo approccio è che quando vuoi controllare cosa fanno i collegamenti chiave nella configurazione predefinita di emacs, devi semplicemente disattivare la modalità minore; quindi lo riattivi e ottieni i tasti personalizzati.

;; Main use is to have my key bindings have the highest priority
;; https://github.com/kaushalmodi/.emacs.d/blob/master/elisp/modi-mode.el

(defvar my-mode-map (make-sparse-keymap)
  "Keymap for `my-mode'.")

;;;###autoload
(define-minor-mode my-mode
  "A minor mode so that my key settings override annoying major modes."
  ;; If init-value is not set to t, this mode does not get enabled in
  ;; `fundamental-mode' buffers even after doing \"(global-my-mode 1)\".
  ;; More info: http://emacs.stackexchange.com/q/16693/115
  :init-value t
  :lighter " my-mode"
  :keymap my-mode-map)

;;;###autoload
(define-globalized-minor-mode global-my-mode my-mode my-mode)

;; https://github.com/jwiegley/use-package/blob/master/bind-key.el
;; The keymaps in `emulation-mode-map-alists' take precedence over
;; `minor-mode-map-alist'
(add-to-list 'emulation-mode-map-alists `((my-mode . ,my-mode-map)))

;; Turn off the minor mode in the minibuffer
(defun turn-off-my-mode ()
  "Turn off my-mode."
  (my-mode -1))
(add-hook 'minibuffer-setup-hook #'turn-off-my-mode)

(provide 'my-mode)

;; Minor mode tutorial: http://nullprogram.com/blog/2013/02/06/

5

Per fare in modo che un'associazione globale abbia la precedenza su un'associazione in modalità principale, è sufficiente impostare l'associazione nilin modalità principale:

(define-key my-major-mode-map (kbd "C-j") nil)

Non è possibile avere la rilegatura globale avere la precedenza su tutte le modalità in generale (altrimenti non avrebbe senso avere modalità principali), ma potresti aggirarla creando una tua modalità minore con le tue associazioni più importanti. Quindi avresti almeno la precedenza sulla maggior parte delle modalità (sebbene non necessariamente tutte).


Funzionerà con qualsiasi modalità principale arbitraria? In altre parole, se installo una modalità principale chiamata "foo-mode" posso inserire il (define-key foo-mode (kbd "C-j") nil)mio file .emacs e aspettarmi che funzioni?
nispio,

In realtà vorrai che lo sia foo-mode-map(il mio esempio nella risposta è stato negativo), ma sì, disabiliterà il keybinding nella modalità principale in modo da utilizzare invece il keybinding globale (a meno che non ci sia una modalità secondaria diversa che lo sta usando).
shosti,

È abbastanza universale che foo-modeverrà chiamata la keymap per foo-mode-map?
nispio,

@nispio sì, questo è vero per la stragrande maggioranza delle modalità (anche se ci sono alcuni ladri là fuori).
shosti,

0

Puoi usare queste macro:

(defmacro expose-global-keybinding (binding map)
  `(define-key ,map ,binding (lookup-key (current-global-map) ,binding)))

(defmacro expose-bindings (map bindings)
  `(dolist (bnd ,bindings)
     (expose-global-keybinding (kbd bnd) ,map)))

MODIFICA :

Controlla il seguente esempio:

Se la keymap X sta sovrascrivendo la tua associazione globale Y, scrivi:

(expose-bindings X '("Y"))

E quindi l'override sarà "annullato".


la tua macro ti consente di utilizzare il backquote: `(define-key, map, binding (lookup-key (current-global-map), binding))
Sigma

Puoi commentare cosa sta facendo la macro e come usarla? Non mi è chiaro dal codice.
nispio,

La prima macro cerca semplicemente la chiave nella mappa globale e assegna il risultato al other map, esponendo così il legame della mappa globale attraverso il other map. Il secondo consente di applicare il primo per un elenco di associazioni.
Renan Ranelli,

Scusate se sono denso, ma ancora non capisco completamente l'uso. Devo definire la mia keymap globale speciale? Deve appartenere a una modalità minore? expose-bindingsPrima eseguo e poi associo globalmente quei tasti ai comandi che desidero? Forse potresti mostrare un esempio di ciò che potrei mettere nel mio file init per farlo funzionare.
nispio,

2
Si noti che questi nomi di macro sono termini impropri. Non "espongono" il legame globale, ma piuttosto duplicano il legame globale. Se la vera associazione globale cambia, queste copie duplicate no.
phils,
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.