Subject: bug#78777: 30.1; insert-file-contents should not set buffer-file-name to nil

From: Jimmy Yuen Ho Wong <[email-masked]>
Date: Mon, 16 Jun 2025 13:19:08 +0100

On Mon, Jun 16, 2025 at 10:09 AM Eli Zaretskii <[email-masked]> wrote:

> > From: Jimmy Yuen Ho Wong <[email-masked]>
> > Date: Sun, 15 Jun 2025 17:30:47 +0100
> > Cc: [email-masked]
> >
> >  I understand what you are saying, but not why you think it's a bug.
> >  Once again, the call to after-change-functions in this scenario is
> >  done not from insert-file-contents, but from the function that decodes
> >  the text read from the file.  That function runs in a temporary
> >  buffer, which has no associated file name.
> >
> > Because the docstring of after-change-functions says the hooks are
> called with the current buffer, and the
> > current buffer at the time insert-file-contents is called, is the file
> buffer, not the code conversion buffer. The
> > message printed out also indicated that the current buffer at the time
> the after-change-functions lambda is
> > called is indeed the file buffer, not the code conversion buffer. The
> file buffer's buffer-file-name should not
> > be set to nil by insert-file-contents or any function it calls. As far
> as I know, only `insert-file-contents` exhibits
> > this undocumented behavior for any functions that change buffer contents.
>
> OK, I see what happens.  insert-file-contents intentionally binds
> buffer-file-name temporarily to nil when it is called with REPLACE
> non-nil, during the deletion or insertion from the code-conversion
> buffer.  It does that to avoid prompting the user via
> ask-user-about-supersession-threat, which in this case will confuse.
>
> So this is a feature, an intentional behavior.
>

This is one silly hack. If the intention is to suppress some file lock
interactive functions, isn't the Emacs convention to use some kind of
inhibit-* variable? In my case, I don't even use file locks, I've
set create-lockfiles permanantly to nil, there's no reason that any file
lock related functions should be run at all.

Can userlock--ask-user-about-supersession-threat be modified to check for
create-lockfiles and a newly introduced inhibit-file-lock internal variable
before running userlock--check-content-unchanged?

This change also seems to have been introduced to before-change-functions
are called at the right time
<https://lists.gnu.org/archive/html/bug-gnu-emacs/2016-08/msg01029.html>,
perhaps we should ask Stefan what the best thing to do here is.

>
> > The guarantee of after-change-functions being called with the current
> buffer isn't very useful if crucial
> > variables of the current buffer such as the buffer file name cannot also
> be guaranteed to remain the same.
> > This use case is illustrated by the tickets I linked to in my original
> report. There exist many file formatter
> > packages that replace the content of the current buffer with a temporary
> file with the formatted file content
> > inside a before-save-hook due to slowness of replace-buffer-content.
> When these packages are used in
> > combination with lsp-mode, which has a function added to
> after-change-functions that needs access to the
> > current buffer's file name in order to synchronize the document between
> the editor and the language server.
>
> I suggest that buffer-modification hooks use buffer-file-truename
> instead, it will provide the correct file name in this (and other)
> cases.
>

This is not ideal. The Language Server Protocol does not specify how to
handle symlinks, there is no guarantee that file content changes to the
source of a symlink will also change the target, which as far as the
language server is concerned, can very well be just 2 regular files.

In addition, the expectation is that unless the user has explicitly changed
the buffer-file-name by renaming the buffer and/or file,
buffer-file-name should remain unmodified at all times from the user's
perspective. Examining buffer-file-truename should only be used as a crutch
to look up the target of a file symlink quickly without hitting the disk.
Both of the above scenarios are not what's happening here.
insert-file-content is simply writing to a buffer and
after-change-functions are simply reacting to changes in the buffer, not
the file on disk.