Subject: bug#34949: 27.0.50; Docstring of `vc-deduce-fileset' incomplete

From: Juri Linkov <[email-masked]>
Date: Wed, 25 Mar 2020 22:47:11 +0200

> All this works fine with the patch below.  The only part of the patch
> that I don't like is too much code in the first part of vc-dir-mark-files
> that just resolves discrepancy between Dired and VC-Dir:
> dired-get-marked-files returns directory names without the trailing slash,
> but vc-dir-fileinfo->name returns directories with the trailing slash.

Ok, here's the patch that fixes these problems.

It moves that ugly piece of code to dired-vc-next-action
(see the comment "Fix deficiency of Dired by adding slash to dirs")

The problem is that dired-get-marked-files returns directory names
as they are displayed in the Dired buffer i.e. where directories are
without the trailing slash.

It's possible to append the trailing slash by adding the switch
"-p" to dired-listing-switches:

  ls -p, --indicator-style=slash append / indicator to directories

But Dired doesn't support trailing slashes because
dired-goto-file can't find directory lines with slashes.
Therefore the need for ugly code in dired-vc-next-action.

Anyway, this is the final version of this feature:

diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 6f50a3da6c..ce192269fc 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -3050,6 +3050,41 @@ dired-show-file-type
 	(backward-delete-char 1))
       (message "%s" (buffer-string)))))
 
+
+(declare-function vc-dir-unmark-all-files "vc-dir")
+(declare-function vc-dir-mark-files "vc-dir")
+
+;;;###autoload
+(defun dired-vc-next-action (verbose)
+  "Do the next version control operation on marked files/directories.
+When only files are marked then call `vc-next-action' with the
+same value of the VERBOSE argument.
+When also directories are marked then call `vc-dir' and mark
+the same files/directories in the VC-Dir buffer that were marked
+in the Dired buffer."
+  (interactive "P")
+  (let* ((marked-files
+          (dired-get-marked-files nil nil nil nil t))
+         (mark-files
+          (when (cl-some #'file-directory-p marked-files)
+            ;; Fix deficiency of Dired by adding slash to dirs
+            (mapcar (lambda (file)
+                      (if (file-directory-p file)
+                          (file-name-as-directory file)
+                        file))
+                    marked-files))))
+    (if mark-files
+        (let ((transient-hook (make-symbol "vc-dir-mark-files")))
+          (fset transient-hook
+                (lambda ()
+                  (remove-hook 'vc-dir-refresh-hook transient-hook t)
+                  (vc-dir-unmark-all-files t)
+                  (vc-dir-mark-files mark-files)))
+          (vc-dir-root)
+          (add-hook 'vc-dir-refresh-hook transient-hook nil t))
+      (vc-next-action verbose))))
+
+
 (provide 'dired-aux)
 
 ;; Local Variables:
diff --git a/lisp/dired.el b/lisp/dired.el
index 41bbf9f56a..51aaf6b01d 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -1870,6 +1870,7 @@ dired-mode-map
     (define-key map "\177" 'dired-unmark-backward)
     (define-key map [remap undo] 'dired-undo)
     (define-key map [remap advertised-undo] 'dired-undo)
+    (define-key map [remap vc-next-action] 'dired-vc-next-action)
     ;; thumbnail manipulation (image-dired)
     (define-key map "\C-td" 'image-dired-display-thumbs)
     (define-key map "\C-tt" 'image-dired-tag-files)
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index 38b4937e85..0da702e3f4 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -696,6 +707,16 @@ vc-dir-mark-all-files
 		(vc-dir-mark-file crt)))
 	    (setq crt (ewoc-next vc-ewoc crt))))))))
 
+(defun vc-dir-mark-files (mark-files)
+  "Mark files specified by file names in the argument MARK-FILES."
+  (ewoc-map
+   (lambda (filearg)
+     (when (member (expand-file-name (vc-dir-fileinfo->name filearg))
+                   mark-files)
+       (setf (vc-dir-fileinfo->marked filearg) t)
+       t))
+   vc-ewoc))
+
 (defun vc-dir-unmark-file ()
   ;; Unmark the current file and move to the next line.
   (let* ((crt (ewoc-locate vc-ewoc))
@@ -1193,7 +1214,8 @@ vc-dir-refresh
                    (if remaining
                        (vc-dir-refresh-files
                         (mapcar 'vc-dir-fileinfo->name remaining))
-                     (setq mode-line-process nil))))))))))))
+                     (setq mode-line-process nil)
+                     (run-hooks 'vc-dir-refresh-hook))))))))))))
 
 (defun vc-dir-show-fileentry (file)
   "Insert an entry for a specific file into the current *VC-dir* listing.