ฉันจะทราบได้อย่างไรว่าคีย์คีย์ใดถูกผูกไว้?


63

ฉันรีบาวน์ปุ่ม 'd' gnus-article-modeแต่พฤติกรรมเก่าของมันยังคงทำงานอยู่เมื่อมีสิ่งที่แนบมา ฉันสามารถเห็นได้ว่าการปฏิเสธไม่ได้มีผลโดยทำC-h k dแต่ก็ไม่ได้บอกฉันว่าคีย์แมปมีผลอย่างไร ณ จุดนั้นเพื่อที่ฉันจะได้สามารถปฏิเสธได้

มีวิธีที่จะค้นหามันได้หรือไม่?

นี่คือตัวอย่างที่ชัดเจน: ฉันใช้ความชั่วร้ายและฉันต้องการให้บทความอยู่ในโหมดเคลื่อนไหว สำหรับรูปแบบแป้นพิมพ์ของฉันฉันได้กำหนดค่า 'd' เป็นคีย์เพื่อขึ้น

(evil-mode 1)
(add-to-list 'evil-motion-state-modes 'gnus-article-mode)
(setq evil-emacs-state-modes (remove 'gnus-article-mode evil-emacs-state-modes))
(define-key evil-motion-state-map "d" 'evil-previous-line)

เพื่อให้แน่ใจว่าคำนึงถึงกุญแจความชั่วร้ายฉันได้ยกเลิกการตั้งค่า gnus ในแผนที่ท้องถิ่น:

(defun as/alter-article-evil-map ()
  (local-unset-key "d"))
(add-hook 'gnus-article-mode-hook 'as/alter-article-evil-map)

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

การแก้ไขฉันใช้keymaps-at-pointด้านล่างเพื่อค้นหา keymap ที่ใช้มาจากคุณสมบัติข้อความ จากนั้นฉันก็ดูโค้ดของฟังก์ชั่นที่ถูกผูกไว้เพื่อค้นหาชื่อของคีย์แมgnus-mime-button-mapป รหัสต่อไปนี้ทำในสิ่งที่ฉันต้องการ:

(defun as/alter-article-evil-map ()
  (define-key gnus-mime-button-map "d" nil))
(add-hook 'gnus-article-mode-hook 'as/alter-article-evil-map)

3
การใช้งานนี้เสียงกระเพื่อมหลอกรหัสและคำอธิบายของคุณเป็นคู่มือระดับสูงวิธี Emacs เงยหน้าขึ้นคีย์ : คู่มือ Elisp Searching Keymapsโหนด ดูเพิ่มเติมโหนดและFunctions for Key Lookup Active Keymaps
Drew

มีข้อผิดพลาดที่ค่อนข้างใหญ่พร้อมคำตอบเริ่มต้นของฉันในฟังก์ชั่นที่สอง ฉันเพิ่งแก้ไขมันในตอนนี้ดังนั้นมันควรจะสามารถหา keybind ของคุณได้ ลองอีกครั้งได้ไหม
Malabarba

คำตอบ:


61

Emacs 25

ดังที่ @YoungFrog กล่าวไว้ในความคิดเห็นซึ่งเริ่มต้นด้วย Emacs 25.1C-h kวิธีการอธิบายการโยงคีย์แบบเก่าจะบอกคุณว่ามีการค้นพบคีย์แมปใด

ก่อน Emacs 25

มีรหัสบางส่วน ที่นี่ แต่ไม่สมบูรณ์เนื่องจากไม่ครอบคลุมทุกอย่าง ด้านล่างนี้เป็นรุ่นที่ปรับปรุงแล้ว

คีย์สามารถถูกผูกไว้ได้ 9 วิธี! ขอขอบคุณ @Drew สำหรับลิงค์นี้ (เพิ่มเติมโดยสิ่งนี้ ) ด้วยรายการทั้งหมด ตามลำดับความสำคัญพวกเขาคือ:

  1. overriding-terminal-local-mapชุดขั้วที่เฉพาะเจาะจงของกุญแจ สิ่งนี้ถูกกำหนดโดยset-transient-mapฟังก์ชั่น
  2. overriding-local-mapบัฟเฟอร์ท้องถิ่นแผนที่แทนที่ หากตั้งค่ารายการนี้รายการที่ 3–8 จะถูกข้ามไป (อาจเป็นเพราะคุณไม่เห็นหลายรายการ)
  3. ที่จุดผ่านkeymapข้อความ - propety (ซึ่งสามารถไปกับข้อความจริงหรือบนภาพซ้อนทับ)
  4. ตัวแปรที่จำลองชุดย่อยที่เป็นไปได้ของโหมดย่อยที่เปิดใช้งาน, emulation-mode-map-alists.
  5. ตัวแปรที่โหมดที่สำคัญสามารถแทนที่ keybinds ของเล็ก ๆ น้อย ๆ minor-mode-overriding-map-alistโหมดที่
  6. ที่เกิดขึ้นจริงเล็กน้อยโหมดซึ่ง keybinds minor-mode-map-alistถูกเก็บไว้ใน
  7. ที่จุด (อีกครั้ง) ผ่านlocal-mapคุณสมบัติข้อความ หากมีอยู่รายการ 8 จะถูกข้ามไป
  8. มาตรฐานkeymap บัฟเฟอร์ท้องถิ่น (ที่สำคัญโหมดหรือบัฟเฟอร์ท้องถิ่น keybinds ไป) current-local-mapส่งกลับโดยฟังก์ชั่น
  9. keymap ทั่วโลกcurrent-global-mapกลับมาโดย

นอกจากนี้ยังมีกึ่งรายการ 10 สิ่งที่พบคำสั่งผ่านขั้นตอนข้างต้นอาจได้รับการ remaped

ฟังก์ชั่นต่อไปนี้จะสอบถามความเป็นไปได้บางอย่าง (โอกาสที่เป็นไปได้มากที่สุด) และส่งคืนหรือพิมพ์ผลลัพธ์

(defun locate-key-binding (key)
  "Determine in which keymap KEY is defined."
  (interactive "kPress key: ")
  (let ((ret
         (list
          (key-binding-at-point key)
          (minor-mode-key-binding key)
          (local-key-binding key)
          (global-key-binding key))))
    (when (called-interactively-p 'any)
      (message "At Point: %s\nMinor-mode: %s\nLocal: %s\nGlobal: %s"
               (or (nth 0 ret) "") 
               (or (mapconcat (lambda (x) (format "%s: %s" (car x) (cdr x)))
                              (nth 1 ret) "\n             ")
                   "")
               (or (nth 2 ret) "")
               (or (nth 3 ret) "")))
    ret))

มีฟังก์ชั่นในตัวสำหรับแต่ละฟังก์ชั่นเหล่านี้ยกเว้นฟังก์ชั่นแรกดังนั้นเราต้องสร้างหนึ่งฟังก์ชั่น

(defun key-binding-at-point (key)
  (mapcar (lambda (keymap) (when (keymapp keymap)
                             (lookup-key keymap key)))
          (list
           ;; More likely
           (get-text-property (point) 'keymap)
           (mapcar (lambda (overlay)
                     (overlay-get overlay 'keymap))
                   (overlays-at (point)))
           ;; Less likely
           (get-text-property (point) 'local-map)
           (mapcar (lambda (overlay)
                     (overlay-get overlay 'local-map))
                   (overlays-at (point))))))

เนื่องจากคุณกำลังบอกว่าพฤติกรรมนั้นทำงานอยู่เมื่อจุดอยู่ในสิ่งที่แนบมาจึงมีโอกาสที่ดีที่ปุ่มลัดนี้จะวางบนซ้อนทับหรือข้อความคุณสมบัติ

หากวิธีนี้ใช้ไม่ได้ผลให้ลองใช้คำสั่งต่อไปนี้เช่นกัน M-x keymaps-at-pointเพียงแค่วางเคอร์เซอร์บนสิ่งที่แนบมาและทำ

(defun keymaps-at-point ()
  "List entire keymaps present at point."
  (interactive)
  (let ((map-list
         (list
          (mapcar (lambda (overlay)
                    (overlay-get overlay 'keymap))
                  (overlays-at (point)))
          (mapcar (lambda (overlay)
                    (overlay-get overlay 'local-map))
                  (overlays-at (point)))
          (get-text-property (point) 'keymap)
          (get-text-property (point) 'local-map))))
    (apply #'message
           (concat 
            "Overlay keymap: %s\n"
            "Overlay local-map: %s\n"
            "Text-property keymap: %s\n"
            "Text-property local-map: %s")
           map-list)))

สิ่งนี้จะบอกฉันว่าคีย์มีการเชื่อมโยงโลคัลหรือไม่และคำสั่งใดถูกผูกไว้กับมัน แต่ก็ยังไม่ได้บอกชื่อของคีย์แมปที่มาจากฉัน
nispio

@nispio หากมีการเชื่อมโยงภายในเครื่องจะต้องมาจาก keymap ของโหมดหลักหรือจากการเรียกไปยัง local-set-key น่าเสียดายที่ไม่มีวิธีที่จะเข้าใจผิดได้ในการแยกสองกรณีออกจากกัน
Malabarba

1
@Malabarba คุณหมายถึง "น่าเสียดายที่ไม่มีวิธีง่ายๆในการแยกสองกรณีออกจากกัน?" แน่นอนว่าข้อมูลนั้นมีอยู่ทั้งหมด ทุกโหมดที่สำคัญมีแผนที่โหมดเดียวหรือไม่ ถ้าไม่เป็นเช่นนั้นมีวิธีใดที่จะบอกว่าแผนที่หลักของโหมดใดเปิดใช้งานอยู่?
nispio

1
เริ่มจากยังไม่ได้ปล่อย emacs 25, "Ch k" จะ, ในบางกรณี (ดี, "ในที่สุด" หวังว่า) บอกคุณใน keymap (แม่นยำยิ่งขึ้น: สัญลักษณ์ที่ถือ keymap นั้นเป็นค่า) keybinding ที่กำหนดคือ ที่กำหนดไว้ ตัวอย่างผลลัพธ์:k runs the command gnus-summary-kill-same-subject-and-select (found in gnus-summary-mode-map), which is (...)
YoungFrog

2
สำหรับทุกคนที่สนใจนี่คือความมุ่งมั่นที่เกี่ยวข้องที่แสดง keymap ของการผูกคีย์ใน emacs 25+
Kaushal Modi

2

เกี่ยวกับ:

(defun my-lookup-key (key)
  "Search for KEY in all known keymaps."
  (mapatoms (lambda (ob) (when (and (boundp ob) (keymapp (symbol-value ob)))
                      (when (functionp (lookup-key (symbol-value ob) key))
                        (message "%S" ob))))
            obarray))

ตัวอย่างเช่น(my-lookup-key (kbd "C-c v v"))ฉันได้รับรายชื่อใน*Message*บัฟเฟอร์:

global-map
term-pager-break-map
widget-global-map

วิธีนี้มีประโยชน์สำหรับการค้นหาคีย์ย่อยย่อยซึ่งรวมอยู่ใน keymap ระดับที่สูงขึ้นเช่นผลลัพธ์จาก:

(my-lookup-key (kbd "d"))

เป็นที่vc-prefix-mapซึ่งเป็นที่รวมอยู่ในglobal-map:

(eq (lookup-key global-map (kbd "C-x v")) 'vc-prefix-map)

หากคุณแก้ไขเงื่อนไขการกรองเพื่อรวมkeymapp- คุณจะสามารถค้นหาคำนำหน้าได้ตลอดเวลา:

(defun my-lookup-key-prefix (key)
  "Search for KEY as prefix in all known keymaps."
  (mapatoms (lambda (ob) (when (and (boundp ob) (keymapp (symbol-value ob)))
                      (when (let ((m (lookup-key (symbol-value ob) key)))
                              (and m (or (symbolp m) (keymapp m))))
                        (message "%S" ob))))
            obarray))

ดังนั้นrst-mode-mapจะพบได้ทั้ง:

(my-lookup-key-prefix (kbd "C-c C-t"))
(my-lookup-key-prefix (kbd "C-c C-t C-t"))

1

ฉันทราบว่าสิ่งต่อไปนี้ไม่ตอบคำถามของฉันจะทราบได้อย่างไรว่าdคีย์แมปใดบ้างแต่เกี่ยวข้องกับปัญหาพื้นฐานในกรณีนี้เพื่อให้แน่ใจว่าคีย์ทำงานตามสิ่งที่ผู้ใช้ต้องการ หากต้องการฉันสามารถลบคำตอบนี้และแปลงเป็นอีกคำถาม + คำตอบเกี่ยวกับปัญหานั้นได้

เป็นวิธีการแทนที่text-property/overlayแผนที่คุณควรจะสามารถใช้:

(let ((map (make-sparse-keymap)))
  (define-key map "d" 'evil-previous-line)
  (setq overriding-local-map map))

เป็นต่อการควบคุมแผนที่ที่ใช้งาน , overriding-local-mapจะเหนือกว่าแผนที่ที่ใช้งานทุกอื่น ๆ overriding-terminal-local-mapนอกเหนือจาก


สิ่งนี้ทำลายทุกสิ่ง: ฉันไม่สามารถเปิดข้อความในโหมดสรุปได้อีกต่อไปและความชั่วร้ายและหยาดน้ำค้างก็หยุดทำงาน
brab

สิ่งนี้ทำลายทุกสิ่ง: ฉันไม่สามารถเปิดข้อความในโหมดสรุปได้อีกต่อไปและความชั่วร้ายและหยาดน้ำค้างก็หยุดทำงาน
Emily Hoover

0

emacs-buttonsจัดเตรียมbuttons-displayซึ่งมีอาร์กิวเมนต์นำหน้าแสดงภาพแบบวนซ้ำของการเชื่อมปัจจุบันทั้งหมด

(ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้เขียนแพ็คเกจ)

https://github.com/erjoalgo/emacs-buttons/blob/master/doc/img/sample-visualization.png

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