วิธีผูก Ci ต่างจาก TAB อย่างไร


16

ฉันต้องการControl-iแสดงindent-region(โดยพื้นฐานแล้วตั้งแต่ Xcode ได้สร้างหน่วยความจำกล้ามเนื้อนั้นแล้ว)

ฉันรู้ว่าControl-iและtabแยกไม่ออกในความรู้สึก Ascii แต่พวกเขาอยู่ในความรู้สึก keycode

ฉันพยายามชัดเจน:

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

ไม่มีประโยชน์ - การกดControl-iยังคงทำสิ่งที่tabสำคัญทำในบริบทปัจจุบัน มีสิ่งใดบ้างที่ฉันสามารถทำได้เพื่อช่วยให้ Emacs ปฏิบัติต่อปุ่มแท็บต่างไปจากเดิมControl-iหรือไม่

อัปเดต:ฉันเดาว่าผลลัพธ์ที่เทียบเท่าจะเกิดขึ้นได้โดยสามารถแมปสิ่งที่tab/ Control-iกดทำเมื่อเลือกภูมิภาค


1
สิ่งนี้มาจากเฟรม GUI หรือเทอร์มินัลเฟรมหรือไม่? ฉันไม่รู้ว่าคุณสามารถลบล้างมันสำหรับเทอร์มินัลได้หรือไม่
dgtized

ดี Q, กรอบ GUI ปกติ แต่ฉันทำระยะไกลในเซิร์ฟเวอร์และใช้ emacs ในเทอร์มินัล (แน่นอนด้วย emacs.d ที่ใช้ร่วมกัน git :)
Mark Aufflick

คำตอบ:


15

ฉันไม่คิดว่าจะสามารถทำได้จาก terminal แต่ในโหมด 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 อีกครั้ง :)
Mark Aufflick

ปัญหาเล็กน้อยเท่านั้นที่ฉันคิดคือตอนนี้เราสามารถเพิ่ม terminal emacsclient กับ Emacs ที่เริ่มต้นด้วยระบบหน้าต่าง (ซึ่งบางครั้งฉันทำ) หากฉันไม่เห็นความล่าช้าฉันจะใช้ func-ทดแทนแท็บในทุกกรณี
Mark Aufflick

1
ผมแค่อยากจะเพิ่มที่<C-i>และ[C-i]จะได้รับการระบุโดยพลการเช่น<foobar>และ[foobar]และมันจะยังคงทำงาน เพียงแค่ไม่ได้เรียกว่าtabหรือbackspace
xdavidliu

ฉันได้เพิ่มรหัสชิ้นแก้ไขในคำตอบของคุณลงใน.emacsไฟล์ แต่ทั้งสองTABและC-iมีการแมปใหม่ :-( @nispio
alper

@alper เป็นไปได้มากว่านี่จะหมายถึงการ(window-system)ส่งคืนnilเมื่อคุณ.emacsโหลด อาจเป็นเพราะคุณใช้งานอินสแตนซ์ที่ไม่ใช่กราฟิกของ Emacs หรือเพราะคุณกำลังใช้งาน Emacs daemon
nispio

13

เฟรม GUI

ในเฟรม GUI (ไม่ว่าจะเป็น X11, Windows, OSX, …), Emacs จะอ่านค่าTabเป็นtabปุ่มฟังก์ชั่น แต่เพราะTabที่สำคัญเกี่ยวกับขั้วประเพณีส่ง^I( ควบคุม + I) ตัวอักษร Emacs แปลtabปุ่มฟังก์ชั่เข้าไปใน Control + ฉันตัวอักษร (ตัวอักษร 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สร้าง ปุ่มฟังก์ชั่นที่ไม่มีตัวอักษรที่เกี่ยวข้อง (เช่นเคอร์เซอร์เคอร์เซอร์) จะถูกส่งเป็น escape sequences นั่นคือลำดับของตัวอักษรที่ขึ้นต้นด้วยESC= Control + [(ซึ่งเป็นสาเหตุที่ Emacs กำหนดescapeเป็นคีย์คำนำหน้า - ESCต้องเป็นส่วนนำหน้า) ดูที่คีย์บอร์ดและเอาต์พุตข้อความทำงานอย่างไร สำหรับพื้นหลังเพิ่มเติม

มีเทอร์มินัลไม่กี่แห่งที่สามารถกำหนดค่าให้ส่งลำดับคีย์ที่แตกต่างกันสำหรับปุ่มฟังก์ชัน แต่ไม่มาก ทั้งLeoNerd's libtermkey / libtickitและxterm ของ Thomas Dickey (ตั้งแต่รุ่น 216) สนับสนุนสิ่งนี้ ใน Xterm คุณลักษณะนี้เป็นทางเลือกและเปิดใช้งานผ่านmodifyOtherKeysทรัพยากร แต่ผมไม่ทราบว่าของจำลอง terminal ใด ๆ ที่นิยมอื่น ๆ กว่า xterm ที่สนับสนุนการนี้โดยเฉพาะอย่างยิ่งในการเลียนแบบจำนวนมากที่สร้างขึ้นบนlibvte เทอร์มินัลอีมูเลเตอร์บางตัวช่วยให้คุณทำสิ่งนี้ได้ด้วยตนเองผ่านการโต้ตอบที่ผู้ใช้กำหนดเองจาก keychords เพื่อหลีกเลี่ยงลำดับ

กลไกนี้ช่วยให้สามารถแยกแยะคีย์ผสมต่าง ๆ ได้ไม่เพียงแค่ tab / Ci, return / Cm และ escape / C- [ ดูที่ปัญหาเกี่ยวกับการผูกกุญแจเมื่อใช้เทอร์มินัลสำหรับคำอธิบายโดยละเอียดเพิ่มเติม

รองรับคุณสมบัติ xterm พื้นฐานตั้งแต่ Emacs 24.4 อย่างไรก็ตามปัจจัยพื้นฐาน (โดยเฉพาะอย่างยิ่งTab, Return, Escape, Backspace) ยังคงส่งตัวควบคุมแบบดั้งเดิมเพราะที่สิ่งที่ใช้งานคาดหวัง มีโหมดที่Ctrl+ letterส่งลำดับ escape แทนอักขระควบคุม ดังนั้นเพื่อแยกความแตกต่างของปุ่มฟังก์ชั่นจาก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" หรือไม่
Tarsius

1
@tarsius ความคิดเห็นในรหัสที่คัดลอกมาจากไฟล์ init ของฉันบอกว่า“ 24.4” ดังนั้นฉันคิดว่าถูกต้องและ“ 24.24” ในข้อความที่ฉันเขียนสำหรับคำตอบนี้เป็นคำที่พิมพ์ผิดสำหรับ“ 24.4”
Gilles 'SO- หยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.