3

How can I check, with a function, if there are marked files in a dired buffer?

Edit. The issue with dired-get-marked-files is that if the user moves the cursor on a "current file name" the function does not return nil.

What about (string-match-p "^\\*" (buffer-string))? Is it so bad?

3
  • dired-number-of-marked-files returns a string that is useful interactively, but you probably want to use the underlying function dired-get-marked-files, but you'll need to get rid of the current file name: AFAICT, if no files are marked, the file on the current line is always returned).
    – NickD
    Apr 14, 2023 at 20:00
  • I edited my question.
    – Gabriele
    Apr 14, 2023 at 20:41
  • The string-match-p looks reasonable to me for the yes/no question. If you want the actual number, see my answer.
    – NickD
    Apr 14, 2023 at 21:45

2 Answers 2

5

One quick way is to just use this, since you apparently don't want to consider the file of the current line as marked if it's not:

(dired-remember-marks (point-min) (point-max))

A more general answer is to use function dired-get-marked-files. If there are marked files it returns their names as a list. But since most uses of it are to get file names, to do something with them, it also returns the name of the current line's file, if no files are marked. If you don't want that, see above or at the end of my answer.

That's the usual Lisp way: return a useful non-nil value for "true". It costs nothing and is far more useful than just learning that there are some marked files.

C-h f dired-get-marked-files. Here's the description from Dired+:

dired-get-marked-files is a compiled Lisp function in dired+.el.

(dired-get-marked-files &optional LOCALP ARG FILTER DISTINGUISH-ONE-MARKED ERROR-IF-NONE-P)

Return names of the marked files and directories as a list of strings.

The list is in the same order as the buffer, that is, the car is the first marked file.

Values returned are normally absolute file names.

  • Optional arg LOCALP as in dired-get-filename. *Optional second argument ARG specifies files to use instead of marked. Usually ARG comes from the command's prefix arg.

If ARG is an integer, use the next ARG files (previous -ARG, if < 0). (1 means file on current line. -1 means file on previous line.)

If ARG is a cons with element 16, 64, or 256, corresponding to C-u C-u, C-u C-u C-u, or C-u C-u C-u C-u, then use all files in the Dired buffer, where:

  • 16 includes NO directories (including . and ..)
  • 64 includes directories EXCEPT . and ..
  • 256 includes ALL directories (including . and ..)

If ARG is otherwise non-nil, use the current file.

Optional third argument FILTER, if non-nil, is a function to select some of the files: those for which (funcall FILTER FILENAME) is non-nil.

If DISTINGUISH-ONE-MARKED is non-nil, then return (t FILENAME) instead of (FILENAME) if only one file is marked (after any filtering by FILTER).

If ERROR-IF-NONE-P is non-nil, signal an error if the list of files is empty. If ERROR-IF-NONE-P is a string then it is the error message.

Note that the Dired+ version of this function differs from the vanilla version in these respects:

  • There are more possibilities for argument ARG (prefix argument).
  • Directories . and .. can be included as marked.
  • You can use arguments FILTER and DISTINGUISH-ONE-MARKED together.

And here's the vanilla Emacs version:

dired-get-marked-files is a byte-compiled Lisp function in dired.el.

(dired-get-marked-files &optional LOCALP ARG FILTER DISTINGUISH-ONE-MARKED ERROR)

Return the marked files’ names as list of strings.

The list is in the same order as the buffer, that is, the car is the first marked file.

Values returned are normally absolute file names.

Optional arg LOCALP as in dired-get-filename’.

Optional second argument ARG, if non-nil, specifies files near point instead of marked files. It usually comes from the prefix argument.

  • If ARG is an integer, use the next ARG files.
  • If ARG is any other non-nil value, return the current file name.
  • If no files are marked, and ARG is nil, also return the current file name.

Optional third argument FILTER, if non-nil, is a function to select some of the files--those for which (funcall FILTER FILENAME) is non-nil.

If DISTINGUISH-ONE-MARKED is non-nil, then if we find just one marked file, return (t FILENAME) instead of (FILENAME). Don’t use that together with FILTER.

If ERROR is non-nil, signal an error when the list of found files is empty. ERROR can be a string with the error message.


Wrt your "evolved" question (please don't do that): here are two alternatives.

  1. Just use this:
(dired-remember-marks (point-min) (point-max))

C-h f dired-remember-marks.

  1. Read the doc for dired-get-marked-files. It too can give you what you want. If you want nil to be returned when there are no marks, rather than returning the file of the current line, just use this:
(defun my-get-marked (localp arg filter error)
  "..."
  (let ((res  (dired-get-marked-files localp arg filter t error)))
    (if (and res  (null (cdr res)))
        nil
      res)))
6
  • I thought about dired-get-marked-files. Please look at my edited question.
    – Gabriele
    Apr 14, 2023 at 20:42
  • @Drew: the problem with the convention of returning always something useful from dired-get-marked-files is the misleading function name. dired-get-file-at-point-plus-marked-files would be a much better name saving time of looking up what it actually does.
    – Claudio
    Apr 15, 2023 at 9:15
  • @Drew: what about proposing a patch to dired changing the behavior of dired-get-marked-files and extending it with dired-get-file-at-point-plus-marked-files instead of suggesting usage of own function?
    – Claudio
    Apr 15, 2023 at 9:34
  • As I wrote, there already is a function to do what you asked: dired-remember-marks. The point about dired-get-marked-files is that it's used to, yes, actually get a list of files, and a very common use case is to get the current-line file when no file is marked. dired-do-* commands all work that way: act on the current-line file if no numeric prefix arg is given and no files are marked. I only showed you how you can also use dired-get-marked-files to give you nil when no files are marked.
    – Drew
    Apr 15, 2023 at 14:41
  • 1
    dired-remember-marks also has the advantage of returning the mark associated with each file (e.g. files marked with D as well as those marked with *).
    – NickD
    Apr 15, 2023 at 14:43
2

dired-number-of-marked-files returns a string and is most useful interactively because of that. But its implementation uses dired-get-marked-files which returns a list of marked files - if there are marked files. But it returns the current file (i.e. whatever your cursor is on), not nil if there are no marked files. To distinguish these cases, there is an optional argument DISTINGUISH-ONE-MARKED that modifies the output in this case: if the current file is marked, then dired-get-marked-files returns (t FILENAME) instead of (FILENAME). All of this is from C-h f dired-get-marked-files.

Here's the code that calculates the number of marked files then (lifted directly from the implementation of dired-number-of-marked-files):

(defun my/dired-number-of-marked-files ()
  (let* ((files (dired-get-marked-files nil nil nil t))
         (nmarked
          (cond ((null (cdr files))
                 0)
                ((and (= (length files) 2)
                      (eq (car files) t))
                 1)
                (t
                 (length files)))))
    nmarked))

That returns the integer that dired-number-of-marked-files uses to construct its message, so you figure out whether there are marked files with something like this:

   (when (> (my/dired-number-of-marked-files) 0)
      ;; there be marked files here
      ...)
2
  • Wouldn't it be better to suggest a patch to dired changing the behavior of the dired-number-of-marked-files providing an additional dired-number-of-marked-plus-file-at-point to avoid all this hassle?
    – Claudio
    Apr 15, 2023 at 9:31
  • @Claudio: feel free to do so.
    – NickD
    Apr 15, 2023 at 14:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.