如何将Ci与TAB绑定在一起?


16

我想Control-i表演indent-region(基本上因为Xcode已经建立了该肌肉记忆)。

我意识到这一点Control-itab在Ascii的意义上是无法区分的,但是在键码意义上却是不可区分的。

我已经尝试了明显的方法:

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

无济于事- 在当前上下文中,按键Control-i仍会执行任何tab操作。我可以做些什么来帮助Emacs区别对待tab按钮Control-i吗?

更新:我猜想通过重新映射选定区域时tab/ Control-i按下的内容,可以实现相同的结果。


1
这是来自GUI框架还是终端框架?我不知道您是否可以在终端上覆盖它。
dgtized

Q,GUI框架通常很好,但是我确实远程进入服务器并有时在终端中使用emacs(当然还有git-shared emacs.d :)
Mark Aufflick

Answers:


15

我不认为这可以从终端上实现,但是在GUI模式下,您可以尝试以下操作:

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

我做同样的事情,C-m以便可以与RET

编辑:

无论您是在GUI还是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))

它虽然不漂亮,但似乎可以完成工作。我欢迎根据需要对此代码进行任何改进或编辑。


1
完美的作品!++会再次购买emacs
stackexchange

我仅想到的一个小问题是,现在我们可以将终端emacsclient与以窗口系统启动的Emacs相对(有时会这样做)。如果没有任何延迟,则在所有情况下都将使用制表符替换功能。
Mark Aufflick 2014年

1
我只想补充一点,<C-i>and和[C-i]可以是任意标识符,例如<foobar>and [foobar],它仍然可以工作;只是不要叫它tabbackspace
xdavidliu

我已经加入你的答案编辑的一段代码到.emacs文件中,但两者TABC-i重新映射:-( @nispio
Alper的

@alper,这很可能意味着它在您加载时(window-system)返回。这可能是因为您正在运行Emacs的非图形实例,或者是因为您正在运行Emacs守护程序。nil.emacs
nispio

13

GUI框架

在GUI框架(是否为X11,Windows,OSX等)中,Emacs会将Tab键读取为tab功能键。但是,由于Tab传统上终端上的按键会发送^IControl + I)字符,因此Emacs 会将tab功能键转换为Control + I字符(字符9),显示为TAB。此翻译是通过进行的function-key-map

其他一些功能键也会发生类似的转换。(Backspace而且Delete是一个棘手的案例,在这里我不会详细讨论。)

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

如果您想完全TabCtrl+ 分开,请从中I删除绑定function-key-map

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

但是,这不是很有用,因为其中的条目function-key-map被特定于模式的键映射或全局映射中的绑定覆盖。因此,如果您想为定义一个不同的绑定tab,就可以做到这一点(在Elisp中,不是交互式的,因为按键阅读提示会应用function-key-map翻译,所以您最终会重新绑定TAB而不是tab):

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

所有修改Tab按键动作的标准模式都通过修改TAB按键来完成,按键是C-i按键组合Ctrl+ 生成的字符的昵称I。如果您希望将标准绑定应用于tab而不是C-i,则不要使用键function-key-map模式和模式,而是将Ctrl+ 重定向I到其他键。

(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将报告Ctrl+ I为“ <control-i>(翻译自TAB)”。这不是很漂亮,但这是不可避免的:TABEmacs源代码中内置的字符9的漂亮字体。

端子架

在终端机架中,问题更加棘手,通常是不可能的。终端不传输密钥,而是传输字符(更确切地说,实际上,它们传输字节)。的Tab是控制+ I,相同什么组合键-键作为制表符发送Ctrl+ I生成。没有对应字符的功能键(例如光标键)作为转义序列传输,即以ESC= Control + [ 开头的字符序列(这就是Emacs定义escape为前缀键的原因- ESC必须为前缀)。请参阅键盘输入和文本输出如何工作?以获得更多背景。

有几个可以配置为发送功能键的不同按键序列的终端,但不是很多。无论LeoNerd的libtermkey / libtickit托马斯Dickey的xterm(因为216的版本)支持此功能。在Xterm中,该功能是可选的,可以通过modifyOtherKeys资源激活。但是,除了支持xterm的xterm之外,我不了解任何流行的终端仿真器,尤其是许多基于libvte构建的仿真器。一些终端仿真器允许您通过用户定义的键和弦到转义序列的对应关系来手动执行此操作。

这种机制允许区分许多键组合,而不仅仅是制表符/ Ci,返回键/ Cm和转义键/ C- [。有关更多详细说明,请参见使用终端时的键绑定问题

从Emacs 24.4开始支持基本的xterm功能。然而基本面(尤其是TabReturnEscapeBackspace)还是发送了传统的控制字符,因为这是应用程序的期望。有一种模式,其中Ctrl+ letter发送一个转义序列而不是控制字符。因此,要将功能键与CtrlEmacs 24.4上的组合区分开来,可以modifyOtherKeys通过将资源设置为2而不是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))

当您说“ Emacs 24.24”时,您是说“ Emacs 24.4”吗?
tarsius

1
@tarsius从我的init文件中复制的代码中的注释为“ 24.4”,所以我认为这是正确的,我为此答案编写的文本中的“ 24.24”是“ 24.4”的错字。
吉尔(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.