]> git.eshelyaron.com Git - emacs.git/commitdiff
Support state changing VC operations on directories in Dired (bug#34949)
authorJuri Linkov <juri@linkov.net>
Sun, 29 Mar 2020 22:34:47 +0000 (01:34 +0300)
committerJuri Linkov <juri@linkov.net>
Sun, 29 Mar 2020 22:34:47 +0000 (01:34 +0300)
* lisp/dired-aux.el (dired-vc-next-action): New command.
(dired-vc-deduce-fileset): Rename from vc-dired-deduce-fileset in vc.el.

* lisp/dired.el (dired-mode-map): Remap vc-next-action to
dired-vc-next-action.

* lisp/vc/vc-dir.el (vc-dir-mark-files): New function.
(vc-dir-refresh): Run hook vc-dir-refresh-hook.

* lisp/vc/vc.el (vc-deduce-fileset): Rename arg 'observer' to
'not-state-changing' and document it in docstring.
(vc-dired-deduce-fileset): Rename to dired-vc-deduce-fileset in dired-aux.el.

* lisp/cedet/ede.el (ede-turn-on-hook, ede-minor-mode):
* lisp/desktop.el (desktop-minor-mode-table): Rename the long ago
obsolete vc-dired-mode to vc-dir-mode.

etc/NEWS
lisp/cedet/ede.el
lisp/desktop.el
lisp/dired-aux.el
lisp/dired.el
lisp/vc/vc-dir.el
lisp/vc/vc.el

index 4b477e5def60371277cf6b3ac953d81006b6224c..bb5f549a2e207bcceea9ddb8d4af167c4dbb0697 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -108,8 +108,8 @@ Mark mode, then Dired commands operate only on files in the active
 region.  The values 'file' and 'line' of this user option define the
 details of marking the file at the end of the region.
 
-*** State changing VC operations are supported in 'dired-mode' on files
-(but still not on directories).
+*** State changing VC operations are supported in Dired on files and
+directories with the help of new command 'dired-vc-next-action'.
 
 ** Change Logs and VC
 
index c2036878288bf3a8161b5ab2a3b97c1f640d9da1..8c336117c9241993166ec46a741d00a633d82676 100644 (file)
@@ -470,7 +470,7 @@ To be used in hook functions."
          ;; Emacs 21 has no buffer file name for directory edits.
          ;; so we need to add these hacks in.
          (eq major-mode 'dired-mode)
-         (eq major-mode 'vc-dired-mode))
+         (eq major-mode 'vc-dir-mode))
       (ede-minor-mode 1)))
 
 (define-minor-mode ede-minor-mode
@@ -481,7 +481,7 @@ controlled project, then this mode is activated automatically
 provided `global-ede-mode' is enabled."
   :group 'ede
   (cond ((or (eq major-mode 'dired-mode)
-            (eq major-mode 'vc-dired-mode))
+            (eq major-mode 'vc-dir-mode))
         (ede-dired-minor-mode (if ede-minor-mode 1 -1)))
        (ede-minor-mode
         (if (not ede-constructing)
index de601a4de8ca49f1c2f952ac7f29a318b4e716eb..9d117c6f0d6d996214c2bf0c7879947155f671c5 100644 (file)
@@ -534,7 +534,7 @@ can guess how to load the mode's definition.")
   '((defining-kbd-macro nil)
     (isearch-mode nil)
     (vc-mode nil)
-    (vc-dired-mode nil)
+    (vc-dir-mode nil)
     (erc-track-minor-mode nil)
     (savehist-mode nil))
   "Table mapping minor mode variables to minor mode functions.
index 6f50a3da6caa3825f4909536ff2a781d5a63d7cf..60a352d78e02f40f4630958243977e515a969322 100644 (file)
@@ -3050,6 +3050,68 @@ instead."
        (backward-delete-char 1))
       (message "%s" (buffer-string)))))
 
+\f
+;;; Version control from dired
+
+(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))))
+
+(declare-function vc-compatible-state "vc")
+
+(defun dired-vc-deduce-fileset (&optional state-model-only-files not-state-changing)
+  (let ((backend (vc-responsible-backend default-directory))
+        (files (dired-get-marked-files nil nil nil nil t))
+        only-files-list
+        state
+        model)
+    (when (and (not not-state-changing) (cl-some #'file-directory-p files))
+      (user-error "State changing VC operations on directories supported only in `vc-dir'"))
+
+    (when state-model-only-files
+      (setq only-files-list (mapcar (lambda (file) (cons file (vc-state file))) files))
+      (setq state (cdar only-files-list))
+      ;; Check that all files are in a consistent state, since we use that
+      ;; state to decide which operation to perform.
+      (dolist (crt (cdr only-files-list))
+        (unless (vc-compatible-state (cdr crt) state)
+          (error "When applying VC operations to multiple files, the files are required\nto  be in similar VC states.\n%s in state %s clashes with %s in state %s"
+                 (car crt) (cdr crt) (caar only-files-list) state)))
+      (setq only-files-list (mapcar 'car only-files-list))
+      (when (and state (not (eq state 'unregistered)))
+        (setq model (vc-checkout-model backend only-files-list))))
+    (list backend files only-files-list state model)))
+
+\f
 (provide 'dired-aux)
 
 ;; Local Variables:
index 41bbf9f56a219000dff743b706a90d2a3f0c7add..72d1cc250a338e241aff62da46a686de6ae9e626 100644 (file)
@@ -1870,6 +1870,7 @@ Do so according to the former subdir alist OLD-SUBDIR-ALIST."
     (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)
index b760e1706769407e8d57ddad528930981448e14a..ab5943917b8f040f0067a08bb6407944ed9c67e5 100644 (file)
@@ -696,6 +696,17 @@ share the same state."
                (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.
+MARK-FILES should be a list of absolute filenames."
+  (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 +1204,8 @@ Throw an error if another update process is in progress."
                    (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.
index 607fb37807cc4532f57e164a2f43b8d232d14baf..d4323d59eb35eb401ebe8561bea61af0f5f57857 100644 (file)
@@ -1006,12 +1006,18 @@ Within directories, only files already under version control are noticed."
 
 (declare-function vc-dir-current-file "vc-dir" ())
 (declare-function vc-dir-deduce-fileset "vc-dir" (&optional state-model-only-files))
+(declare-function dired-vc-deduce-fileset "dired-aux" (&optional state-model-only-files not-state-changing))
 
-(defun vc-deduce-fileset (&optional observer allow-unregistered
+(defun vc-deduce-fileset (&optional not-state-changing
+                                   allow-unregistered
                                    state-model-only-files)
   "Deduce a set of files and a backend to which to apply an operation.
 Return (BACKEND FILESET FILESET-ONLY-FILES STATE CHECKOUT-MODEL).
 
+NOT-STATE-CHANGING if non-nil, means that the operation
+requesting the fileset doesn't intend to change VC state,
+such as printing the log or showing the diff.
+
 If we're in VC-dir mode, FILESET is the list of marked files,
 or the directory if no files are marked.
 Otherwise, if in a buffer visiting a version-controlled file,
@@ -1025,14 +1031,12 @@ the FILESET-ONLY-FILES STATE and MODEL info.  Otherwise, that
 part may be skipped.
 
 BEWARE: this function may change the current buffer."
-  ;; FIXME: OBSERVER is unused.  The name is not intuitive and is not
-  ;; documented.  It's set to t when called from diff and print-log.
   (let (backend)
     (cond
      ((derived-mode-p 'vc-dir-mode)
       (vc-dir-deduce-fileset state-model-only-files))
      ((derived-mode-p 'dired-mode)
-      (vc-dired-deduce-fileset state-model-only-files observer))
+      (dired-vc-deduce-fileset state-model-only-files not-state-changing))
      ((setq backend (vc-backend buffer-file-name))
       (if state-model-only-files
        (list backend (list buffer-file-name)
@@ -1048,7 +1052,7 @@ BEWARE: this function may change the current buffer."
                                      (derived-mode-p 'dired-mode)))))
       (progn                  ;FIXME: Why not `with-current-buffer'? --Stef.
        (set-buffer vc-parent-buffer)
-       (vc-deduce-fileset observer allow-unregistered state-model-only-files)))
+       (vc-deduce-fileset not-state-changing allow-unregistered state-model-only-files)))
      ((and (derived-mode-p 'log-view-mode)
           (setq backend (vc-responsible-backend default-directory)))
       (list backend nil))
@@ -1065,32 +1069,6 @@ BEWARE: this function may change the current buffer."
              (list buffer-file-name))))
      (t (error "File is not under version control")))))
 
-(declare-function dired-get-marked-files "dired"
-                  (&optional localp arg filter distinguish-one-marked error))
-
-(defun vc-dired-deduce-fileset (&optional state-model-only-files observer)
-  (let ((backend (vc-responsible-backend default-directory))
-        (files (dired-get-marked-files nil nil nil nil t))
-       only-files-list
-       state
-       model)
-    (when (and (not observer) (cl-some #'file-directory-p files))
-      (error "State changing VC operations on directories not supported in `dired-mode'"))
-
-    (when state-model-only-files
-      (setq only-files-list (mapcar (lambda (file) (cons file (vc-state file))) files))
-      (setq state (cdar only-files-list))
-      ;; Check that all files are in a consistent state, since we use that
-      ;; state to decide which operation to perform.
-      (dolist (crt (cdr only-files-list))
-       (unless (vc-compatible-state (cdr crt) state)
-         (error "When applying VC operations to multiple files, the files are required\nto  be in similar VC states.\n%s in state %s clashes with %s in state %s"
-                (car crt) (cdr crt) (caar only-files-list) state)))
-      (setq only-files-list (mapcar 'car only-files-list))
-      (when (and state (not (eq state 'unregistered)))
-       (setq model (vc-checkout-model backend only-files-list))))
-    (list backend files only-files-list state model)))
-
 (defun vc-ensure-vc-buffer ()
   "Make sure that the current buffer visits a version-controlled file."
   (cond