Subject: Re: bug#63648: 29.0.90; project.el: with switch-use-entire-map, switch-project errors on non-project commands

From: Spencer Baugh <[email-masked]>
Date: Tue, 29 Aug 2023 16:34:02 -0400

Dmitry Gutov <[email-masked]> writes:

> On 23/08/2023 16:53, Spencer Baugh wrote:
>> Oh, another thought (which maybe should be discussed on emacs-devel):
>> maybe we don't need to make this specific next-default-directory var.
>> Instead, maybe what we want is a way to bind a dynamic variable
>> *without*  changing the buffer-local value.  It would shadow the existing
>> binding, but if we explicitly switched buffer we'd get back to the old
>> value.  So we'd have:
>> (special-let ((default-directory newval))
>>    (assert default-directory newval))
>> and
>> (special-let ((default-directory newval))
>>    (set-buffer (current-buffer))
>>    (assert default-directory oldval))
>
> Where does the main logic run in this case?
>
> If we call set-buffer before the main logic is ran, the old value of
> dd will be used.
>
> If we call set-buffer after the main logic is ran, we could as well
> use plain 'let' because that's what it does: restores the previous
> values at the end (and we know that it doesn't suit our purpose).

Sorry, I was unclear - our logic wouldn't use set-buffer at all, it's
just that things would work fine if user code used set-buffer.

So this would work:

(project-current) ;; -> (vc . oldval)
(special-let ((default-directory newval))
  (project-current) ;; -> (vc . newval)
  (with-current-buffer (current-buffer)
    (project-current))) ;; -> (vc . oldval)
  (project-current) ;; -> (vc . newval)

The actual logic of project-switch-project would be:

(defun project-switch-project (dir)
  (interactive (list (funcall project-prompter)))
  (let ((command (if (symbolp project-switch-commands)
                     project-switch-commands
                   (project--switch-project-command))))
    (special-let ((default-directory dir))
      (call-interactively command))))

(well, as long as (project--switch-project-command) could support
reading arbitrary commands)

> I was also considering rebinding the global value of dd instead, but
> that turned out to be even sillier, since any new buffer inherits the
> local value of this var from the previous buffer, the global one isn't
> used anywhere (or doesn't seem to be).
>
> (cl-letf (((default-value 'default-directory) "~/Documents/"))
>   (with-temp-buffer
>     (message "dv %s" (default-value 'default-directory))
>     (message "lv %s" default-directory)))
>
> So to make use of this, every relevant spot would have to look up the
> global value of this var manually. Might as well use the special var
> that we already have (...-override).

Sad!