Hi Christopher,

Christopher Lemmer Webber <cweb...@dustycloud.org> writes:

[...]

> I'm a bit unsure what the implications fully are with this change, but
> here was my user experience:
>
>  - Did a pull using magit to guix
>  - Suddenly every file I open in Guix is prompting me if I want to
>    enable these dir-locals, I notice some have "eval" and I don't know
>    what it's doing so I say no
>  - But it's asking me every file
>  - And oh no, it's asking me about ten times for every magit operation!
>    (Presumably due to the reload operation.)  Fine okay fine, YES, okay
>    cool it's quiet now... I hope that was safe.

Thanks for the feedback (even though it's not a great experience you've
had!).  If I understand correctly when prompted like this following the
change to .dir-locals.el:

--8<---------------cut here---------------start------------->8---
The local variables list in /home/maxim/src/guix/
contains values that may not be safe (*).

Do you want to apply it?  You can type
y  -- to apply the local variables list.
n  -- to ignore the local variables list.
!  -- to apply the local variables list, and permanently mark these
      values (*) as safe (in the future, they will be set automatically.)

    fill-column : 78
    tab-width : 8
    sentence-end-double-space : t
    bug-reference-url-format : "http://bugs.gnu.org/%s";
    bug-reference-bug-regexp : 
"<https?://\\(debbugs\\|bugs\\)\\.gnu\\.org/\\([0-9]+\\)>"
  * eval : (setq guix-directory (locate-dominating-file default-directory 
".dir-locals.el"))
  * eval : (let* ((root-dir (expand-file-name (locate-dominating-file 
default-directory ".dir-locals.el"))) (root-dir* (directory-file-name 
root-dir))) (unless (boundp 'geiser-guile-load-path) (defvar 
geiser-guile-load-path 'nil)) (make-local-variable 'geiser-guile-load-path) 
(require 'cl-lib) (cl-pushnew root-dir* geiser-guile-load-path :test 
#'string-equal))
--8<---------------cut here---------------end--------------->8---

You've been trying to decline with 'n', but Emacs doesn't remember your
choice and keeps bugging you with it.  To be honest, that seems a design
shortcoming in Emacs; there's a '!' that means 'yes and remember it' but
there doesn't seem to be an equivalent option for 'no and remember it'.
So it keeps forgetting.

Also note that this isn't the first use of 'eval' in the Guix
.dir-locals file; so if you started hacking on the Guix sources in Emacs
for the first time, you'd have been greeted with this (!):

--8<---------------cut here---------------start------------->8---
The local variables list in /home/maxim/src/guix/
contains values that may not be safe (*).

Do you want to apply it?  You can type
y  -- to apply the local variables list.
n  -- to ignore the local variables list.
!  -- to apply the local variables list, and permanently mark these
      values (*) as safe (in the future, they will be set automatically.)

    fill-column : 78
    tab-width : 8
    sentence-end-double-space : t
    bug-reference-url-format : "http://bugs.gnu.org/%s";
    bug-reference-bug-regexp : 
"<https?://\\(debbugs\\|bugs\\)\\.gnu\\.org/\\([0-9]+\\)>"
    indent-tabs-mode : nil
    eval : (put 'eval-when 'scheme-indent-function 1)
    eval : (put 'call-with-prompt 'scheme-indent-function 1)
    eval : (put 'test-assert 'scheme-indent-function 1)
    eval : (put 'test-assertm 'scheme-indent-function 1)
    eval : (put 'test-equalm 'scheme-indent-function 1)
    eval : (put 'test-equal 'scheme-indent-function 1)
    eval : (put 'test-eq 'scheme-indent-function 1)
    eval : (put 'call-with-input-string 'scheme-indent-function 1)
    eval : (put 'guard 'scheme-indent-function 1)
    eval : (put 'lambda* 'scheme-indent-function 1)
    eval : (put 'substitute* 'scheme-indent-function 1)
    eval : (put 'match-record 'scheme-indent-function 2)
    eval : (put 'modify-phases 'scheme-indent-function 1)
    eval : (put 'replace 'scheme-indent-function 1)
    eval : (put 'add-before 'scheme-indent-function 2)
    eval : (put 'add-after 'scheme-indent-function 2)
    eval : (put 'modify-services 'scheme-indent-function 1)
    eval : (put 'with-directory-excursion 'scheme-indent-function 1)
    eval : (put 'with-file-lock 'scheme-indent-function 1)
    eval : (put 'with-file-lock/no-wait 'scheme-indent-function 1)
    eval : (put 'with-profile-lock 'scheme-indent-function 1)
    eval : (put 'with-writable-file 'scheme-indent-function 2)
    eval : (put 'package 'scheme-indent-function 0)
    eval : (put 'package/inherit 'scheme-indent-function 1)
    eval : (put 'origin 'scheme-indent-function 0)
    eval : (put 'build-system 'scheme-indent-function 0)
    eval : (put 'bag 'scheme-indent-function 0)
    eval : (put 'graft 'scheme-indent-function 0)
    eval : (put 'operating-system 'scheme-indent-function 0)
    eval : (put 'file-system 'scheme-indent-function 0)
    eval : (put 'manifest-entry 'scheme-indent-function 0)
    eval : (put 'manifest-pattern 'scheme-indent-function 0)
    eval : (put 'substitute-keyword-arguments 'scheme-indent-function 1)
    eval : (put 'with-store 'scheme-indent-function 1)
    eval : (put 'with-external-store 'scheme-indent-function 1)
    eval : (put 'with-error-handling 'scheme-indent-function 0)
    eval : (put 'with-mutex 'scheme-indent-function 1)
    eval : (put 'with-atomic-file-output 'scheme-indent-function 1)
    eval : (put 'call-with-compressed-output-port 'scheme-indent-function 2)
    eval : (put 'call-with-decompressed-port 'scheme-indent-function 2)
    eval : (put 'call-with-gzip-input-port 'scheme-indent-function 1)
    eval : (put 'call-with-gzip-output-port 'scheme-indent-function 1)
    eval : (put 'call-with-lzip-input-port 'scheme-indent-function 1)
    eval : (put 'call-with-lzip-output-port 'scheme-indent-function 1)
    eval : (put 'signature-case 'scheme-indent-function 1)
    eval : (put 'emacs-batch-eval 'scheme-indent-function 0)
    eval : (put 'emacs-batch-edit-file 'scheme-indent-function 1)
    eval : (put 'emacs-substitute-sexps 'scheme-indent-function 1)
    eval : (put 'emacs-substitute-variables 'scheme-indent-function 1)
    eval : (put 'with-derivation-narinfo 'scheme-indent-function 1)
    eval : (put 'with-derivation-substitute 'scheme-indent-function 2)
    eval : (put 'with-status-report 'scheme-indent-function 1)
    eval : (put 'with-status-verbosity 'scheme-indent-function 1)
    eval : (put 'with-build-handler 'scheme-indent-function 1)
    eval : (put 'mlambda 'scheme-indent-function 1)
    eval : (put 'mlambdaq 'scheme-indent-function 1)
    eval : (put 'syntax-parameterize 'scheme-indent-function 1)
    eval : (put 'with-monad 'scheme-indent-function 1)
    eval : (put 'mbegin 'scheme-indent-function 1)
    eval : (put 'mwhen 'scheme-indent-function 1)
    eval : (put 'munless 'scheme-indent-function 1)
    eval : (put 'mlet* 'scheme-indent-function 2)
    eval : (put 'mlet 'scheme-indent-function 2)
    eval : (put 'run-with-store 'scheme-indent-function 1)
    eval : (put 'run-with-state 'scheme-indent-function 1)
    eval : (put 'wrap-program 'scheme-indent-function 1)
    eval : (put 'with-imported-modules 'scheme-indent-function 1)
    eval : (put 'with-extensions 'scheme-indent-function 1)
    eval : (put 'with-parameters 'scheme-indent-function 1)
    eval : (put 'let-system 'scheme-indent-function 1)
    eval : (put 'with-database 'scheme-indent-function 2)
    eval : (put 'call-with-transaction 'scheme-indent-function 1)
    eval : (put 'with-statement 'scheme-indent-function 3)
    eval : (put 'call-with-retrying-transaction 'scheme-indent-function 1)
    eval : (put 'call-with-savepoint 'scheme-indent-function 1)
    eval : (put 'call-with-retrying-savepoint 'scheme-indent-function 1)
    eval : (put 'call-with-container 'scheme-indent-function 1)
    eval : (put 'container-excursion 'scheme-indent-function 1)
    eval : (put 'eventually 'scheme-indent-function 1)
    eval : (put 'call-with-progress-reporter 'scheme-indent-function 1)
    eval : (put 'with-repository 'scheme-indent-function 2)
    eval : (put 'with-temporary-git-repository 'scheme-indent-function 2)
    eval : (put 'with-temporary-git-worktree 'scheme-indent-function 2)
    eval : (put 'with-environment-variables 'scheme-indent-function 1)
    eval : (put 'with-fresh-gnupg-setup 'scheme-indent-function 1)
    eval : (put 'with-paginated-output-port 'scheme-indent-function 1)
  * eval : (modify-syntax-entry 126 "'")
  * eval : (modify-syntax-entry 36 "'")
  * eval : (modify-syntax-entry 43 "'")
--8<---------------cut here---------------end--------------->8---

So I don't see how the new behavior is much different.  The experience
is bad unless you trust (and tell Emacs to remember your choice) the
.dir-locals with '!', and sadly Emacs doesn't seem to provide an
alternative.

> Later...
>
>  - I'm hacking on another file in another repo
>  - C-x v = (check to see a diff of the work-in-progress changes of the
>    file I'm working on)
>  - Error in the minibuffer!  "Wrong type argument: stringp, nil"
>  - wtf, okay M-x toggle-debug-on-error
>
> Debugger entered--Lisp error: (wrong-type-argument stringp nil)
>   expand-file-name(nil)
>   (let* ((root-dir (expand-file-name (locate-dominating-file 
> default-directory ".dir-locals.el"))) (root-dir* (directory-file-name 
> root-dir))) (unless (boundp 'geiser-guile-load-path) (defvar 
> geiser-guile-load-path 'nil)) (make-local-variable 'geiser-guile-load-path) 
> (require 'cl-lib) (cl-pushnew root-dir* geiser-guile-load-path :test 
> #'string-equal))
>   eval((let* ((root-dir (expand-file-name (locate-dominating-file 
> default-directory ".dir-locals.el"))) (root-dir* (directory-file-name 
> root-dir))) (unless (boundp 'geiser-guile-load-path) (defvar 
> geiser-guile-load-path 'nil)) (make-local-variable 'geiser-guile-load-path) 
> (require 'cl-lib) (cl-pushnew root-dir* geiser-guile-load-path :test 
> #'string-equal)))
>   hack-one-local-variable(eval (let* ((root-dir (expand-file-name 
> (locate-dominating-file default-directory ".dir-locals.el"))) (root-dir* 
> (directory-file-name root-dir))) (unless (boundp 'geiser-guile-load-path) 
> (defvar geiser-guile-load-path 'nil)) (make-local-variable 
> 'geiser-guile-load-path) (require 'cl-lib) (cl-pushnew root-dir* 
> geiser-guile-load-path :test #'string-equal)))
>   hack-local-variables-apply()
>   hack-dir-local-variables-non-file-buffer()
>   diff-mode()
>   vc-diff-internal(t (Git 
> ("/home/cwebber/devel/scribble/scribble-lib/scribble...")) nil nil t)
>   vc-diff(nil t)
>   funcall-interactively(vc-diff nil t)
>   call-interactively(vc-diff nil nil)
>   command-execute(vc-diff)
>
>  - Oh... it's whatever thing I enabled earlier in the guix repo.  Well
>    now my vc-diff is broken outside of there... :\

This is quite unexpected, given the new Elisp snippet should run only
for buffers attached to the Guix source tree.

> I'm presuming that if I understood whatever this is doing, it's probably
> something that gives me a better user experience if I accept it while
> working on Guix.  But a) for whatever reason Emacs' dir-locals stuff is
> written in such a way that it antagonizes me for not accepting it and I
> didn't know what it eval was (maybe this is a lack of understanding in
> how to "say no and get it to listen to me"... I didn't resist for too
> long)

I think my explanation above covers a); basically this is a shortcoming
in Emacs and was already the case with the previous version of
.dir-locals.

b) it seems like this change isn't scoped to Guix's checkout
 itself somehow...

I'll try to reproduce, and report back.

Thanks for the feedback!

Maxim

Reply via email to