เหตุใดฉันไม่ผูกฟังก์ชันของฉันกับคีย์หรือเรียกมันด้วย Mx


13

ฉันเขียนฟังก์ชั่นและฉันต้องการเรียกมันผ่าน Mx และผูกมันไว้กับกุญแจ นี่คือฟังก์ชั่นของฉัน:

(defun my-function ()
    (message "This is a great function"))

ถ้าฉันพยายามโทรด้วยM-x my-functionฉันได้รับข้อผิดพลาด: [no match]ใน mini-buffer

ถ้าฉันพยายามผูกมันไว้กับกุญแจ (หรือคลิกเมาส์):

(global-set-key (kbd "C-c a") 'my-function)

ดูเหมือนว่าจะใช้งานได้ แต่เมื่อฉันพยายามโทรด้วยC-c aฉันได้รับข้อผิดพลาด

อาร์กิวเมนต์ประเภทไม่ถูกต้อง: commandp, my-function

ทำไมฉันถึงใช้ฟังก์ชั่นไม่ได้?


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

1
ขอบคุณที่ทำสิ่งนี้ไทเลอร์ ฉันตั้งค่าสถานะ Q สำหรับผู้ดำเนินรายการเพื่อโปรดแปลงเป็นคำถามชุมชน
Drew

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

มันจะดีถ้าตอนนี้ผู้คนค้นหาวิกิเพื่อพูดcommandpเพื่อพยายามค้นหา Qs อื่น ๆ ที่สามารถปิดได้เหมือนรายการที่ซ้ำกันของอันนี้ โปรดระมัดระวังในการอ่านคำถาม & ตอบเนื่องจากมีบางอย่างแตกต่างกัน ในบางกรณีคำตอบ (และบริบท Q) อาจมีค่าซ้ำที่นี่ ในกรณีอื่น ๆคำถามนั้นไม่เกี่ยวข้องและควรปล่อยทิ้งไว้ตามที่เป็นอยู่ (ไม่ปิด)
Drew

1
@ ดึงฉันไม่แน่ใจว่าวิธีที่ดีที่สุดในการ 'โฆษณา' นี้ในชื่อ ข้อผิดพลาด commandp จะปรากฏขึ้นพร้อมกับการโยงคีย์ดังนั้นผู้ใช้ที่พบเจอสิ่งนี้จากทิศทาง Mx จะไม่เห็นการเชื่อมต่อ ไม่แน่ใจว่าสิ่งที่สมดุลที่ดีที่สุดคือระหว่างชื่อที่ชัดเจนกระชับและชื่อที่จะปรากฏขึ้นสำหรับคำค้นหาที่เกี่ยวข้องทั้งหมด ปรับแต่งตามใจชอบ!
ไทเลอร์

คำตอบ:


22

จุดหลักคือว่ามีความแตกต่างระหว่างการทำงานและคำสั่ง

ในเสียงกระเพื่อม Emacs ฟังก์ชั่นจะไม่สามารถเรียกร้องได้โดยการโต้ตอบ ซึ่งหมายความว่าคุณไม่สามารถเข้าถึงผ่านM-xหรือผูกไว้กับคีย์หรือการคลิกเมาส์ หากคุณต้องการทำเช่นนั้นคุณต้องประกาศฟังก์ชั่นให้ชัดเจนinteractiveซึ่งคุณทำได้โดยการเพิ่ม(interactive)ฟอร์มเป็นบรรทัดแรกในเนื้อความ (ตามด้วยสตริงเอกสารประกอบ) ฟังก์ชั่นการโต้ตอบที่เรียกว่าคำสั่งนี้จะอธิบายในคู่มือการ: (ฉบับออนไลน์)(info "(elisp) Using Interactive")

เกิดข้อผิดพลาดที่คุณเห็นWrong type argument: commandp, my-functionจะแสดงให้เห็นว่าคุณกำลังพยายามที่จะเรียกฟังก์ชั่นการโต้ตอบ แต่ฟังก์ชั่นที่ไม่ได้เป็นคำสั่ง

เพื่ออธิบายข้อผิดพลาดที่เกิดขึ้นจริงจดหมายpมักใช้ในเสียงกระเพื่อมเพื่อระบุภาคแสดงหรือการทดสอบ ในกรณีนี้ Emacs กำลังทดสอบmy-functionเพื่อดูว่าเป็นคำสั่งที่ใช้การทดสอบcommandpหรือไม่ ไม่ใช่ซึ่งนำไปสู่ข้อผิดพลาด ข้อผิดพลาดที่คล้ายกันปรากฏขึ้นเมื่อใดก็ตามที่คุณใช้วัตถุชนิดที่ไม่ถูกต้องถ้า Emacs คาดสตริงและคุณผ่านสัญลักษณ์คุณอาจเห็นการอ้างอิงถึงstringpยกตัวอย่างเช่น

ในการตอบคำถามตามที่ถามคุณจะต้องเพิ่ม(interactive)บรรทัดลงในคำจำกัดความ:

(defun my-function ()
    (interactive)
    (message "This is a great function"))

มีเป็นจำนวนมากของตัวเลือกสำหรับinteractiveรูปแบบการสนับสนุนทุกชนิดของวิธีการส่งผ่านข้อมูลไปยังการทำงานของคุณ ตรวจสอบคู่มือสำหรับรายละเอียดทั้งหมด

แมโครคีย์บอร์ดเป็นกรณีพิเศษในบริบทนี้ มาโครคีย์บอร์ดคือลำดับเหตุการณ์การป้อนข้อมูลแสดงเป็นสตริง มาโครคีย์บอร์ดทำงานเหมือนคำสั่งดังนั้นคุณสามารถผูกมันไว้กับคีย์ได้โดยไม่ต้องกังวลกับการเพิ่มการinteractiveประกาศ ตัวอย่างเช่นในต่อไปนี้:

(global-set-key (kbd "C-c l") "λ")

"λ"เป็นมาโครคีย์บอร์ดดังนั้นเราสามารถผูกมันไว้ได้C-c lโดยไม่มีปัญหา หากเราพยายามทำสิ่งเดียวกันกับฟังก์ชั่นเราต้องแน่ใจว่ากำหนดฟังก์ชั่นเป็นinteractive:

(global-set-key (kbd "C-c k") 
  (lambda () (insert "λ"))
;; C-c k is undefined! We tried to bind it to a function

(global-set-key (kbd "C-c m") 
  (lambda () (interactive) (insert "λ"))
;; C-c m is bound to a command that inserts λ

คำแนะนำเดียวที่ฉันต้องการเพิ่มทำให้ชัดเจนว่าคุณต้องทำCx Ceก่อนทำM-x my-functionในตัวอย่างของคุณ นอกจากนี้ในฐานะผู้เริ่มต้น emacs ฉันยังไม่ชัดเจน 100% เลยในสิ่งที่C-x C-eทำหรือเมื่อคุณต้องการเรียกใช้ แต่ปรากฏว่าเอ่อ ... เมื่อคุณเรียกใช้มันจะแยกวิเคราะห์บัฟเฟอร์และเขียนทับmy-functionในหน่วยความจำเพราะถ้าฉัน อย่าเรียกใช้C-x C-e M-xฟังก์ชันจากครั้งสุดท้ายที่ฉันวิ่งC-x C-e
jrh

ดูเหมือนว่าจะC-x C-e ประเมินบัฟเฟอร์ดูเหมือนว่าผลลัพธ์ของการประเมินบัฟเฟอร์ที่มีการdefunลงทะเบียนฟังก์ชั่นแม้ว่าบทความนี้จะทำให้ฉันคิดว่ามันควรจะเรียกใช้ฟังก์ชั่นและสิ่งเดียวที่แสดงใน minibuffer คือmy-function(นัยว่ามันกลับฟังก์ชั่น?) This is a great functionไม่ได้ ฉันต้องคิดถึงบางสิ่งที่นี่
jrh

1
ขอบคุณสำหรับความคิดเห็นของคุณ @jrh คำถาม & คำตอบนี้กล่าวถึงลักษณะเฉพาะของ elisp วิธีทำให้ฟังก์ชั่นโต้ตอบ (เช่นเปลี่ยนฟังก์ชั่นเป็นคำสั่ง) คุณกำลังถามเกี่ยวกับลักษณะพื้นฐานเพิ่มเติมของ elisp และอยู่นอกเหนือขอบเขตของคำถามนี้ ฉันแนะนำให้ทำงานผ่าน Emacs Lisp Intro ดูเหมือนว่าคุณจะสับสนเกี่ยวกับความแตกต่างระหว่างการประเมินฟังก์ชั่นนิยามซึ่ง (อีกครั้ง) กำหนดฟังก์ชั่น แต่ไม่ได้เรียกจริง ๆ แล้วเรียกฟังก์ชั่นที่เรียกใช้รหัสฟังก์ชั่น
Tyler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.