วิธีการผูกกุญแจของคุณกับปุ่มกดที่ยังไม่ได้โหลด?


9

ฉันใช้use-packageเพื่อจัดการแพ็คเกจที่ติดตั้งและbind-keyกำหนดการกระทำให้กับคีย์แบบกำหนดเองที่ฉันชอบ

ฉันแทนที่ที่สุดของการเริ่มต้น Emacs ปุ่มลัด (เช่นC-nกลายเป็นM-k, C-pกลายเป็นM-i) แต่ฉันตกลงกับโหมดอื่น ๆ เอาชนะโครงการปุ่มลัดของฉัน อย่างไรก็ตามในบางครั้งฉันต้องการให้ปุ่มกดยังคงอยู่ ฉันต้องการความM-kหมายอย่างอื่นมากกว่าใน Gnus หรือ Helm ที่เป็นค่าเริ่มต้น

อย่างไรก็ตามพวกเขาขัดแย้งกันในการเริ่มต้นของ Emacs เพราะฉันไม่สามารถเพิ่มการเชื่อมโยงกับ keymap ได้หากไม่มีอยู่ (เพราะuse-packageบางครั้งทำให้การโหลดแพคเกจล่าช้า) เช่นคำสั่งต่อไปนี้มีข้อผิดพลาด (เช่น(void-variable helm-map)) เนื่องจาก Helm และ Gnus ยังไม่โหลดเต็มที่

