1

I have a project with a .dir-locals.el file. This file contains some customizations for various project local variables, e.g. include directories for semantic and arguments for clang.

First time opening the project, Emacs asks if I want to consider these variables safe. Obviously I press !, because I don't want to do this every time I open up Emacs.

The problem is that my init.el is part of a git repository, and these local customizations are saved inside the init file as such:

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 [...]
 '(safe-local-variable-values
   '((eval semantic-add-system-include "custom/include/path")
   [...]
   ))

But, IMO., these customizations are meant to be local, ie. not included in the git worktree. And I would really like to not having to include them in the init file.

Could I perhaps point to these safe-local-variable-values by storing them inside another elisp file, and then .gitignore that file instead? And how could I achieve this? Or is there a better way?

Edit:

There's a related answer here, but that moves ALL customizations inside another file, whereas I would like to filter ONLY on the safe-local-variable-values (hoping that it's actually possible).

Drew
  • 75,699
  • 9
  • 109
  • 225
alexpanter
  • 111
  • 4

2 Answers2

2

Yes, possible. You need to change the definition of hack-local-variables-confirm. Find the form (customize-push-and-save (if (= char ?!) ...)) and modify it.

I agree with you to some extent: these should be put into another file. But to be honest, I don’t recommend you change the function’s definition, because this is not elegant, so maybe we'll wait and see if there's any other way.


BTW, you can take a look at my code. (Please ignore the coding style; I will refactor it someday but not now.) try the code shown below. It doesn't answer your question (or, you could say that it answers, because the files that you trust are where the safe variables are.), but does solve your problem: you just need to put the .dir-locals.el file’s path to your .emacs, then Emacs will never ask you to confirm, because these variables are stored in safe-local-variable-values and thus considered safe:

(let ((shynur/safe-local-variable-values (list)))
  (named-let get-vars ((dir-locals
                        (mapcan (lambda (file-path)
                                  (when (file-exists-p file-path)
                                    (with-temp-buffer
                                      (insert-file-contents file-path)
                                      (read (current-buffer)))))
                                ["~/.emacs.d/.dir-locals.el"
                                 "~/.emacs.d/.dir-locals-2.el"
                                 ;; Files that you trust ...
                                 ])))
    (dolist (mode-vars dir-locals)
      (let ((vars (cdr mode-vars)))
        (if (stringp (car mode-vars))
            (get-vars vars)
          (dolist (var-pair vars)
            (push var-pair shynur/safe-local-variable-values))))))
  (setq safe-local-variable-values (nconc shynur/safe-local-variable-values
                                          safe-local-variable-values)))
shynur
  • 4,065
  • 1
  • 3
  • 23
  • Thank you for the suggestion, though I was hoping for something a bit more optimal - the way you have set it up is such that the name and path of local `.dir-locals` files are included in repository, which I _kind_ of wanted to avoid, especially if/when open-sourcing the init file. Or I end up with a global `.dir-locals` file, which means that all my C++ projects locally will have all the same (unnecessary include directories). But I can explore with having _another_ file (ignored by git), which contains a list of `.dir-locals` files and use that in the init. Gotta experiment! Thanks again. – alexpanter Jun 29 '23 at 09:36
1
(let ((safe-vars-file "~/.emacs.d/.data/safe-vars.el"))
  (advice-add 'hack-local-variables-confirm :around
              (lambda (fn &rest args)
                (let ((custom-file safe-vars-file))
                  (apply fn args))))
  (when (file-exists-p safe-vars-file)
    (my/read-safe-vars safe-vars-file)))

You need to implement my/read-safe-vars yourself, but it's not hard.

shynur
  • 4,065
  • 1
  • 3
  • 23