วิธีการแทนที่การผูกโหมดหลัก


38

บางครั้งการโยงคีย์โกลบอลของฉันถูกเขียนทับโดยโหมดหลัก ตัวอย่างง่ายๆคือการตั้งค่าต่อไปนี้ในไฟล์ init ของฉัน

(global-set-key (kbd "C-j") 'newline-and-indent)

แต่น่ารำคาญที่การเชื่อมโยงปุ่มกดนี้ถูกซ่อนไว้ในโหมดหลัก "Lisp Interaction" ซึ่งเป็นโหมดเริ่มต้นของบัฟเฟอร์รอยขีดข่วน

เมื่อฉันพบว่าตัวเองอยู่ในสถานการณ์ที่เป็นโหมดหลัก (หรือโหมดรอง) กำลังซ่อนปุ่มลัดส่วนกลางของฉันฉันจะเอามันกลับมาได้อย่างไร

หมายเหตุ: คำถามของฉันไม่ใช่"ฉันจะผูกC-jไว้newline-and-indentในโหมด" Lisp Interaction "ได้อย่างไร" ฉันสนใจคำตอบทั่วไปเพิ่มเติมเกี่ยวกับวิธีจัดการกับ keymaps ที่ขัดแย้งหรือ keybindings ผู้ใช้ที่ถูกซ่อนโดยโหมดหลัก / รองบางอย่าง


คำตอบ:


39

มีวิธี "ทางลัด" ด้วยเช่นกันหากคุณไม่ต้องการกำหนดโหมดย่อยของคุณเอง (ที่ฉันพูดถึงในคำตอบแรก)

คุณสามารถติดตั้งuse-packageแพคเกจใช้ได้จาก Melpa และทำให้การใช้bind-key*หรือbind-keys*แมโครที่เป็นส่วนหนึ่งของแพคเกจที่มาพร้อมกับbind-keyuse-package

จากเอกสารของbind-key.el:

;; If you want the keybinding to override all minor modes that may also bind
;; the same key, use the `bind-key*' form:
;;
;;   (bind-key* "<C-return>" 'other-window)

;; To bind multiple keys in a `bind-key*' way (to be sure that your bindings
;; will not be overridden by other modes), you may use `bind-keys*' macro:
;;
;;    (bind-keys*
;;     ("C-o" . other-window)
;;     ("C-M-n" . forward-page)
;;     ("C-M-p" . backward-page))

ในกรณีที่ใครอยากรู้โปรดทราบว่านี่เป็นเพียงการใช้โหมดรองหลังฉาก มันใช้วิธีการที่แตกต่างกันในการขัดแย้งกับโหมดย่อยอื่น ๆ โดยใช้emulation-mode-map-alistsเพื่อบังคับใช้ลำดับความสำคัญ)
phils

ฉันทำเครื่องหมายคำตอบนี้เป็นคำตอบเนื่องจากความเรียบง่าย โดยพื้นฐานแล้วมันจะทำสิ่งเดียวกันกับคำตอบนี้แต่ก็เป็นการทำงานที่สะดวกที่สุดสำหรับคุณที่อยู่เบื้องหลัง
nispio

@nispio คุณถูกต้อง จากประสบการณ์ของฉันความแตกต่างเพียงอย่างเดียวคือวิธีการที่ใช้เพื่อทำให้การเชื่อมโยงโหมดรองแทนที่โหมดอื่นทั่วโลก แต่ข้อดีของวิธีการอื่น ๆ (ของการมีโหมดรองของคุณ) คือคุณสามารถปิดชั่วขณะเพื่อลองใช้การผูก emacs ดั้งเดิมหากคุณต้องการ (ฉันต้องทำสองสามครั้ง)
Kaushal Modi

1
เพิ่ม(bind-key* "C-M-&" 'override-global-mode)ไปยัง init ของคุณและโดยปกติคุณสามารถทำให้การเชื่อมโยงออกไปอย่างรวดเร็วหากคุณต้องการ เนื่องจากoverride-global-modeไม่ใช่โหมดย่อย "ทั่วโลก" คุณจะยังคงต้องปิดการใช้งานในรูปแบบต่อบัฟเฟอร์ ดังนั้นหากคุณพบว่าตัวเองปิดใช้งานคีย์แทนที่ทั่วโลกบ่อยครั้งโซลูชันนี้จึงไม่สะดวก
nispio

25

คุณสามารถกำหนดโหมดรองของคุณเองและแผนที่ที่สำคัญและมีที่แทนที่โหมดอื่น ๆ ทั้งหมด (เล็กน้อย + ที่สำคัญ) นั่นเป็นเหตุผลที่ฉันเลือกที่จะเขียนโหมดรองของตัวเอง

ขั้นตอนในการผูกการคีย์ของคุณจะแทนที่การโยงทั้งหมด:

  • การกำหนดโหมดย่อยและแผนที่หลักของคุณเองดังแสดงด้านล่าง
  • เปิดใช้งานโหมดย่อยของคุณทั่วโลก
  • (define-key my-mode-map (kbd "C-j") #'newline-and-indent)

ในทำนองเดียวกันการเชื่อมโยงคีย์อื่น ๆ ของคุณที่ตั้งค่าในโหมดรองของคุณจะแทนที่สิ่งเหล่านั้นในโหมดอื่น ๆ

ฉันขอแนะนำให้อ่านโพสต์บล็อกโดย Christopher Wellons เกี่ยวกับวิธีการเขียนโหมดรอง บล็อกนั้นบวกกับความยุ่งยากในการตั้งค่าการเชื่อมโยงคีย์nilหลาย ๆ แบบในโหมดหลักและรองหลาย ๆ โหมดเป็นแรงบันดาลใจให้ฉันเขียนโหมดรองของตัวเอง

ส่วนที่ดีที่สุดของการใช้วิธีนี้คือเมื่อคุณต้องการตรวจสอบว่าการเชื่อมโยงคีย์ทำอะไรในการกำหนดค่าเริ่มต้นของ emacs คุณเพียงปิดโหมดรอง จากนั้นคุณเปิดใช้งานอีกครั้งและคุณจะได้รับการเชื่อมโยงคีย์แบบกำหนดเองของคุณ

;; Main use is to have my key bindings have the highest priority
;; https://github.com/kaushalmodi/.emacs.d/blob/master/elisp/modi-mode.el

(defvar my-mode-map (make-sparse-keymap)
  "Keymap for `my-mode'.")

