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

From: Eli Zaretskii <[email-masked]>
Date: Sat, 14 Jun 2025 17:51:22 +0300

> From: Jimmy Yuen Ho Wong <[email-masked]>
> Date: Thu, 12 Jun 2025 20:34:30 +0100
> Cc: [email-masked]
> 
> On Thu, Jun 12, 2025 at 7:19 PM Eli Zaretskii <[email-masked]> wrote:
> 
>  > From: Jimmy Yuen Ho Wong <[email-masked]>
>  > Date: Thu, 12 Jun 2025 17:58:34 +0100
>  > 
>  > 
>  > When investigating https://github.com/emacs-lsp/lsp-mode/issues/4782 and
>  > https://github.com/purcell/emacs-reformatter/issues/63, I've discovered
>  > the following bug in insert-file-contents.
>  > 
>  > Reproduction:
>  > 
>  > 1. echo "hello world" > ~/test.txt
>  > 2. emacs -q ~/test.txt
>  > 3. M-x eval-expression RET (add-hook 'after-change-functions (lambda (&rest _) (message
>  "buffer-file-name: %s, current-buffer: %s" (buffer-file-name) (current-buffer))) nil t) RET
>  > 4. Type something into the buffer
>  > 5. M-x eval-expression RET (insert-file-contents (buffer-file-name) nil nil nil t) RET
>  > 6. Switch to the *Messages* buffer and observe the buffer file name is nil.
>  > 
>  > Expectation:
>  > 
>  > insert-file-contents should not set buffer-file-name to nil
> 
>  I don't think it does.  (buffer-file-name) returns nil when the call
>  is evaluated in the minibuffer, and I thin that's what you see.  After
>  performing the above recipe the buffer-filename of the buffer that
>  visits test.txt remains to be "test.txt", at least in my testing.  So
>  the only evidence that it's set to nil are the messages logged in
>  *Messages*, and they are about a different buffer.
> 
> When a lisp expression is evaluated in the minibuffer, the current buffer is the file buffer, not the minibuffer.
> You can easily verify this with M-x eval-expression RET (current-buffer)  RET.
> 
> The crux of the matter is the lambda added to after-change-function. `insert-file-contents` calls
> `signals_after_change` (fileio.c line 5007 on master), which will run the after-change-functions. It is at this
> moment the buffer-file-name is nil.
> 
> In addition, the following will NOT result in insert-file-contents temporarily setting the buffer-file-name of the
> current buffer to nil:
> 
> (let ((coding-system-for-read 'no-conversion)
>       (coding-system-for-write 'no-conversion))
>   (insert-file-contents (buffer-file-name) nil nil nil t))
> 
> Which suggests some of the code conversion logic in the C function is erroneously setting the current
> buffer's file-name to nil, and then running the after-change-functions before resetting it.

I think your after-change-function is called not due to
insert-file-contents inserting the text from the file, but from the
functions that decode the file's text.  To see if this is true, make
your after-change-function show the name of the current buffer.  If
I'm right, you will see something like " *code conversion works" as
the name of the buffer, in which case indeed buffer-filename is
expected to be nil, and I don't see a bug here.