Come legare Ci come diverso da TAB?


16

Voglio Control-iesibirmi indent-region(praticamente da quando Xcode ha già costruito quella memoria muscolare).

Me ne rendo conto Control-ie tabsono indistinguibili nel senso Ascii, ma sono nel senso del codice chiave.

Ho provato l'ovvio:

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

inutilmente - premendo Control-iancora si fa qualunque cosa il tabtasto faccia nel contesto attuale. C'è qualcosa che posso fare per aiutare Emacs a trattare diversamente il pulsante della scheda Control-i?

Aggiornamento: immagino che si otterrebbe un risultato equivalente potendo rimappare ciò che fa un tab/ Control-ipress quando viene selezionata una regione.


1
Proviene da un frame GUI o da un frame terminale? Non so se è possibile ignorarlo per un terminale.
dgtized

Buona Q, frame GUI di solito, ma a volte eseguo remoti nei server e uso emacs in un terminale a volte (con un emacs.d condiviso da git ovviamente) :)
Mark Aufflick,

Risposte:


15

Non penso che ciò possa essere ottenuto da un terminale, ma in modalità GUI potresti provare questo:

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

Faccio la stessa cosa con in C-mmodo che possa essere distinto daRET

MODIFICARE:

Quanto segue dovrebbe funzionare in modalità GUI o 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))

Non è carino, ma sembra fare il lavoro. Accolgo con favore qualsiasi perfezionamento o modifica di questo codice, se necessario.


1
Funziona perfettamente! ++ comprerebbe di nuovo uno stackexchange di emacs :)
Mark Aufflick,

L'unico problema minore che ho appena pensato è che ora possiamo richiamare un emacsclient terminale contro un Emacs che è stato avviato con un sistema a finestre (cosa che a volte faccio). Se non vedo alcun ritardo, userò semplicemente la funzione di sostituzione della scheda in tutti i casi.
Mark Aufflick,

1
Voglio solo aggiungere che il <C-i>e [C-i]avrebbe potuto essere un identificatore arbitrario, come <foobar>e [foobar], e funzionerebbe ancora; semplicemente non chiamarlo tabobackspace
xdavidliu,

Ho aggiunto pezzo di codice modificato sulla vostra risposta nel .emacsfile, ma entrambi TABed C-iè rimappata :-( @nispio
Alper

13

Frame della GUI

Nei frame della GUI (sia X11, Windows, OSX, ...), Emacs legge il Tabtasto come tabtasto funzione. Tuttavia, poiché il Tabtasto sui terminali tradizionalmente invia il carattere ^I( Control + I), Emacs traduce il tabtasto funzione nel carattere Control + I (carattere 9), che viene visualizzato come TAB. Questa traduzione viene effettuata tramite function-key-map.

Una traduzione simile avviene con alcuni altri tasti funzione. ( Backspacee Deletesono un caso spinoso di cui non parlerò in dettaglio qui.)

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 si desidera separare Tabda Ctrl+ del Itutto, rimuovere l'associazione da function-key-map:

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

Tuttavia, ciò non è molto utile, poiché le voci in function-key-mapvengono sovrascritte dai collegamenti nelle mappe dei tasti specifiche della modalità o nella mappa globale. Quindi, se vuoi definire un'associazione diversa per tab, fallo (in Elisp, non in modo interattivo, perché il prompt di lettura della chiave applica la function-key-maptraduzione in modo da finire con la rilegatura TABe non tab):

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

Tutte le modalità standard che modificano l'azione della Tabchiave lo fanno modificando la TABchiave, che è un soprannome per il C-icarattere generato dalla combinazione di tasti Ctrl+ I. Se desideri che i binding standard si applichino tabpiuttosto che C-i, lascia function-key-mape modifichi da solo le mappe dei tasti e invece reindirizza Ctrl+ Ia una chiave diversa.

(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] '…)

Ora Emacs riporterà Ctrl+ Icome " <control-i>(tradotto da TAB)". Questo non è carino, ma è inevitabile: la bella stampa del personaggio 9 così come TABè incorporata nel codice sorgente di Emacs.

Telai terminali

Nei terminali, il problema è più difficile e spesso impossibile. I terminali non trasmettono chiavi, trasmettono caratteri (più precisamente, infatti, trasmettono byte). La Tabchiave viene trasmessa come carattere di tabulazione, ovvero Control + I, uguale a ciò che genera la combinazione di tasti Ctrl+ I. I tasti funzione che non hanno caratteri corrispondenti (come i tasti cursore) vengono trasmessi come sequenze di escape, ovvero sequenze di caratteri che iniziano con ESC= Control + [(motivo per cui Emacs definisce escapeun tasto prefisso - ESCdeve essere un prefisso). Vedi Come funzionano l'input da tastiera e l'output di testo? per più sfondo.

Esistono alcuni terminali che possono essere configurati per inviare sequenze di tasti diversi per i tasti funzione, ma non molti. Sia libtermkey / libtickit di LeoNerd che xterm di Thomas Dickey (dalla versione 216) supportano questo. In Xterm, la funzione è facoltativa e attivata tramite la modifyOtherKeysrisorsa. Tuttavia, non conosco alcun emulatore di terminale popolare diverso da xterm che supporti questo, in particolare i numerosi emulatori basati su libvte . Alcuni emulatori di terminale ti consentono di farlo manualmente attraverso una corrispondenza definita dall'utente dai tasti principali per sfuggire alle sequenze.

Questo meccanismo consente di distinguere molte combinazioni di tasti, non solo tab / Ci, return / Cm e escape / C- [. Vedere Problemi con le combinazioni di tasti quando si utilizza il terminale per una descrizione più dettagliata.

La funzione xterm di base è supportata da Emacs 24.4. Tuttavia i fondamentali (in particolare Tab, Return, Escape, Backspace) ancora inviare i caratteri di controllo tradizionali, perché è quello che si aspettano applicazioni. C'è una modalità in cui Ctrl+ letterinvia una sequenza di escape invece del carattere di controllo. Quindi, per distinguere i tasti funzione dalle Ctrlcombinazioni di Emacs 24.4, modifica il suo supporto per modifyOtherKeysutilizzare questa modalità impostando la risorsa su 2 anziché 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))

Quando dici "Emacs 24.24" intendi "Emacs 24.4"?
tarsius,

1
@tarsius Un commento nel codice che è stato copiato dal mio file init dice "24.4", quindi penso che sia corretto, e "24.24" nel testo che ho scritto per questa risposta era un refuso per "24.4".
Gilles 'SO- smetti di essere malvagio' l'
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.