;;;###autoload
(define-minor-mode my-mode
  "A minor mode so that my key settings override annoying major modes."
  ;; If init-value is not set to t, this mode does not get enabled in
  ;; `fundamental-mode' buffers even after doing \"(global-my-mode 1)\".
  ;; More info: http://emacs.stackexchange.com/q/16693/115
  :init-value t
  :lighter " my-mode"
  :keymap my-mode-map)

;;;###autoload
(define-globalized-minor-mode global-my-mode my-mode my-mode)

;; https://github.com/jwiegley/use-package/blob/master/bind-key.el
;; The keymaps in `emulation-mode-map-alists' take precedence over
;; `minor-mode-map-alist'
(add-to-list 'emulation-mode-map-alists `((my-mode . ,my-mode-map)))

;; Turn off the minor mode in the minibuffer
(defun turn-off-my-mode ()
  "Turn off my-mode."
  (my-mode -1))
(add-hook 'minibuffer-setup-hook #'turn-off-my-mode)

(provide 'my-mode)

;; Minor mode tutorial: http://nullprogram.com/blog/2013/02/06/

5

หากต้องการให้การรวมโกลบอลแทนที่การโยงโหมดหลักให้ตั้งค่าการรวมnilในโหมดหลัก:

(define-key my-major-mode-map (kbd "C-j") nil)

เป็นไปไม่ได้ที่จะมีการเชื่อมโยงทั่วโลกมีความสำคัญกว่าทุกโหมดโดยทั่วไป (ไม่เช่นนั้นจะไม่มีประเด็นในการมีโหมดหลัก) แต่คุณสามารถแฮ็คมันโดยการสร้างโหมดรองของคุณเองด้วยการผูกที่สำคัญที่สุด อย่างน้อยคุณก็จะมีความสำคัญเหนือกว่าโหมดส่วนใหญ่ (แม้ว่าจะไม่จำเป็นทั้งหมด)


จะใช้งานได้กับโหมดหลักใด ๆ หรือไม่ กล่าวอีกนัยหนึ่งถ้าฉันติดตั้งโหมดหลักเรียกว่า "foo-mode" ฉันสามารถใส่(define-key foo-mode (kbd "C-j") nil)ไฟล์. emacs ของฉันและคาดหวังว่ามันจะทำงานได้หรือไม่
nispio

ที่จริงคุณจะต้องการให้มันเป็นfoo-mode-map(ตัวอย่างของฉันในคำตอบไม่ดี) แต่ใช่ว่าจะปิดใช้งานการเชื่อมปุ่มกดในโหมดหลักดังนั้นการใช้ปุ่มลัดทั่วโลกจะถูกนำมาใช้แทน
shosti

มันเป็นสากลที่เป็นธรรมหรือไม่ที่มีการfoo-modeเรียกใช้ keymap foo-mode-map
nispio

@nispio ใช่มันเป็นความจริงสำหรับโหมดส่วนใหญ่ (แม้ว่าจะมีคนร้ายอยู่สองสามคน)
shosti

0

คุณสามารถใช้มาโครเหล่านี้ได้:

(defmacro expose-global-keybinding (binding map)
  `(define-key ,map ,binding (lookup-key (current-global-map) ,binding)))

(defmacro expose-bindings (map bindings)
  `(dolist (bnd ,bindings)
     (expose-global-keybinding (kbd bnd) ,map)))

แก้ไข :

ตรวจสอบการร้อง:

หาก keymap X กำลังแทนที่ Y ส่วนกลางของคุณคุณเขียน:

(expose-bindings X '("Y"))

จากนั้นการแทนที่จะเป็น 'เลิกทำ'


แมโครของคุณคุณได้รับประโยชน์จากการใช้ backquote: `(define-key, map, binding (lookup-key (current-global-map), binding))
Sigma

คุณสามารถแสดงความคิดเห็นเกี่ยวกับสิ่งที่แมโครทำและวิธีการใช้งานได้หรือไม่ มันไม่ชัดเจนสำหรับฉันจากรหัส
nispio

แมโครแรกเพียงแค่รูปลักษณ์ขึ้นที่สำคัญในแผนที่โลกและกำหนดผลไปจึงเผยให้เห็นแผนที่โลกที่มีผลผูกพันผ่านother map other mapอันที่สองช่วยให้คุณสามารถใช้อดีตสำหรับรายการของการผูก
Renan Ranelli

ขออภัยถ้าฉันหนาแน่น แต่ฉันยังไม่เข้าใจการใช้งานทั้งหมด ฉันจำเป็นต้องกำหนด keymap หลักพิเศษของตัวเองหรือไม่? มันจำเป็นต้องเป็นของโหมดรองหรือไม่? ฉันต้องดำเนินการexpose-bindingsก่อนแล้วจึงผูกคีย์เหล่านั้นกับคำสั่งที่ฉันต้องการหรือไม่ บางทีคุณอาจแสดงตัวอย่างของสิ่งที่ฉันอาจใส่ในไฟล์ init ของฉันเพื่อใช้งานได้
nispio

2
โปรดทราบว่าชื่อแมโครเหล่านี้เป็นชื่อที่ใช้ผิด พวกเขาไม่ "เปิดเผย" การเชื่อมโยงทั่วโลก แต่จะเป็นการทำซ้ำการเชื่อมโยงส่วนกลาง หากการผูกพันทั่วโลกที่แท้จริงมีการเปลี่ยนแปลงสำเนาที่ซ้ำกันเหล่านี้จะไม่
phils
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.