(bind-key "M-Y" 'helm-end-of-buffer helm-map)
(bind-key "M-k" 'helm-next-line helm-find-files-map)
(bind-key "M-s" 'other-window gnus-summary-mode-map)

ฉันมีuse-packageการร้องขอทั้งหมดของฉันในไฟล์เดียวและbind-keyสำหรับการผูกคีย์ที่กำหนดเองในไฟล์อื่น ฉันไม่ต้องการผูกuse-packageสายไว้เพราะบางทีฉันอาจต้องการเผยแพร่รูปแบบการผูกกุญแจที่กำหนดเองของฉันเป็นแพ็คเกจแบบสแตนด์อโลน จะทำอย่างไรถ้าฉันต้องการให้ใครบางคนติดตั้งแบบแผนของฉันมี Helm และ Gnus keybindings ในพื้นที่อยู่ด้วยหรือไม่

ฉันจะจัดการการโยงbind-keyคีย์- โลคัลโหมดได้อย่างไรเพื่อให้คีย์ทั้งหมดถูกตั้งค่าแม้ว่าจะโหลดแพ็กเกจเมื่อเร็ว ๆ นี้และการตั้งค่าคีย์ทั้งหมดอยู่ในไฟล์เดียว

คำตอบ:


20

คุณสามารถใช้with-eval-after-loadเพื่อเลื่อนการเชื่อมโยงคีย์จนกระทั่งหลังจากโหลดโมดูลที่แน่นอนแล้ว (และกำหนด keymap):

(with-eval-after-load "helm"
  (bind-key "M-Y" #'helm-end-of-buffer helm-map))

ใช้C-h v helm-mapเพื่อค้นหาโมดูลที่มีการกำหนดคีย์แมปและสิ่งที่จะใส่ในสตริงในบรรทัดแรก


with-eval-after-loadเปิดตัวใน Emacs 24.4 หากคุณมีเวอร์ชั่น Emacs รุ่นก่อนหน้าคุณต้องใช้eval-after-loadแทนและใส่เครื่องหมายคำพูดเดี่ยวไว้หน้าการbind-keyโทร:

(eval-after-load "helm"
  '(bind-key "M-Y" #'helm-end-of-buffer helm-map))

หากคุณต้องการbind-keyโทรหลายสายในแบบฟอร์มนี้โดยwith-eval-after-loadคุณเพียงแค่โทรออกไปหาคนอื่น แต่eval-after-loadคุณต้องใส่ทุกสายไว้ในprogn:

(eval-after-load "helm"
  '(progn
     (bind-key "M-Y" #'helm-end-of-buffer helm-map)
     (bind-key "M-k" #'helm-next-line helm-find-files-map)))

9

สารละลาย

เพื่อดำเนินการสิ่งที่หลังจากได้รับแพคเกจที่มีการโหลดคุณจะต้องใส่ว่าหลังจากที่ใน:configuse-package

นี่คือตัวอย่างการใช้ตัวอย่างในคำถามของคุณ:

ตัวอย่าง # 1

(use-package helm
  :config
  (progn
    (bind-key "M-Y" #'helm-end-of-buffer helm-map)
    (bind-key "M-k" #'helm-next-line helm-find-files-map)))

(use-package gnus
  :config
  (bind-key "M-s" #'other-window gnus-summary-mode-map))

คำอธิบาย

มันก็โอเคที่จะมีตัวอย่างข้อมูลด้านล่าง 2 ตำแหน่งในสถานที่ต่าง ๆ ใน emacs ของคุณinit.elหรือในไฟล์ที่ซ้อนกันโหลด / จำเป็น

ตัวอย่าง # 2

(use-package gnus)

ตัวอย่าง # 3

(use-package gnus
  :config
  (bind-key "M-s" #'other-window gnus-summary-mode-map))

เหตุผลก็คือไม่สำคัญว่าจะมีการเรียกใช้ข้อมูลขนาดเล็กด้านบนใดใน 2 อันดับแรกก่อน

นี่คือเหตุผลที่ .. ด้านล่างเป็นตัวอย่างที่ # 3 ขยายออกไป

คุณจะได้รับด้านล่างโดยทำM-x pp-macroexpand-last-sexpเมื่อจุด (เคอร์เซอร์) อยู่หลังวงเล็บปิดสุดท้ายของตัวอย่าง

ตัวอย่าง # 4

(if (not (require 'gnus nil t))
    (ignore (message (format "Could not load %s" 'gnus)))
  (condition-case-unless-debug err
      (bind-key "M-s" #'other-window gnus-summary-mode-map)
    (error
     (ignore
      (display-warning 'use-package
                       (format "%s %s: %s" "gnus" ":config"
                               (error-message-string err))
                       :error))))
  t)

ตัวอย่างข้างต้นโดยทั่วไปหมายความว่า

  • gnusจำเป็นต้องมีก่อนจากนั้นbind-keyจึงดำเนินการแบบฟอร์ม
  • หากgnusไม่พบคุณจะเห็นข้อความในบัฟเฟอร์ * Messages * ที่บอกว่าไม่สามารถโหลดแพ็คเกจได้
  • มันจะโยนข้อผิดพลาดหากมีปัญหาใด ๆ ในการดำเนินการ (bind-key "M-s" #'other-window gnus-summary-mode-map)

นอกจากนี้หากgnusจำเป็นโดยSnippet # 2ด้านบนและต้องการSnippet # 3อีกครั้งก็ไม่สำคัญเพราะrequireไม่โหลดแพ็กเกจอีกครั้งหากถูกโหลดไปแล้ว


การอ้างอิง

จากuse-packageพื้นฐานบน GitHub ของมัน

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

ตัวอย่าง # 5

(use-package foo
  :init
  (setq foo-variable t)
  :config
  (foo-mode 1))

ด้านบนดำเนินการ:initส่วน ( (setq foo-variable t)) ก่อนที่ fooจะโหลดแพคเกจ แต่(foo-mode 1)ใน:configส่วนที่ดำเนินการหลังจาก fooโหลด


3

ตรงข้ามกับคำตอบอื่น ๆ ฉันมักใช้ hooks สำหรับสิ่งนี้เสมอ:

(defun my-company-maps()
  (define-key company-active-map "\C-x\M-h" 'company-show-doc-buffer)
  (define-key company-active-map "\C-n" 'company-select-next)
  (define-key company-active-map "\C-p" 'company-select-previous)
  (define-key company-active-map "\C-h" 'delete-backward-char))

(add-hook 'company-mode-hook 'my-company-maps)

ฉันเช่นกันฉันคิดว่านี่เป็นวิธีที่เหมาะสมในการทำเช่นนั้น
ชื่อผู้ใช้ที่มีความหมาย

2

เนื่องจากคุณใช้ bind-key อยู่แล้วโดยตรงจากเอกสารของbind-key.el:

หากคุณต้องการให้การผูกคีย์เพื่อแทนที่โหมดย่อยทั้งหมดที่อาจผูกคีย์เดียวกันให้ใช้แบบฟอร์ม `bind-key * ':

(bind-key* "<C-return>" 'other-window)

หากต้องการยกเลิกการผูกคีย์ภายใน keymap (ตัวอย่างเช่นหากต้องการหยุดโหมดหลักที่คุณโปรดปรานไม่ให้เปลี่ยนการผูกที่คุณไม่ต้องการแทนที่ทุกที่) ให้ใช้การยกเลิกการผูกคีย์:

(unbind-key "C-c x" some-other-mode-map)

แบบฟอร์มสุดท้ายจะพังหากว่ายังไม่ได้กำหนด Keymap ในขณะนี้เนื่องจากการกำหนดไฟล์some-other-mode-mapยังไม่ได้โหลด ดังนั้นคุณสามารถใส่สิ่งนี้ในการuse-packageสำหรับsome-other-mode(การกำหนดแพ็คเกจsome-other-mode-map) หรือการใช้with-eval-after-load:

(with-eval-after-load 'some-other-mode
  (unbind-key "C-c x" some-other-mode-map))

อีกทางเลือกหนึ่งคือการกำหนดโหมดย่อยของคุณเองที่มีการผูกทั้งหมดซึ่งไม่ควรแทนที่ด้วยโหมดหลัก:

(defvar my-very-own-keymap (make-keymap) "my very own keymap.")

(define-key my-very-own-keymap (kbd "M-i") 'my-foo)

(define-minor-mode my-very-own-keys-minor-mode
  "Minor mode with my very own keybindings."
  t " my-own-keys" my-very-own-keymap)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.