Subject: Re: bug#70996: project-find-file defaults

From: Spencer Baugh <[email-masked]>
Date: Tue, 11 Jun 2024 20:11:28 -0400

Dmitry Gutov <[email-masked]> writes:

> On 09/06/2024 19:51, Juri Linkov wrote:
>>>> But the problem is that in this case it drops the current file name
>>>> as the default value that is also useful in many cases.
>>>> Fortunately, the minibuffer supports a list of default values,
>>>> like in the following patch:
>>>
>>> This seems like a good idea, except it reverses the priority: previously,
>>> if file-at-point was present, it would be the default, not the current file
>>> name.
>> I mentioned in the log message that this change was intentional.
>> 
>>> So how about this?
>> The reason of this change to make the first item of the M-n list
>> more deterministic:
>
> Okay, now I see that line, thanks.
>
>> 1. when there is no thing-at-point, then the first item will be
>>     buffer-file-name;
>> 2. and also when there is a thing-at-point, the first item
>>     will remain buffer-file-name.
>> Otherwise, it was too unpredictable: after typing 'M-n RET'
>> to use buffer-file-name, it often did a wrong thing
>> when point happened to stay in a thing-at-point.
>
> Okay, but I'm not sure predictability must be the overriding principle.
>
> If 10 people use the thing-at-point default, for example, and only 2
> use the buffer-file-name default (or, say, the number of users is the
> same, but the frequency is higher for the latter), we'd be forcing a
> lot of people to press C-n to jump over the default they don't use.

It seems to me that we can have the best of both worlds if we match the
behavior of find-file, and use something like
(run-hook-with-args-until-success 'file-name-at-point-functions) rather
than (thing-at-point 'file-name).

The default of file-name-at-point-functions is
ffap-guess-file-name-at-point, which by default only returns a filename
if that file name actually exists in the filesystem.

The old behavior of (thing-at-point 'file-name) often got in the way,
since it would pick up any random string at point, even if it wasn't
referring to an actual file name.

Instead we can be like find-file and have:

(delq nil (list
  (run-hook-with-args-until-success 'file-name-at-point-functions)
  buffer-file-name))

So the file name at point *does* take precedence over
buffer-file-name... but the file name at point is only present when it's
actually useful - that is, when the file exists.

This is especially useful now that there is ffap-in-project by default,
so ffap-guess-file-name-at-point will pick up relative file names in the
project root.

I personally never use the file-name-at-point behavior of
project-find-file, but I'm happy with it being higher-precedence because
it will match find-file - as long as it also matches find-file in only
including filenames of existing files.

> What's the main usage scenario for the buffer-file-name default? I
> recall Spencer describing his workflow, but that seems only useful
> when you have a lot of branches, checked out specifically into
> worktrees or similar, and switch between them often (while explicitly
> staying in the "same" file during a switch). Do you do something
> similar?

For me, two use cases:

1. Copy project-relative filename:
   C-x p f M-n C-a C-k

2. Switch to the same file in another project:
   C-x p p [type project name] f M-n RET

About half of my use for 2 is switching between my emacs-29 and trunk
git worktrees.  (The other half is switching between checkouts of
branches in Jane Street's internal monorepo)