Como vincular Ci como diferente da TAB?

15

Eu quero fazer Control-iperformance indent-region(basicamente porque o Xcode já construiu essa memória muscular).

Eu percebo isso Control-ie tabsão indistinguíveis no sentido Ascii, mas eles são no sentido do código-chave.

Eu tentei o óbvio:

(global-unset-key (kbd "C-i"))
(global-set-key (kbd "C-i") 'indent-region)

sem sucesso - pressionar Control-iainda faz apenas o que a tabtecla faz no contexto atual. Existe algo que eu possa fazer para ajudar o Emacs a tratar o botão da guia de maneira diferente Control-i?

Atualização: Eu acho que um resultado equivalente seria alcançado sendo capaz de remapear o que a tab/ Control-ipress faz quando uma região é selecionada.

Mark Aufflick
fonte
11
Isso é de um quadro da GUI ou de um quadro do terminal? Não sei se você pode substituí-lo por um terminal.
dgtized 25/09/14
Boa Q, quadro GUI normalmente, mas eu faço remoto para servidores e uso emacs em um às vezes terminais (com um emacs.d compartilhada-git é claro :)
Mark Aufflick

Respostas:

14

Eu não acho que isso possa ser alcançado a partir de um terminal, mas no modo GUI você pode tentar o seguinte:

(define-key input-decode-map [?\C-i] [C-i])
(global-set-key (kbd "<C-i>") 'indent-region)

Eu faço a mesma coisa C-mpara que possa ser distinguido deRET

EDITAR:

O seguinte deve funcionar se você estiver no modo GUI ou TTY:

;; Unbind <C-i> from the TAB key and bind it to indent-region.
;; Since TAB and <C-i> cannot be differentiated in TTY emacs,
;; the workaround is to conditionally bind TAB to indent-region
;; when there is an active region selected.
(if (window-system)
  ; IF we are not in a TTY, unbind C-i from TAB
    (progn
      (define-key input-decode-map [?\C-i] [C-i])
      ; ... and remap it to indent-region
      (global-set-key (kbd "<C-i>") 'indent-region))
  ; ELSE IF we are in a TTY, create a replacement for TAB
  (defun my/tab-replacement (&optional START END)
    (interactive "r")
    (if (use-region-p)
      ; IF active region, use indent-region
        (indent-region START END)
      ; ELSE IF no active region, use default tab command
      (indent-for-tab-command)))
  ; Bind our quick-and-dirty TAB replacement to the TAB key
  (global-set-key (kbd "TAB") 'my/tab-replacement))

Não é bonito, mas parece fazer o trabalho. Congratulo-me com quaisquer aperfeiçoamentos ou edições neste código, conforme necessário.

nispio
fonte
11
Funciona perfeitamente! ++ iria comprar um emacs Stackexchange novamente :)
Mark Aufflick
O único pequeno problema que pensei é que agora podemos abrir um emacsclient terminal contra um Emacs iniciado com um sistema de janelas (o que eu faço algumas vezes). Se não houver atraso, usarei a função de substituição de guias em todos os casos.
precisa saber é o seguinte
11
Eu só quero acrescentar que o <C-i>e [C-i]poderia ter sido um identificador arbitrário, como <foobar>e [foobar], e ainda funcionaria; apenas não chame taboubackspace
xdavidliu 13/07/19
13

Quadros da GUI

Nos quadros da GUI (seja X11, Windows, OSX,…), o Emacs lê a Tabchave como a tabtecla de função. No entanto, como a Tabtecla nos terminais envia tradicionalmente o caractere ^I( Control + I), o Emacs converte a tabtecla de função no caractere Control + I (caractere 9), que é exibido como TAB. Esta tradução é feita via function-key-map.

Uma tradução semelhante ocorre com algumas outras teclas de função. ( Backspacee Deleteé um caso espinhoso que não discutirei em detalhes aqui.)

Function key    Translated to character         Notes
                Number  Name  Decomposition
backspace       127     DEL   Ctrl+?            May be translated to C-h instead
tab               9     TAB   Ctrl+I
linefeed         10     LFD   Ctrl+J            Few keyboards have this key
return           13     RET   Ctrl+M
escape           27     ESC   Ctrl+[

Se você deseja separar Taba partir Ctrl+ Icompletamente, remover a ligação de function-key-map:

(define-key function-key-map [tab] nil)

No entanto, isso não é muito útil, porque as entradas em function-key-mapsão substituídas por ligações em mapas de teclas específicos de modo ou no mapa global. Portanto, se você deseja definir uma ligação diferente tab, basta fazê-lo (no Elisp, não de maneira interativa, porque o prompt de leitura de chave aplica a function-key-maptradução, para que você acabe religando TABe não tab):

(global-set-key [tab] '…)
(define-key some-mode-map [tab] '…)

Todos os modos padrão que modificam a ação da Tabchave fazem isso modificando a TABchave, que é um apelido para o C-icaractere gerado pela combinação de teclas Ctrl+ I. Se você deseja que as ligações padrão sejam aplicadas em tabvez de C-i, deixe function-key-mape modifique os mapas de teclas sozinhos e, em vez disso, redirecione Ctrl+ Ipara uma chave diferente.

(define-key input-decode-map [(control ?i)] [control-i])
(define-key input-decode-map [(control ?I)] [(shift control-i)])
(define-key some-mode-map [control-i] '…)

Agora o Emacs reportará Ctrl+ Icomo " <control-i>(traduzido de TAB)". Isso não é bonito, mas é inevitável: a bonita impressão do personagem 9, como TABestá embutida no código-fonte do Emacs.

Quadros de terminais

Nos quadros de terminais, o problema é mais difícil e geralmente impossível. Os terminais não transmitem chaves, eles transmitem caracteres (mais precisamente, eles transmitem bytes). A Tabtecla é transmitida como o caractere de tabulação - que é Control + I, igual ao que a combinação de teclas Ctrl+ Igera. As teclas de função que não possuem caracteres correspondentes (como teclas de cursor) são transmitidas como seqüências de escape, ou seja, sequências de caracteres começando com ESC= Control + [(é por isso que o Emacs define escapecomo uma tecla de prefixo - ESCdeve ser um prefixo). Consulte Como funcionam a entrada do teclado e a saída de texto? para mais informações.

Existem alguns terminais que podem ser configurados para enviar sequências de teclas diferentes para teclas de função, mas não muitas. Ambos de LeoNerd libtermkey / libtickit e xterm de Thomas Dickey (desde a versão 216) suporta isto. No Xterm, o recurso é opcional e ativado por meio do modifyOtherKeysrecurso. No entanto, não conheço outro emulador de terminal popular que não seja o xterm que suporte isso, em particular os muitos emuladores criados com libvte . Alguns emuladores de terminal permitem fazer isso manualmente por meio de uma correspondência definida pelo usuário, dos acordes de teclas, para escapar das seqüências.

Este mecanismo permite distinguir muitas combinações de teclas, não apenas tab / Ci, return / Cm e escape / C- [. Consulte Problemas com atalhos de teclas ao usar o terminal para obter uma descrição mais detalhada.

O recurso básico do xterm é suportado desde o Emacs 24.4. No entanto, os fundamentos (em particular Tab, Return, Escape, Backspace) ainda enviar os caracteres de controle tradicionais, porque é isso que as aplicações esperar. Existe um modo em que Ctrl+ letterenvia uma sequência de escape em vez do caractere de controle. Portanto, para distinguir as teclas de função das Ctrlcombinações no Emacs 24.4, modifique seu suporte para modifyOtherKeysusar esse modo, configurando o recurso para 2 em vez de 1.

;; xterm with the resource ?.VT100.modifyOtherKeys: 2
;; GNU Emacs >=24.4 sets xterm in this mode and define
;; some of the escape sequences but not all of them.
(defun character-apply-modifiers (c &rest modifiers)
  "Apply modifiers to the character C.
MODIFIERS must be a list of symbols amongst (meta control shift).
Return an event vector."
  (if (memq 'control modifiers) (setq c (if (or (and (<= ?@ c) (<= c ?_))
                                                (and (<= ?a c) (<= c ?z)))
                                            (logand c ?\x1f)
                                          (logior (lsh 1 26) c))))
  (if (memq 'meta modifiers) (setq c (logior (lsh 1 27) c)))
  (if (memq 'shift modifiers) (setq c (logior (lsh 1 25) c)))
  (vector c))
(defun my-eval-after-load-xterm ()
  (when (and (boundp 'xterm-extra-capabilities) (boundp 'xterm-function-map))
    ;; Override the standard definition to set modifyOtherKeys to 2 instead of 1
    (defun xterm-turn-on-modify-other-keys ()
      "Turn the modifyOtherKeys feature of xterm back on."
      (let ((terminal (frame-terminal)))
        (when (and (terminal-live-p terminal)
                   (memq terminal xterm-modify-other-keys-terminal-list))
          (send-string-to-terminal "\e[>4;2m" terminal))))
    (let ((c 32))
      (while (<= c 126)
        (mapc (lambda (x)
                (define-key xterm-function-map (format (car x) c)
                  (apply 'character-apply-modifiers c (cdr x))))
              '(;; with ?.VT100.formatOtherKeys: 0
                ("\e\[27;3;%d~" meta)
                ("\e\[27;5;%d~" control)
                ("\e\[27;6;%d~" control shift)
                ("\e\[27;7;%d~" control meta)
                ("\e\[27;8;%d~" control meta shift)
                ;; with ?.VT100.formatOtherKeys: 1
                ("\e\[%d;3~" meta)
                ("\e\[%d;5~" control)
                ("\e\[%d;6~" control shift)
                ("\e\[%d;7~" control meta)
                ("\e\[%d;8~" control meta shift)))
        (setq c (1+ c)))))
  (define-key xterm-function-map "")
  t)
(eval-after-load "xterm" '(my-eval-after-load-xterm))
Gilles 'SO- parar de ser mau'
fonte
Quando você diz "Emacs 24.24", você quer dizer "Emacs 24.4"?
tarsius 11/11/19
11
@tarsius Um comentário no código copiado do meu arquivo init diz “24.4”, então acho que está correto e “24.24” no texto que escrevi para esta resposta foi um erro de digitação para “24.4”.
Gilles 'SO- stop be evil'