Comment lier Ci comme différent de TAB?

16

Je veux faire Control-iperformer indent-region(essentiellement depuis que Xcode a déjà construit cette mémoire musculaire).

Je me rends compte de cela Control-iet tabsont indiscernables dans le sens Ascii, mais ils sont dans le sens du code clé.

J'ai essayé l'évidence:

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

en vain - appuyer sur fait Control-itoujours ce que fait la tabtouche dans le contexte actuel. Puis-je faire quelque chose pour aider Emacs à traiter le bouton de tabulation différemment Control-i?

Mise à jour: Je suppose qu'un résultat équivalent serait atteint en étant capable de remapper ce que fait tab/ Control-ipress lorsqu'une région est sélectionnée.

Mark Aufflick
la source
1
Est-ce à partir d'une trame GUI ou d'une trame de terminal? Je ne sais pas si vous pouvez le remplacer pour un terminal.
dgtized
Bon Q, cadre GUI généralement, mais je me connecte à distance aux serveurs et j'utilise parfois emacs dans un terminal (avec un emacs.d partagé par git bien sûr :)
Mark Aufflick

Réponses:

15

Je ne pense pas que cela puisse être réalisé à partir d'un terminal, mais en mode GUI, vous pouvez essayer ceci:

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

Je fais la même chose avec C-mpour que ça se distingue deRET

ÉDITER:

Les éléments suivants devraient fonctionner, que vous soyez en mode 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))

Ce n'est pas joli, mais ça semble faire l'affaire. Je me réjouis de tout raffinement ou modification de ce code si nécessaire.

nispio
la source
1
Marche parfaitement! ++ achèterait à nouveau un stackexchange emacs :)
Mark Aufflick
Le seul problème mineur auquel je viens de penser est que nous pouvons maintenant faire apparaître un terminal emacsclient contre un Emacs qui a été démarré avec un système de fenêtres (ce que je fais parfois). Si je ne vois aucun retard, je vais simplement utiliser la fonction de remplacement de tabulation dans tous les cas.
Mark Aufflick
1
Je veux juste ajouter que le <C-i>et [C-i]aurait pu être un identifiant arbitraire, comme <foobar>et [foobar], et cela fonctionnerait toujours; il suffit de ne pas l'appeler taboubackspace
xdavidliu
J'ai ajouté un morceau de code modifié sur votre réponse dans le .emacsfichier mais les deux TABet C-iest remappé :-( @nispio
alper
@alper, Cela signifie très probablement qu'il (window-system)est revenu nilau moment où votre a .emacsété chargé. Cela peut être dû au fait que vous exécutez une instance non graphique d'Emacs ou parce que vous exécutez un démon Emacs.
nispio
13

Cadres GUI

Dans les cadres GUI (que ce soit X11, Windows, OSX,…), Emacs lit la Tabclé comme touche de tabfonction. Cependant, étant donné que la Tabtouche sur les terminaux envoie traditionnellement le caractère ^I( Control + I), Emacs traduit la tabtouche de fonction en caractère Control + I (caractère 9), qui s'affiche comme TAB. Cette traduction se fait via function-key-map.

Une traduction similaire se produit avec certaines autres touches de fonction. ( Backspaceet Deletesont un cas épineux dont je ne parlerai pas en détail ici.)

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+[

Si vous souhaitez séparer complètement Tabde Ctrl+ I, supprimez la liaison de function-key-map:

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

Cependant, cela n'est pas très utile, car les entrées dans function-key-mapsont remplacées par des liaisons dans des images clés spécifiques au mode ou dans la carte globale. Donc, si vous souhaitez définir une liaison différente pour tab, faites-le (dans Elisp, pas de manière interactive, car l'invite de lecture de clé applique la function-key-maptraduction afin que vous finissiez par la relier TABet non tab):

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

Tous les modes standard qui modifient l'action de la Tabtouche le font en modifiant la TABtouche, qui est un surnom pour le C-icaractère généré par la combinaison de touches Ctrl+ I. Si vous souhaitez que les liaisons standard s'appliquent à tabplutôt que C-i, laissez function-key-mapet modifiez les images clés en mode, et redirigez plutôt Ctrl+ Ivers une autre clé.

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

Emacs rapportera désormais Ctrl+ Icomme « <control-i>(traduit de TAB)». Ce n'est pas joli, mais c'est inévitable: la jolie impression du caractère 9 TABest intégrée au code source d'Emacs.

Cadres de bornes

Dans les châssis terminaux, le problème est plus difficile et souvent impossible. Les terminaux ne transmettent pas de clés, ils transmettent des caractères (plus précisément, en fait, ils transmettent des octets). La Tabclé est transmise sous forme de caractère de tabulation - qui est Contrôle + I, identique à ce que génère la combinaison de touches Ctrl+ I. Les touches de fonction qui n'ont pas de caractère correspondant (telles que les touches de curseur) sont transmises en tant que séquences d'échappement, c'est-à-dire que les séquences de caractères commençant par ESC= Control + [(c'est pourquoi Emacs définit escapecomme une touche de préfixe - ESCdoit être un préfixe). Voir Comment fonctionnent la saisie au clavier et la sortie du texte? pour plus de fond.

Il y a quelques terminaux qui peuvent être configurés pour envoyer différentes séquences de touches pour les touches de fonction, mais pas beaucoup. Les deux libtermkey / libtickit de LeoNerd et le xterm de Thomas Dickey (depuis la version 216) l' appui. Dans Xterm, la fonctionnalité est facultative et activée via la modifyOtherKeysressource. Cependant, je ne connais aucun émulateur de terminal populaire autre que xterm qui le supporte, en particulier les nombreux émulateurs construits sur libvte . Certains émulateurs de terminal vous permettent de le faire manuellement via une correspondance définie par l'utilisateur à partir des clés pour échapper aux séquences.

Ce mécanisme permet de distinguer de nombreuses combinaisons de touches, pas seulement tab / Ci, return / Cm et escape / C- [. Voir Problèmes avec les raccourcis clavier lors de l'utilisation du terminal pour une description plus détaillée.

La fonction de base xterm est prise en charge depuis Emacs 24.4. Toutefois , les fondamentaux (en particulier Tab, Return, Escape, Backspace) envoient toujours les caractères de contrôle traditionnels, parce que ce applications attendent. Il existe un mode où Ctrl+ letterenvoie une séquence d'échappement au lieu du caractère de contrôle. Donc, pour distinguer les touches de fonction des Ctrlcombinaisons sur Emacs 24.4, modifiez sa prise en charge pour modifyOtherKeysutiliser ce mode en définissant la ressource sur 2 au lieu 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- arrête d'être méchant'
la source
Lorsque vous dites "Emacs 24.24", voulez-vous dire "Emacs 24.4"?
tarsius
1
@tarsius Un commentaire dans le code copié de mon fichier init dit "24.4", donc je pense que c'est correct, et "24.24" dans le texte que j'ai écrit pour cette réponse était une faute de frappe pour "24.4".
Gilles 'SO- arrête d'être méchant'