Emacs ให้คำแนะนำที่ถูกผูกไว้


14

ฉันต้องการแทนที่ฟังก์ชันในโค้ดชั่วคราว

ยกตัวอย่างเช่น

(defun nadvice/load-quiet (args)
  (cl-destructuring-bind
      (file &optional noerror nomessage nosuffix must-suffix)
      args
    (list file noerror t nosuffix must-suffix)))

(defun nadvice/idle-require-quiet (old-fun &rest args)
    (advice-add 'load :filter-args #'nadvice/load-quiet)
    (apply old-fun args)
    (advice-remove #'load #'nadvice/load-quiet))

(advice-add 'idle-require-load-next :around #'nadvice/idle-require-quiet)

อะไรไม่ทำงาน:

  • นี้. มันจะสะอาดกว่านี้ถ้าฉันสามารถหลีกเลี่ยงการเปิดใช้งานและปิดการใช้งานคำแนะนำและไว้วางใจธรรมชาติของ Emacs แบบเธรดเดียวเพื่อดูแลสิ่งต่าง ๆ
  • cl-letfจะไม่ให้ฉันอ้างอิงฟังก์ชั่นการกำเนิดดังนั้นฉันไม่สามารถใช้สิ่งที่:filter-argsปกติจะทำ
  • cl-flet ไม่สามารถแทนที่ฟังก์ชั่นในฟังก์ชั่นอื่น ๆ
  • nofletเป็นแพ็คเกจภายนอกซึ่งฉันต้องการหลีกเลี่ยง (ทำมากกว่าที่ฉันต้องการด้วย)

คำตอบ:


16

คุณไม่สามารถใช้(cl-)letfในขณะที่อ้างอิงฟังก์ชั่นดั้งเดิมของตัวเองได้ใช่ไหม

บางสิ่งเช่นนี้

;; Original function
(defun my-fun (arg)
  (message "my-fun (%s)" arg))


;; Standard call
(my-fun "arg") ;; => my-fun (arg)


;; Temporary overriding (more or less like an around advice)
(let ((orig-fun (symbol-function 'my-fun)))
  (letf (((symbol-function 'my-fun)
          (lambda (arg)
            ;; filter arguments
            (funcall orig-fun (concat "modified-" arg)))))
    (my-fun "arg")))
;; => my-fun (modified-arg)


;; The overriding was only temporary
(my-fun "arg") ;; => my-fun (arg)



คุณยังสามารถใส่คำสั่งนี้ในแมโครได้หากคุณวางแผนที่จะนำมาใช้ซ้ำ:

(defmacro with-advice (args &rest body)
  (declare (indent 1))
  (let ((fun-name (car args))
        (advice   (cadr args))
        (orig-sym (make-symbol "orig")))
    `(cl-letf* ((,orig-sym  (symbol-function ',fun-name))
                ((symbol-function ',fun-name)
                 (lambda (&rest args)
                   (apply ,advice ,orig-sym args))))
       ,@body)))

ตัวอย่างด้านบนนั้นสามารถเขียนใหม่ได้ดังต่อไปนี้:

(defun my-fun (arg)
  (message "my-fun (%s)" arg))


(my-fun "my-arg")

(with-advice (my-fun
              (lambda (orig-fun arg)
                (funcall orig-fun (concat "modified-" arg))))
  (my-fun "my-arg"))

(my-fun "my-arg")

ขอบคุณนี่คือสิ่งที่ฉันกำลังมองหา สิ่งเดียวที่ฉันเปลี่ยนแปลงคือใช้cl-letf*สำหรับทั้งสองletอย่าง
PythonNut

ฉันเพิ่มเวอร์ชันแมโครซึ่งใช้เพียงletf*รูปแบบเดียวสำหรับการผูกทั้งสอง
FrançoisFévotte

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