Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong type argument: listp, eval-after-load in .dir-locals.el

I'm writing my first .dir-locals.el, and I'm getting an error in *Messages*.

Code:

(eval-after-load "grep"
  '(add-to-list 'grep-find-ignored-directories "blur"))

Trace:

.dir-locals error: Wrong type argument: listp, eval-after-load

What am I doing wrong?

like image 326
mcandre Avatar asked Mar 24 '23 04:03

mcandre


1 Answers

The general format for .dir-locals.el is described here:

  • C-hig (emacs) Directory Variables RET
  • http://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html
  • http://www.emacswiki.org/emacs/DirectoryVariables

To evaluate code, you must use the special pseudo variable name eval, as described at:

  • C-hig (emacs) Specifying File Variables RET
  • http://www.gnu.org/software/emacs/manual/html_node/emacs/Specifying-File-Variables.html
  • http://www.emacswiki.org/emacs/LocalVariables

e.g.:

((nil . ((indent-tabs-mode . t)
         (eval . (eval-after-load "grep"
                   '(add-to-list 'grep-find-ignored-directories "blur")))
         (fill-column . 80)))
 (c-mode . ((c-file-style . "BSD")
            (subdirs . nil))))

However, grep-find-ignored-directories is not an automatic buffer-local variable, and we are not explicitly setting it as a directory local variable here (the 'local variable' in question here is eval), so when grep-find-ignored-directories gets set this way it is set globally, which is surely not what you intended1.

You might try something like this:

((nil . ((eval . (eval-after-load "grep"
                   '(add-to-list 
                     (make-local-variable 'grep-find-ignored-directories) 
                     "blur"))))))

but in fact that's still wrong, as once you have visited a file under this directory, that eval-after-load (which is a global setting) will be triggered as soon as grep is loaded, no matter which buffer you are in at the time, so you could easily add your "blur" value locally in some unwanted buffer from which you called grep, while also failing to add it for any of the previously-visited buffers in which you wanted it.

The simplest solution is probably to forcibly require grep before setting the variable:

((nil . ((eval . (progn
                   (require 'grep)
                   (add-to-list 
                    (make-local-variable 'grep-find-ignored-directories)
                    "blur"))))))

That ensures that all files under the directory will get the local value (and that files elsewhere will not).

Now, that's one approach to the general problem, but taking a look at this specific case, and C-hv grep-find-ignored-directories, this variable provide some functionality which can make the solution simpler, and not require grep to be loaded unnecessarily.

Your .dir-locals.el file can set a local variable thus:

((nil . ((my-ignore-blur-p . t))))

And in your .emacs you can do the following:

(defun my-ignore-blur-p (dir)
  "Return non-nil when the `my-ignore-blur-p' local variable is set."
  (local-variable-if-set-p 'my-ignore-blur-p))

(eval-after-load "grep"
  '(add-to-list 'grep-find-ignored-directories
                (cons 'my-ignore-blur-p "blur")))

Then when you execute rgrep from any buffer in which this local variable is set, the custom function we have specified in the global grep-find-ignored-directories variable will return a non-nil value, which will cause "blur" to be included in the list of ignored directories.

(n.b. I used the same name for both the function and the variable because I can -- elisp has separate name spaces for variables and functions -- but that's not necessary. For clarity, I'm referring to the function in the eval-after-load code, and the variable in the function code and the .dir-locals.el file).

Or you could just base the behaviour of the my-ignore-blur-p function on the dir argument (being the directory being searched), and ignore local variables altogether. That would make the decision to include or omit "blur" from the list completely independent of the buffer from which you initiated the rgrep command, which might be even more desirable.


1 If adding "blur" to grep-find-ignored-directories globally is what you wanted, then don't use .dir-locals.el at all -- just add your eval-after-load call to your .emacs file.

like image 122
phils Avatar answered Apr 27 '23 18:04

phils