1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-27 07:37:33 +00:00

Support state changing VC operations on directories in Dired (bug#34949)

* 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.
This commit is contained in:
Juri Linkov 2020-03-30 01:34:47 +03:00
parent 1276c8e10b
commit 7a6f5a5167
7 changed files with 90 additions and 37 deletions

View File

@ -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

View 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)

View 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.

View File

@ -3050,6 +3050,68 @@ instead."
(backward-delete-char 1))
(message "%s" (buffer-string)))))
;;; 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)))
(provide 'dired-aux)
;; Local Variables:

View 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)

View 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.

View 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