Subject: bug#75626: 31.0.50; Dired misses or double-processes files when auto-revert-mode is enabled

From: Drew Adams <[email-masked]>
Date: Mon, 20 Jan 2025 00:24:41 +0000

> The context is that commands like dired-do-compress which use
> dired-map-over-marks can skip or double-process marked files in case the
> dired buffer is reverted during the operation by auto-revert-mode (most
> likely because the sorting order changes due to the suffix .gz being
> removed or added).

As the doctor says, when the patient says it hurts
if he bangs his head on the wall: "Don't do that." ;-)

> > The doc string, and how those two are used in
> > the code, tell you the answer.
> >
> > `dired-get-marked-files' just gives you a list
> > of the marked files.  `dired-map-over-marks'
> > is a macro, not a function, and it _processes_
> > the files.
> 
> Ok, I should have said: why do some dired commands use
> dired-get-marked-files together with some loop, and a processing
> function while others use dired-map-over-marks with the processing code
> as body?  I mean, both approaches do essentially the same but only the
> latter is subject of the issue I've reported.

`dired-get-marked-files' is defined using
`dired-map-over-marks'.  The latter is more general
and more basic.

You use the former to get a list of file names -
the files marked in the buffer.

The latter isn't just about file names.  It's about
the markings, and even the state of the Dired
buffer.  You can do anything you want, as you map
over the marked _lines_.

(But it seems from this bug report that one
shouldn't try to revert the buffer etc.  To me, that
makes sense, since the macro is explicitly about the
current state of the buffer - its markings etc.
Depending on the revert function/behavior that could
change that state.)

> Is there some example dired command that can only work with
> dired-map-over-marks and not by collecting all marked files at the
> beginning?

See below, for general info.  One example is command
`dired-do-flagged-delete'.

> It would need to be something where the processing code
> marks files that haven't been marked before.

Not at all.  It could depend on the sort order
of the listing, etc., since it _processes_ the
marked lines _in order_.  More generally, it
could depend other ways on the current Dired
display.  It's about going to the marked _lines_,
in order, and doing something on each line.  It
need not do anything with the files listed on
those lines.  It could report on how the buffer
displays their mod time or size...

Function `dired-get-marked-files' just gives
you a list of file names, which you can process
in any order.

> But I can't think of an example where that would be desired.

Did you look at the functions that are defined
using macro `dired-map-over-marks'?  Functions
such as `dired-do-redisplay' explicitly have to
do with the buffer display.  (I don't claim that
each such function needs to be defined using
that macro, but its not a bad bet that it does.)

`image-dired-dired-insert-marked-thumbs' inserts
thumbnails before the file names on the marked
lines.  Again, it's about the displayed Dired
buffer.

Function `dired-map-over-marks-check' processes
the marked lines, in order, reporting on errors
from invoking a function on each of them.  The
function need not act on the file that's marked
at all; it can take any arguments and do anything.

Similarly for other functions that use the macro.

Another use is in commands that you want to act
on the marked files - OR, if none are marked, on
the file of the current line.  Yes, sometimes
you could use `dired-get-marked-files' for that.
But there's difference between a currently marked
file name in a listing (let alone a marked line,
which is really what it's about) and a file.

The listing might not even correspond currently
with the state of the file system.  You could
use the macro to do something for files that no
longer exist, provided they're still listed -
so yeah, you might not want the command to
allow reversion.  (I don't know how to prevent
reversion, but I suppose you could make and
restore a copy of the buffer. ;-))

Yet another use case is wanting to do something
on the lines marked with a char other than `*'.

That's used, for instance, in the definition of
`dired-do-flagged-delete'.  It couldn't use
`dired-get-marked-files' to do what it does.
E.g., try using this command to get you a list
of the files marked for deletion (i.e., `D'):

(defun foo ()
  (interactive)
  (let ((dired-marker-char 42))
    (message "%S" (dired-get-marked-files))))

Doesn't work - it always gives you the files
marked `*' (or the file of the current line, 
if none are marked `*').
___

You could ask the same question about using
function `dired-map-over-marks-check' versus
using `dired-get-marked-files'.  And pretty
much the same answer is relevant, I think:
processing marked lines, in the current sort
order, versus just getting a list of files.

(In Dired+ I use `dired-map-over-marks-check'
often.  I use `dired-map-over-marks' much
less often.)
___

BTW, `dired-do-compress' uses function
`dired-map-over-marks-check', not macro
`dired-map-over-marks'.  Indirectly, it
uses the latter, of course.
___

The point is that if you need only a list
of the files marked `*' then you can use
`dired-get-marked-files'.  If you need only
what `dired-map-over-marks-check' does,
then you can use that.  If you need what
macro `dired-map-over-marks' does, then use
that.