Subject: Re: bug#65854: Multi-file replacement diff

From: Eshel Yaron <[email-masked]>
Date: Mon, 11 Sep 2023 09:23:37 +0200

Hi Juri,

Juri Linkov <[email-masked]> writes:

>>> +(defun multi-file-replace-as-diff (files-or-buffers from-string replacements regexp-flag delimited-flag)
>>> +  (require 'diff)
>>> +  (let ((inhibit-message t)
>>> +        (diff-buffer (get-buffer-create "*replace-diff*")))
>>> +    (with-current-buffer diff-buffer
>>> +      (buffer-disable-undo (current-buffer))
>>> +      (let ((inhibit-read-only t))
>>> +        (erase-buffer))
>>> +      (diff-mode))
>>> +    (dolist (file-or-buffer files-or-buffers)
>>> +      (let ((file-name (if (bufferp file-or-buffer) buffer-file-name file-or-buffer)))
>>> +        (when file-name
>>> +          (with-temp-buffer
>>> +            (if (bufferp file-or-buffer)
>>> +                (insert-buffer-substring file-or-buffer)
>>> +              (insert-file-contents file-or-buffer))
>>
>> I wonder what happens if I call `multi-file-replace-regexp-as-diff` and
>> select a file `foo.txt`, that I already have open and modified in a
>> buffer.  IIUC, this will generate the diff based on the contents of the
>> file on disk, not the buffer, so it might not match when I subsequently
>> try to apply the diff to the buffer.  WDYT?
>
> For such cases you can use multi-buffer-replace-regexp-as-diff
> from this patch instead of multi-file-replace-regexp-as-diff.

Well, in the simple example of one file, yes that possible, but the
point is that you don't always know (or worry about) whether there's an
overlap between the files you have open and modified and the files your
regexp/wildcard matches.  Let's say I'm editing an HTML file, and find
something that I'd like to change.  So I do it.  Than I think "actually,
let's change that across all my HTML files in this directory".  IMO It
would be great if I could use this new command,
`multi-file-replace-regexp-as-diff`, to get a diff showing how that'd
look.  But in the proposed implementation, that won't work if one of
those HTML files is open and modified--without any warning, Emacs would
create a diff that doesn't apply.

> The former generates the diff based on the contents of the
> file in the buffer, the latter uses the contents on disk.

Yes, but what is the use case for generating the diff based on the
contents on disk when the file is modified in Emacs?  Basically, my
suggestion is to check in `multi-file-replace-regexp-as-diff` if any of
the matching files are visited by some buffer, and if so simply pass the
buffer instead of the file name for that file to
`multi-file-replace-as-diff`.  That way you always get an up-to-date
diff, and you don't need to manually check that you don't have any of
the matching files open by any chance.  Does that make sense?