How can I access the path to the current directory in an emacs directory variable file?
According to the Emacs documentation, Directory Variables appl开发者_运维技巧y to all files below a directory that contains an .dir-locals.el
file.
How can I, in that file, set a variable to the full path that contains the file? For example:
((nil . ((indent-tabs-mode . t)
(my-project-path **THIS_DIRECTORY**))))
I asked myself the same question and found no solution on the web, so I think this answer may help. Actually, it turns out we can reuse dir-locals-find-file
to get the directory containing the .dir-locals.el
file. So here's what I found for, e.g, setting up an aspell personal dictionary dedicated to a whole directory:
((nil . ((eval . (setq ispell-personal-dictionary
(expand-file-name
".aspell_words"
(file-name-directory
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d))))))))))
Also, it seems entries are evaluated in the order they are specified, so the following code should work:
((nil . ((eval . (set (make-local-variable 'my-project-path)
(file-name-directory
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d))))))
(eval . (message "Project directory set to `%s'." my-project-path)))))
Emacs will complain about unsafe local variables (due to the eval
construct), yet one can still permanently mark it safe.
Update: Since Emacs ≥ 26.3 (and maybe older versions as well), it appears that one needs to use (dir-locals-find-file "./")
instead of (dir-locals-find-file ".")
.
I think (file-name-directory (or load-file-name buffer-file-name))
should give you the directory path.
See Link
Edit: Except it won't, because any eval
expressions are evaluated in the context of the buffer whose variables are being hacked.
In my case, I wanted to locate a file that was relative to my current working directory for my repository, and the .dir-locals.el file was checked into the root, so a file "local" to the .dir-locals.el was also a file "local" to the project root.
pajato0's answer above worked for some cases, but it was also breaking other modes (like magit). I got around the issue by using the projectile
package's projectile-project-root
function to find my the base path for me:
((nil . ((eval . (setq cmake-ide-build-dir
(concat (projectile-project-root) "/build-make"))
))))
I've found the locate-dominating-file
procedure, which comes out-of-the-box with Emacs, useful to retreive the current directory of a known file. The example below sets the guix-directory
variable to the topmost directory of the project containing a .dir-locals.el
file.
((nil . ((eval . (setq guix-directory
(locate-dominating-file default-directory
".dir-locals.el"))))))
It's not a safe .dir-locals.el setting, due to relying on eval
, but it gets the job done.
In case it still matters, to the OP or some other, I would suggest you create a function to generate the .dir-locals.el
file. Then one could write something like:
(let ((path default-directory)
file)
(setq file (format "%s/.dir-locals.el" path))
(with-temp-buffer
(insert (format "((nil . ((indent-tabs-mode . t)
(my-project-path \"%s\"))))" path))
(when (file-writable-p file)
(write-region (point-min)
(point-max)
file))))
to be executed within the project home directory.
hack-local-variables
is the main function for processing all local variables, and it calls hack-dir-local-variables
to deal with the .dir-locals.el
file (or a dir local class variable, if you're not using that file).
The code for establishing the directory is not isolated in its own function, so we'll have to copy it out into a new function (this from GNU Emacs 24.0.95.1):
(defun my-dir-locals-dir ()
"Return the directory local variables directory.
Code taken from `hack-dir-local-variables'."
(let ((variables-file (dir-locals-find-file (or (buffer-file-name) default-directory)))
(dir-name nil))
(cond
((stringp variables-file)
(setq dir-name (file-name-directory variables-file)))
((consp variables-file)
(setq dir-name (nth 0 variables-file))))
dir-name))
If you are working on *nix, you might get the work directory by the following elisp code,
(defun get-working-directory ()
(getenv "PWD))
Btw, I have to mentioned that, (shell-command "pwd")
will result in the directory where file (which is corresponding to the buffer you are currently editing).
精彩评论