Cómo anular enlaces de modo mayor

38

A veces, mis combinaciones de teclas globales son anuladas por un modo principal. Un ejemplo sencillo es la siguiente configuración en mi archivo de inicio

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

Pero molestamente, esta combinación de teclas está oculta por el modo principal "Interacción Lisp", que es el modo predeterminado del búfer de memoria virtual.

Cuando me encuentro en una situación en la que un modo mayor (o modo menor) está ocultando mi combinación de teclas global, ¿cómo puedo recuperarlo?

Nota: Mi pregunta no es "¿Cómo puedo unen C-ja newline-and-indent'? Modo' en" Lisp Interaction Estoy interesado en una respuesta mucho más general sobre cómo lidiar con los mapas de teclas que chocan o las combinaciones de teclas del usuario que se ocultan en algún modo mayor / menor.

nispio
fuente

Respuestas:

39

También hay un enfoque de "acceso directo" para la misma solución si no desea definir su propio modo menor (del que hablo en mi primera respuesta).

Puede instalar el use-packagepaquete disponible de melpa y hacer uso de bind-key*o bind-keys*macro que es parte del bind-keypaquete que se envía con use-package.

De la documentación de 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))
Kaushal Modi
fuente
En caso de que alguien tenga curiosidad, tenga en cuenta que esto solo usa un modo menor detrás de escena. Toma un enfoque diferente a los conflictos con otros modos menores, al usar emulation-mode-map-alistspara imponer la precedencia).
Phil
He marcado esto como la respuesta debido a su simplicidad. Básicamente está haciendo lo mismo que esta respuesta , pero está haciendo convenientemente la mayor parte del trabajo detrás de escena.
nispio
@nispio Estás en lo correcto. Según mi experiencia, la única diferencia es el método que se utiliza para hacer que los enlaces de modo menor anulen otros modos a nivel mundial. Pero la ventaja del otro enfoque (de tener su propio modo menor) es que puede desactivarlo momentáneamente para probar los enlaces originales de emacs si alguna vez lo necesita (he tenido que hacerlo varias veces).
Kaushal Modi
1
Agregue (bind-key* "C-M-&" 'override-global-mode), a su inicio, y generalmente puede eliminar los enlaces rápidamente si lo necesita. Dado override-global-modeque no es un modo menor "global", aún deberá desactivarlo por búfer. Entonces, si te encuentras desactivando con frecuencia las teclas de anulación global, entonces esta solución no es conveniente.
nispio
25

Puede definir su propio modo menor y su mapa clave y hacer que anule todos los demás modos (menor + mayor). Es exactamente por eso que elegí escribir mi propio modo menor.

Pasos para que sus combinaciones de teclas anulen todas las combinaciones:

  • Definir su propio modo menor y mapa de teclas como se muestra a continuación.
  • Activa tu modo menor globalmente
  • (define-key my-mode-map (kbd "C-j") #'newline-and-indent)

Del mismo modo, sus otras combinaciones de teclas establecidas en su modo menor anularán las de otros modos.

Recomiendo leer la publicación de blog de Christopher Wellons sobre cómo escribir un modo menor. Ese blog, más la molestia de tener que establecer varias asociaciones de teclas nilen múltiples modos mayores y menores, me inspiró a escribir mi propio modo menor.

La mejor parte del uso de este enfoque es que cuando desea verificar qué hacen las combinaciones de teclas en la configuración predeterminada de emacs, simplemente apaga su modo menor; luego lo vuelve a encender y recupera sus combinaciones de teclas personalizadas.

;; 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/
Kaushal Modi
fuente
5

Para que un enlace global anule un enlace del modo principal, simplemente configure el enlace nilen el modo principal:

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

No es posible que el enlace global tenga prioridad sobre todos los modos en general (de lo contrario, no tendría sentido tener modos principales), pero podría hackearlo creando su propio modo menor con sus enlaces más importantes. Entonces al menos tendría prioridad sobre la mayoría de los modos (aunque no necesariamente todos).

shosti
fuente
¿Funcionará para algún modo mayor arbitrario? En otras palabras, si instalo un modo principal llamado "modo foo", ¿puedo poner (define-key foo-mode (kbd "C-j") nil)mi archivo .emacs y esperar que esto funcione?
nispio
En realidad, querrás que sea foo-mode-map(mi ejemplo en la respuesta fue malo), pero sí, eso deshabilitará la combinación de teclas en el modo mayor, por lo que se usará la combinación de teclas global (a menos que haya un modo menor diferente que lo esté usando).
shosti
¿Es bastante universal que foo-modese llame al mapa de teclas para foo-mode-map?
nispio
@nispio sí, eso es cierto para la gran mayoría de los modos (aunque hay algunos pícaros por ahí).
shosti
0

Puedes usar estas macros:

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

EDITAR :

Verifique el ejemplo a continuación:

Si el mapa de teclas X está anulando su enlace global Y, usted escribe:

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

Y luego la anulación se 'deshacerá'.

Renan Ranelli
fuente
su macro se beneficia al usar la comilla invertida: `(clave de definición, mapa, enlace (clave de búsqueda (mapa global actual), enlace))
Sigma
¿Puedes comentar qué está haciendo la macro y cómo usarla? No me queda claro por el código.
nispio
La primera macro solo busca la clave en el mapa global y asigna el resultado a other map, exponiendo así el enlace del mapa global a través de other map. El segundo simplemente le permite aplicar el primero para una lista de enlaces.
Renan Ranelli
Lo siento si estoy siendo denso, pero todavía no entiendo completamente el uso. ¿Necesito definir mi propio mapa de teclas global especial? ¿Tiene que pertenecer a un modo menor? ¿Realizo expose-bindingsprimero y luego ato globalmente esas teclas a los comandos que quiero? Tal vez podría mostrar un ejemplo de lo que podría poner en mi archivo de inicio para que esto funcione.
nispio
2
Tenga en cuenta que estos nombres de macro son nombres incorrectos. No "exponen" el enlace global, sino que duplican el enlace global. Si el enlace global real cambia, estas copias duplicadas no lo harán.
phils