我找到了这个宏,为特定的项目路径运行代码:
(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)))))
我用它:
(project-specifics "projects/test"
(message "z"))
我正在进行修改,将从钩子中删除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))))
但是当我打电话时:
(remove-hook-name-lambda "projects/test" find-file-hook)
找到的显示在*Messages*
缓冲区中,但不删除lambda。这里有什么问题?
答案 0 :(得分:4)
原因可能是找到的对象是list
中的 first ,在这种情况下(delete item list)
返回(cdr list)
而不是修改其结构以保留身份
重点是delete
不能保证
(eq x (delete item x))
==> t
e.g。当item
是x
的唯一元素时,delete
将返回nil
,eq
不能cons
原始remove-lambda-helper
。
解决方案是通过替换
返回来自(dolist (item list) ...)
的列表的新值
(dolist (item list list) ...)
与
remove-hook-name-lambda
并在(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)))))
中使用它,例如add-to-list
:
(add-hook 'my-hook (lambda () ...))
将lambda添加到钩子中并不是一个好主意,特别是如果你想稍后删除它们。请注意,如果您碰巧编译代码,则lambda删除测试将失败。
如果你修改它们,Lambda也会在钩子中累积,例如,如果你有
lambda
然后您修改add-hook
并再次评估defun
表单,最终会在两个 lambdas中结束。
更好的解决方案是使用(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))))
来定义函数:
add-project-specifics
回应您在评论中表达的担忧,只要您在与读者打交道时引用它们,符号中的特殊字符就可以了;因为你不打算这样做 - 你只会使用remove-project-specifics
和.dir-locals.el
- 你可以随意实习。
在{{1}}中使用Per-Directory Local Variables。
答案 1 :(得分:2)
将lambda添加到钩子和由名称键入的哈希表中。然后当你需要删除它时,在哈希表中查找lambda并从钩子中查找它。
关于Elisp哈希表:http://www.gnu.org/software/emacs/manual/html_node/elisp/Hash-Tables.html
btw(eq(car item)'lambda)在词法绑定时会失败。
答案 2 :(得分:1)
我想提出一个重构,它允许你定义一次钩子,然后让它只在满足某些条件时运行实际动作。
(defvar project-specific-name-regex "projects/test"
"*Regex to match on buffer name in order to trigger `project-specific-fun'.")
(defvar project-specific-fun (lambda () (message "z"))
"*Lambda form to run when `project-specific-name-regex' triggers.")
(defsubst project-specific-trigger-maybe (name)
(and project-specific-name-regex
(stringp project-specific-name-regex)
(string-match-p project-specific-name-regex name)
project-specific-fun
(funcall project-specific-fun) ) )
(defun project-specific-find-file ()
"Hook run from `find-file-hook' to run `project-specific-fun' if it's set
and the buffer name matches `project-specific-name-regex'."
(project-specific-trigger-maybe (buffer-file-name)) )
(defun project-specific-dired-after-readin ()
"Hook run from `dired-after-readin-hook' to run `project-specific-fun'
if it's set and the directory name matches `project-specific-name-regex'."
(project-specific-trigger-maybe (dired-current-directory)) )
(add-hook 'find-file-hook #'project-specific-find-file)
(add-hook 'dired-after-readin-hook #'project-specific-dired-after-readin)
因此,只需取消设置project-specific-name
和/或project-specific-fun
即可禁用挂钩操作。