I found this macro, to run code for specific project path:
(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)))))
and I use it:
(project-specifics "projects/test"
(message "z"))
And I work on modification that will remove prevoius lambda from the hook, so far I have helper functions
(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))))
But when I call:
(remove-hook-name-lambda "projects/test" find-file-hook)
found is show up in *Messages*
buffer but the lambda is not removed. What's wrong here?
Add the lambdas to the hooks and to your own hash table keyed by name. Then when you need to remove it, look up the lambda in the hash table and delq it from the hook.
About Elisp hash tables: http://www.gnu.org/software/emacs/manual/html_node/elisp/Hash-Tables.html
Btw (eq (car item) 'lambda) will fail when lexical-binding t.
The Problem
The reason is probably that the found object is the first in
list
, in which case(delete item list)
returns(cdr list)
instead of modifying its structure to preserve identity.The important point here is that
delete
cannot guarantee thate.g. when
item
is the only element ofx
,delete
will returnnil
which cannot beeq
to the originalcons
.The Solution
The solution is to return the new value of list from
remove-lambda-helper
by replacingwith
and use it in
remove-hook-name-lambda
like inadd-to-list
:The Final Remark
Adding lambdas to hooks is not a very good idea, especially if you want to remove them later. Note that your lambda removal test will fail if you happen to compile your code.
Lambdas also accumulate in the hook if you modify them, e.g., if you have
and then you modify the
lambda
and evaluate theadd-hook
form again, you will end up with two lambdas in the hook.The much better solution is to use
defun
to define the functions:PS
Responding to the concern you expressed in a comment, special characters in symbols are okay as long as you quote them when dealing with the reader; since you are not going to do that - you will be only using
add-project-specifics
andremove-project-specifics
- you should be fine with interning them.The Best Solution to Your Actual Problem
Use Per-Directory Local Variables in
.dir-locals.el
.I would like to propose a refactoring which allows you to define the hook once, then have it run the actual action only when some conditions are fulfilled.
So, just unset
project-specific-name
and/orproject-specific-fun
to disable the action from the hooks.