Sobrescrever globalmente a vinculação de teclas no Emacs


100

Como posso definir uma associação de chave que substitui globalmente e tem precedência sobre todas as outras associações dessa chave? Desejo substituir todos os mapas de modo principal / secundário e garantir que minha vinculação esteja sempre em vigor.

É claro que isso não funciona:

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

Funciona text-mode, mas quando eu uso lisp-mode, C-ié rebote para lisp-indent-line.

Posso passar e substituir essa ligação em lisp-modetodos os outros modos individualmente, mas deve haver uma maneira mais fácil. Cada vez que instalo um novo modo para um novo tipo de arquivo, tenho que voltar e verificar se todas as minhas combinações de teclas não estão sendo substituídas pelo novo modo.

Quero fazer isso porque quero emular ligações que já aprendi e arraigou de outros editores.

Respostas:


149

Eu uso um modo menor para todas as minhas combinações de teclas "substituir":

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

Isso tem o benefício adicional de poder desligar todas as minhas modificações de uma só vez (apenas desabilitar o modo menor) no caso de outra pessoa estar dirigindo o teclado ou se eu precisar ver o que um atalho de tecla padrão faz.

Observe que você pode precisar desligar isso no minibuffer:

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

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

1
Parece uma boa ideia. Existe alguma maneira de garantir que seu modo menor não combata com outros modos menores?
— Brian Carper,

3
Certifique-se de que seu modo menor seja o primeiro na lista de mapeamento de modo menor.
— Trey Jackson,

2
Trey está certo. Normalmente, colocar isso perto do final do seu .emacs é o suficiente. Além disso, a maioria das ligações que você substituiria seriam aquelas que os modos principais estão definindo ... os modos secundários geralmente ficam fora do caminho.
— scottfrazer

Eu segui essa abordagem, mas então percebi que qualquer coisa que eu vincular a Ci também é vinculada à tecla TAB. Alguma sugestão?
— Steve

3
Brian Carper: Aqui está uma melhoria para lidar com modos secundários carregados subsequentemente: stackoverflow.com/questions/683425/…
— phils

30

Como complemento à resposta de scottfrazer , escrevi o seguinte para que meus atalhos de teclado mantenham a precedência, mesmo que as bibliotecas carregadas posteriormente tragam novos mapas de teclado próprios.

Como os mapas de teclado podem ser gerados em tempo de compilação, load parecia o melhor lugar para fazer isso.

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

Colei seu script, mas não fez nenhum efeito :(
— alper

@alper Eu sugiro que você poste uma pergunta com todos os detalhes relevantes, incluindo o código que você está realmente usando, e um exemplo / receita específica para reproduzir o problema.
— phils

21

Instale use-package, avalie e pronto:

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

5
Instalar apenas a chave de ligação é suficiente para o caso de uso, embora o pacote de uso dependa da chave de ligação.
— xuchunyang de

2
Este (pacote 'bind-key') parece ser a solução mais conveniente; obrigado por compartilhar.
— oligilo

Não consegui encontrar correspondência para use-package:Install package: use-package [No Match]
— alper

14

Eu encontrei esta questão enquanto procurava por "emacs undefine org mode keybindings", porque eu queria desvincular o comportamento Cc Cb existente para permitir que meu mapa global enterrasse o buffer para funcionar em um buffer org.

Isso acabou sendo a solução mais simples para mim:

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

1
Isso é específico do modo e não aborda o panorama geral, embora funcione para o seu único caso de uso.
— RichieHH

12

Embora a resposta de Scottfrazer seja exatamente o que você pediu, mencionarei para a posteridade outra solução.

Do Manual Emacs :

"Não defina a letra Cc como uma chave em programas Lisp. As sequências que consistem em Cc e uma letra (maiúscula ou minúscula) são reservadas para os usuários; são as únicas sequências reservadas para os usuários, portanto, não as bloqueie."

Se você vincular suas ligações globais pessoais a Cc mais uma letra, "deveria" estar seguro. No entanto, isso é apenas uma convenção, e qualquer modo ainda pode substituir suas ligações.


3
Eu não esperava que o modo org, de todos os modos, quebrasse essa regra. `Cc Ch 'me diz que Cc a, b, c e l estão vinculados a org-agenda, org-iswitchb, org-capture e org-store-link, respectivamente.
— Nate Parsons

7
Afaik, vinculá-los é a primeira etapa que o modo org sugere para usá-lo, mas o usuário deve defini-los (ou seja, não é feito por padrão) e pode escolher qualquer outro enquanto faz isso. (também, é porque essas vinculações devem ser globais, não vinculadas ao modo org major)
— Nikana Reklawyks,

3

Se você quiser "sempre usar os atalhos de teclado no mapa, a menos que eu os substitua explicitamente por um mapa de modo específico" e presumindo que está usando a abordagem de scottfrazier , você deseja:

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

assim

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

deve remover a ligação "\ Ci" do modo secundário apenas no buffer atual. Aviso: isso não foi testado, mas parece ser a abordagem certa. O objetivo de definir o pai em vez de apenas lidar com o valor global de my-keys-minor-mode-map é que quaisquer alterações posteriores no valor global sejam automaticamente refletidas no valor local.


2

Eu não acho que você pode. Isso é aproximadamente equivalente a dizer que você deseja definir uma variável global que não pode ser oculta por declarações de variáveis ​​locais em funções. O escopo simplesmente não funciona dessa maneira.

No entanto, pode haver uma maneira de escrever uma função elisp para percorrer a lista de modos e reatribuí-la em cada um para você.


Essa ideia de escopo é tecnicamente correta, mas overriding-local-mapfoi projetada especificamente para substituir todos os outros mapas. No entanto, é perigoso usá-lo.
— event_jr

2

A menos que você realmente queira fazer isso sozinho, deve verificar ao redor e ver se alguém já fez isso.

Existe um pacote para Emacs que fornece atalhos de teclado semelhantes aos do Windows. Você deve ser capaz de encontrá-lo no google.


4
O pacote em que você está pensando é provavelmente cua-mode.
— Desenhou em

1
Sim, esse é o pacote.
— JesperE
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.