Як зв'язати Ci на відміну від TAB?


16

Я хочу зробити Control-iвиконання indent-region(в основному, оскільки Xcode вже створив цю м'язову пам'ять).

Я усвідомлюю це Control-iі tabне відрізняються в сенсі Ассії, але вони є в сенсі ключового коду.

Я спробував очевидне:

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

безрезультатно - натискання Control-iвсе одно просто робить все, що tabробиться в поточному контексті. Чи можу я щось зробити, щоб допомогти Emacs по-різному ставитися до кнопки вкладки Control-i?

Оновлення: я думаю, що еквівалентний результат буде досягнутий, коли можна буде перезавантажувати, що робить tab/ Control-iнатискання, коли вибрано регіон


1
Це з кадру графічного інтерфейсу або з термінального кадру? Я не знаю, чи можете ви її замінити на термінал.
занотувано

Хороший Q, кадр GUI зазвичай, але я віддалено працюю на серверах і інколи використовую emacs в терміналі (звичайно, з git-спільним emacs.d :)
Марк Оффлік,

Відповіді:


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, який був запущений з віконною системою (що я роблю іноді). Якщо я не бачу жодної затримки, я просто використовувати функцію заміни вкладок у всіх випадках.
Марк Оффлік

1
Я просто хочу додати, що <C-i>і [C-i]міг бути довільним ідентифікатором, як <foobar>і [foobar], і він би все ще працював; просто не називайте його tabабоbackspace
xdavidliu

Я додав відредагований фрагмент коду до вашої відповіді у .emacsфайл, але обидва TABі C-iперезаписаний :-( @nispio
alper

@alper, швидше за все це означає, що (window-system)повернувся nilв момент .emacsзавантаження. Це може бути тому, що ви використовуєте не графічний екземпляр Emacs або тому, що ви використовуєте демон Emacs.
nispio

13

Кадри графічного інтерфейсу

У кадрах графічного інтерфейсу (будь то X11, Windows, OSX,…) Emacs читає Tabключ як tabфункціональну клавішу. Однак, оскільки Tabключ на терміналах традиційно надсилає символ ^I( Control + 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+[

Якщо ви хочете відокремитись Tabвід Ctrl+ 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)". Це не дуже, але це неминуче: симпатичний друк символу 9 як TABвбудований у вихідний код Emacs.

Термінальні рами

У термінальних кадрах проблема складніше і часто неможлива. Термінали не передають ключі, вони передають символи (точніше, насправді, вони передають байти). TabКлюч передається як символ табуляції - який Control + I, такий же , як то , що комбінація клавіш Ctrl+ Iгенерує. Функціональні клавіші, що не мають відповідного символу (наприклад, клавіші курсору), передаються у вигляді послідовностей відведення, тобто послідовності символів, що починаються з ESC= Control + [(саме тому Emacs визначає escapeяк ключ префіксу - ESCповинен бути префіксом). Див. Як працюють введення з клавіатури та вихід тексту? для отримання додаткової інформації.

Є кілька терміналів, які можна налаштувати для надсилання різних послідовностей клавіш для функціональних клавіш, але їх не багато. Як libtermkey / libtickit LeoNerd, так і xterm Томаса Дікі (починаючи з версії 216) це підтримують. У Xterm функція є необов'язковою та активується через modifyOtherKeysресурс. Однак я не знаю жодного популярного емулятора терміналу, окрім xterm, який підтримує це, зокрема багатьох емуляторів, побудованих на libvte . Деякі емулятори терміналів дозволяють вам це робити вручну за допомогою визначеної користувачем кореспонденції з клавіатур для виходу з послідовностей.

Цей механізм дозволяє виділити багато комбінацій клавіш, а не лише вкладку / Ci, return / Cm та escape / C- [. Детальніший опис див. Проблеми з прив'язкою клавіатури при використанні терміналу .

Основна функція xterm підтримується з Emacs 24.4. Однак основи (зокрема Tab, Return, Escape, Backspace) до сих пір відправити традиційні керуючі символи, тому що це те , що очікують додаток. Існує режим, коли Ctrl+ letterнадсилає послідовність евакуації замість символу управління. Отже, щоб відрізнити функціональні клавіші від Ctrlкомбінацій на Emacs 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"?
Тарсій

1
@tarsius У коментарі до коду, скопійованого з мого файлу init, написано "24.4", тому я вважаю, що це правильно, і "24.24" у тексті, який я написав для цієї відповіді, був помилковим для "24.4".
Жиль "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.