Anular globalmente el enlace de claves en Emacs

100

¿Cómo puedo establecer un enlace de clave que anule globalmente y tenga prioridad sobre todos los demás enlaces para esa clave? Quiero anular todos los mapas de modo mayor / menor y asegurarme de que mi enlace esté siempre en efecto.

Esto, por supuesto, no funciona:

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

Funciona text-mode, pero cuando lo uso lisp-mode, C-ise recupera lisp-indent-line.

Puedo revisar y anular este enlace en lisp-modey en cualquier otro modo individualmente, pero debe haber una manera más fácil. Cada vez que instalo un nuevo modo para un nuevo tipo de archivo, tengo que volver atrás y comprobar para asegurarme de que el nuevo modo no anula todas mis combinaciones de teclas.

Quiero hacer esto porque quiero emular enlaces que ya aprendí y arraigé de otros editores.

Brian Carper
fuente

Respuestas:

149

Utilizo un modo menor para todas mis combinaciones de teclas de "anulación":

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

Esto tiene el beneficio adicional de poder desactivar todas mis modificaciones de una sola vez (solo deshabilite el modo menor) en caso de que alguien más esté manejando el teclado o si necesito ver qué hace una combinación de teclas predeterminada.

Tenga en cuenta que es posible que deba desactivar esto en el minibúfer:

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

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
Scottfrazer
fuente
1
Esto parece una buena idea. ¿Hay alguna forma de asegurarse de que su modo menor no pelee con otros modos menores?
Brian Carper
3
Asegúrese de que su modo menor esté primero en la lista minor-mode-map-alist.
Trey Jackson
2
Trey tiene razón. Por lo general, poner esto cerca del final de su .emacs es suficiente. Además, la mayoría de los enlaces que anularía serían los que están configurando los modos principales ... los modos menores generalmente permanecen fuera del camino.
scottfrazer
Seguí este enfoque, pero luego me di cuenta de que todo lo que vincule a Ci también se vinculará a la tecla TAB. ¿Alguna sugerencia?
Steve
3
Brian Carper: Aquí hay una mejora para lidiar con los modos menores cargados posteriormente: stackoverflow.com/questions/683425/…
phils
30

Como adición a la respuesta de scottfrazer , escribí lo siguiente para que mis combinaciones de teclas conserven la prioridad, incluso si las bibliotecas cargadas posteriormente traen nuevos mapas de teclas propios.

Debido a que los mapas de teclas se pueden generar en tiempo de compilación, loadparecía el mejor lugar para hacer esto.

(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
fuente
Pegué su script pero no tuvo ningún efecto :(
alper
@alper Le sugiero que publique una pregunta con todos los detalles relevantes, incluido el código que está usando realmente, y un ejemplo / receta específica para reproducir el problema.
phils
21

Instalar use-package, evaluar y listo:

(require 'bind-key)
(bind-key* "C-i" 'some-function)
Mirzhan Irkegulov
fuente
5
Instalar solo bind-key es suficiente para el caso de uso, aunque use-package depende de bind-key.
xuchunyang
2
Este (paquete 'bind-key') parece ser la solución más conveniente; gracias por compartir.
oligilo
No pude encontrar coincidencias para use-package:Install package: use-package [No Match]
alper
14

Encontré esta pregunta mientras buscaba "emacs undefine org mode keybindings", porque quería desvincular el comportamiento existente de Cc Cb para permitir que mi mapa global bury-buffer funcione en un búfer de organización.

Esta terminó siendo la solución más simple para mí:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))
Jay Doane
fuente
1
Esto es específico del modo y no aborda el panorama general a pesar de que funciona para su caso de uso único.
RichieHH
12

Aunque la respuesta de scottfrazer es exactamente lo que pediste, mencionaré para la posteridad otra solución.

Del manual de Emacs :

"No defina la letra Cc como una clave en los programas Lisp. Las secuencias que constan de Cc y una letra (mayúscula o minúscula) están reservadas para los usuarios; son las únicas secuencias reservadas para los usuarios, así que no las bloquee".

Si vincula sus enlaces globales personales a Cc más una letra, entonces "debería" estar seguro. Sin embargo, esto es simplemente una convención, y cualquier modo puede anular sus enlaces.

Kirkland
fuente
3
No esperaba que el modo org, de todos los modos, rompiera esta regla. 'Cc Ch' me dice que Cc a, b, c y l están vinculados a org-agenda, org-iswitchb, org-capture y org-store-link, respectivamente.
Nate Parsons
7
Afaik, vincular estos es el primer paso que sugiere org-mode para usarlo, pero el usuario tiene que definirlos él mismo (es decir, no se hace por defecto), y puede elegir cualquier otro mientras lo hace. (también, es porque se supone que estas vinculaciones son globales, no vinculadas al modo principal de la organización)
Nikana Reklawyks
3

Si desea "usar siempre las combinaciones de teclas en el mapa, a menos que las anule explícitamente para un mapa de modo específico", y asumiendo que está utilizando el enfoque de scottfrazier , desea:

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

Entonces

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

debería eliminar el enlace "\ Ci" del modo menor sólo en el búfer actual. Advertencia: esto no está completamente probado, pero parece el enfoque correcto. El objetivo de establecer el padre en lugar de simplemente hacer frente al valor global de my-keys-minor-mode-map es que cualquier cambio posterior al valor global se refleje automáticamente en el valor local.

gbrunick
fuente
2

No creo que puedas. Eso es aproximadamente equivalente a decir que desea definir una variable global que no se pueda ocultar mediante declaraciones de variables locales en funciones. El alcance simplemente no funciona de esa manera.

Sin embargo, puede haber una forma de escribir una función elisp para revisar la lista de modos y reasignarla en cada uno de ellos.

TED
fuente
Esta idea de delimitación es técnicamente correcta, pero overriding-local-mapestá diseñada específicamente para anular todos los demás mapas. Sin embargo, es peligroso usarlo.
event_jr
2

A menos que realmente desee hacer esto usted mismo, debe verificar y ver si alguien más ya lo ha hecho.

Hay un paquete para Emacs que proporciona combinaciones de teclas similares a las de Windows. Debería poder encontrarlo a través de Google.

JesperE
fuente
4
El paquete en el que está pensando probablemente sea cua-mode.
Drew
1
Sí, ese es el paquete.
JesperE