从Emacs中的挂钩中删除特定lambda的函数

jcu*_*bic 3 emacs hook lambda elisp

我找到了这个宏,用于运行特定项目路径的代码:

(defmacro project-specifics (name &rest body)
  `(progn
     (add-hook 'find-file-hook
             (lambda ()
               (when (string-match-p ,name (buffer-file-name))
                 ,@body)))
     (add-hook 'dired-after-readin-hook
             (lambda ()
               (when (string-match-p ,name (dired-current-directory))
                 ,@body)))))
Run Code Online (Sandbox Code Playgroud)

我用它:

(project-specifics "projects/test"
  (message "z"))
Run Code Online (Sandbox Code Playgroud)

我正在做一些修改工作,该工作将从钩子中删除prevoius lambda,到目前为止,我具有帮助功能

(defun remove-lambda-helper (list matcher)
  (dolist (item list)
    (if (and (listp item) (eq (car item) 'lambda))
        (when (funcall matcher item)
          (message "found")
          (setq list (delete item list))))))

(defun remove-hook-name-lambda (name hook)
  (remove-lambda-helper hook
                        (lambda (body)
                          (equal (cadr (cadr (caddr body))) name))))
Run Code Online (Sandbox Code Playgroud)

但是当我打电话时:

(remove-hook-name-lambda "projects/test" find-file-hook)
Run Code Online (Sandbox Code Playgroud)

发现的内容显示在*Messages*缓冲区中,但未删除lambda。怎么了

sds*_*sds 5

问题

原因可能是找到的对象是in 中的第一个对象list,在这种情况下,(delete item list)返回(cdr list)而不是修改其结构以保留身份。

这里的重点是delete 不能保证

(eq x (delete item x))
==> t
Run Code Online (Sandbox Code Playgroud)

例如,当item是的唯一元素时xdelete将会返回原来nil不能返回eq的值cons

解决方案

解决方案是通过替换返回 list的新值remove-lambda-helper

(dolist (item list) ...)
Run Code Online (Sandbox Code Playgroud)

(dolist (item list list) ...)
Run Code Online (Sandbox Code Playgroud)

remove-hook-name-lambda像下面这样使用add-to-list

(defun remove-hook-name-lambda (name hook-name)
  (set hook-name
       (remove-lambda-helper (symbol-value hook)
                             (lambda (body)
                               (equal (cadr (cadr (caddr body))) name)))))
Run Code Online (Sandbox Code Playgroud)

最后的话

在钩子上添加lambda不是一个好主意,尤其是如果您以后要删除它们时。请注意,如果您碰巧编译代码,则lambda删除测试将失败。

如果您修改Lambda,它们也会在钩子中累积,例如,如果您有

(add-hook 'my-hook (lambda () ...))
Run Code Online (Sandbox Code Playgroud)

然后修改lambdaadd-hook再次评估表单,最后在钩子中得到两个 lambda。

更好的解决方案是使用defun定义功能:

(defmacro add-project-specifics (name &rest body)
  (let ((ffh (intern (concat name "-find-file-hook")))
        (darh (intern (concat name "-dired-after-readin-hook"))))
    `(progn
       (defun ,ffh ()
         (when (string-match-p ,name (buffer-file-name))
           ,@body))
       (add-hook 'find-file-hook ',ffh)
       (defun ,darh ()
         (when (string-match-p ,name (dired-current-directory))
           ,@body))
       (add-hook 'dired-after-readin-hook ',darh))))

(defmacro remove-project-specifics (name)
  (let ((ffh (intern (concat name "-find-file-hook")))
        (darh (intern (concat name "-dired-after-readin-hook"))))
    `(progn
       (remove-hook 'find-file-hook ',ffh)
       (unintern ',ffh nil)
       (remove-hook 'dired-after-readin-hook ',darh)
       (unintern ',darh nil))))
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

回应您在评论中表达的关注,只要您在与读者打交道时引用符号,就可以使用符号中的特殊字符;因为您不打算这样做-您只会使用add-project-specificsremove-project-specifics-实习他们应该没问题。

实际问题的最佳解决方案

使用每目录局部变量.dir-locals.el