# HG changeset patch # User Stefan Monnier # Date 1271815524 14400 # Node ID 17d3324f96dd384944718a26ee2c5f7612560a51 # Parent 3ccddf080698dd41e5c3832b11216948fc7555db Make the log-edit comments use RFC822 format throughout. * vc.el (vc-checkin, vc-modify-change-comment): Adjust to new vc-start/finish-logentry. (vc-find-conflicted-file): New command. (vc-transfer-file): Adjust to new vc-checkin. (vc-next-action): Improve scoping. * vc-hg.el (vc-hg-log-edit-mode): Remove. (vc-hg-checkin): Remove extra arg. Use log-edit-extract-headers. * vc-git.el (vc-git-log-edit-mode): Remove. (vc-git-checkin): Remove extra arg. Use log-edit-extract-headers. (vc-git-commits-coding-system): Rename from git-commits-coding-system. * vc-dispatcher.el (vc-log-edit): Shorten names for log-edit-show-files. (vc-start-logentry): Remove argument `extra'. (vc-finish-logentry): Remove extra args. * vc-bzr.el (vc-bzr-log-edit-mode): Remove. (vc-bzr-checkin): Remove extra arg. Use log-edit-extract-headers. (vc-bzr-conflicted-files): New function. * log-edit.el (log-edit-extra-flags) (log-edit-before-checkin-process): Remove. (log-edit-summary, log-edit-header, log-edit-unknown-header): New faces. (log-edit-headers-alist): New var. (log-edit-header-contents-regexp): New const. (log-edit-match-to-eoh): New function. (log-edit-font-lock-keywords): Use them. (log-edit): Insert a "Summary:" header as default. (log-edit-mode): Mark font-lock rules as case-insensitive. (log-edit-done): Cleanup headers. (log-view-process-buffer): Remove. (log-edit-extract-headers): New function to replace it. diff -r 3ccddf080698 -r 17d3324f96dd etc/NEWS --- a/etc/NEWS Wed Apr 21 02:49:40 2010 +0200 +++ b/etc/NEWS Tue Apr 20 22:05:24 2010 -0400 @@ -88,6 +88,8 @@ ** Archive Mode has basic support to browse 7z archives. ** partial-completion-mode is now obsolete. +You can get the same behavior with +(setq completion-styles '(partial-completion initials)). ** mpc.el: Can use pseudo tags of the form tag1|tag2 as a union of two tags. ** Customize @@ -106,23 +108,18 @@ ** VC and related modes -*** New VC commands: vc-log-incoming and vc-log-outgoing. +*** New VC commands: vc-log-incoming, vc-log-outgoing, vc-find-conflicted-file. *** vc-dir for Bzr supports viewing shelve contents and shelving snapshots. *** Special markup can be added to log-edit buffers. - -**** For Bzr, adding an -Author: NAME -line will add "--author NAME" to the "bzr commit" command. - -**** For Git, adding an -Author: NAME -line will add "--author NAME" to the "git commit" command. - -**** For Hg, adding an -Author: NAME -line will add "--user NAME" to the "hg commit" command. +The log-edit buffers are expected to have a format similar to email messages +with headers of the form: + Author: + Summary: + Fixes: +Some backends handle some of those headers specially, but any unknown header +is just left as is in the message, so it is not lost. ** Directory local variables can apply to file-less buffers. For example, adding "(diff-mode . ((mode . whitespace)))" to your diff -r 3ccddf080698 -r 17d3324f96dd lisp/ChangeLog --- a/lisp/ChangeLog Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/ChangeLog Tue Apr 20 22:05:24 2010 -0400 @@ -1,3 +1,39 @@ +2010-04-21 Stefan Monnier + + * vc.el (vc-checkin, vc-modify-change-comment): + Adjust to new vc-start/finish-logentry. + (vc-find-conflicted-file): New command. + (vc-transfer-file): Adjust to new vc-checkin. + (vc-next-action): Improve scoping. + + * vc-hg.el (vc-hg-log-edit-mode): Remove. + (vc-hg-checkin): Remove extra arg. Use log-edit-extract-headers. + + * vc-git.el (vc-git-log-edit-mode): Remove. + (vc-git-checkin): Remove extra arg. Use log-edit-extract-headers. + (vc-git-commits-coding-system): Rename from git-commits-coding-system. + + * vc-dispatcher.el (vc-log-edit): Shorten names for log-edit-show-files. + (vc-start-logentry): Remove argument `extra'. + (vc-finish-logentry): Remove extra args. + + * vc-bzr.el (vc-bzr-log-edit-mode): Remove. + (vc-bzr-checkin): Remove extra arg. Use log-edit-extract-headers. + (vc-bzr-conflicted-files): New function. + + * log-edit.el (log-edit-extra-flags) + (log-edit-before-checkin-process): Remove. + (log-edit-summary, log-edit-header, log-edit-unknown-header): New faces. + (log-edit-headers-alist): New var. + (log-edit-header-contents-regexp): New const. + (log-edit-match-to-eoh): New function. + (log-edit-font-lock-keywords): Use them. + (log-edit): Insert a "Summary:" header as default. + (log-edit-mode): Mark font-lock rules as case-insensitive. + (log-edit-done): Cleanup headers. + (log-view-process-buffer): Remove. + (log-edit-extract-headers): New function to replace it. + 2010-04-20 Juanma Barranquero * subr.el (default-direction-reversed): Remove obsolescence info. diff -r 3ccddf080698 -r 17d3324f96dd lisp/emacs-lisp/cl-loaddefs.el --- a/lisp/emacs-lisp/cl-loaddefs.el Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/emacs-lisp/cl-loaddefs.el Tue Apr 20 22:05:24 2010 -0400 @@ -1242,7 +1242,6 @@ ;; version-control: never ;; no-byte-compile: t ;; no-update-autoloads: t +;; coding: utf-8 ;; End: - -;; arch-tag: 08cc5aab-e992-47f6-992e-12a7428c1a0e ;;; cl-loaddefs.el ends here diff -r 3ccddf080698 -r 17d3324f96dd lisp/log-edit.el --- a/lisp/log-edit.el Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/log-edit.el Tue Apr 20 22:05:24 2010 -0400 @@ -125,6 +125,7 @@ :type 'boolean) (defcustom log-edit-hook '(log-edit-insert-cvs-template + log-edit-show-files log-edit-insert-changelog) "Hook run at the end of `log-edit'." :group 'log-edit @@ -188,22 +189,6 @@ (defvar log-edit-callback nil) (defvar log-edit-diff-function nil) (defvar log-edit-listfun nil) -(defvar log-edit-extra-flags nil - "List of extra flags to pass to the check in command.") -(defvar log-edit-before-checkin-process nil - "Alist with instructions for processing the commit message before check in. -The format is: (REGEXP . INSTRUCTIONS). -All lines matching REGEXP are removed. For example: - -\(\"^#.*\" . nil) - -means: just remove all lines starting with #. This can be used -to insert lines in the commit buffer that contain, for example, the -list of files to be committed. - -\(\"Author: \\\\(.*\\\\)\" . (list \"--author\" (match-string 1))) - -means: append (list \"--author\" (match-string 1)) to `log-edit-extra-flags'.") (defvar log-edit-parent-buffer nil) @@ -329,10 +314,53 @@ ;;; Actual code ;;; +(defface log-edit-summary '((t :inherit font-lock-function-name-face)) + "Face for the summary in `log-edit-mode' buffers.") + +(defface log-edit-header '((t :inherit font-lock-keyword-face)) + "Face for the headers in `log-edit-mode' buffers.") + +(defface log-edit-unknown-header '((t :inherit font-lock-comment-face)) + "Face for unknown headers in `log-edit-mode' buffers.") + +(defvar log-edit-headers-alist '(("Summary" . log-edit-summary) + ("Fixes") ("Author")) + "AList of known headers and the face to use to highlight them.") + +(defconst log-edit-header-contents-regexp + "[ \t]*\\(.*\\(\n[ \t].*\\)*\\)\n?") + +(defun log-edit-match-to-eoh (limit) + ;; FIXME: copied from message-match-to-eoh. + (let ((start (point))) + (rfc822-goto-eoh) + ;; Typical situation: some temporary change causes the header to be + ;; incorrect, so EOH comes earlier than intended: the last lines of the + ;; intended headers are now not considered part of the header any more, + ;; so they don't have the multiline property set. When the change is + ;; completed and the header has its correct shape again, the lack of the + ;; multiline property means we won't rehighlight the last lines of + ;; the header. + (if (< (point) start) + nil ;No header within start..limit. + ;; Here we disregard LIMIT so that we may extend the area again. + (set-match-data (list start (point))) + (point)))) + (defvar log-edit-font-lock-keywords - '(("\\`\\(Summary:\\)\\(.*\\)" - (1 font-lock-keyword-face) - (2 font-lock-function-name-face)))) + ;; Copied/inspired by message-font-lock-keywords. + `((log-edit-match-to-eoh + (,(concat "^\\(\\([a-z]+\\):\\)" log-edit-header-contents-regexp + "\\|\\(.*\\)") + (progn (goto-char (match-beginning 0)) (match-end 0)) nil + (1 (if (assoc (match-string 2) log-edit-headers-alist) + 'log-edit-header + 'log-edit-unknown-header) + nil lax) + (3 (or (cdr (assoc (match-string 2) log-edit-headers-alist)) + 'log-edit-header) + nil lax) + (4 font-lock-warning-face))))) ;;;###autoload (defun log-edit (callback &optional setup params buffer mode &rest ignore) @@ -358,7 +386,10 @@ (if buffer (pop-to-buffer buffer)) (when (and log-edit-setup-invert (not (eq setup 'force))) (setq setup (not setup))) - (when setup (erase-buffer)) + (when setup + (erase-buffer) + (insert "Summary: ") + (save-excursion (insert "\n\n"))) (if mode (funcall mode) (log-edit-mode)) @@ -387,7 +418,7 @@ \\{log-edit-mode-map}" (set (make-local-variable 'font-lock-defaults) - '(log-edit-font-lock-keywords t)) + '(log-edit-font-lock-keywords t t)) (make-local-variable 'log-edit-comment-ring-index) (hack-dir-local-variables-non-file-buffer)) @@ -401,6 +432,17 @@ "Finish editing the log message and commit the files. If you want to abort the commit, simply delete the buffer." (interactive) + ;; Clean up empty headers. + (goto-char (point-min)) + (while (looking-at (concat "^[a-z]*:" log-edit-header-contents-regexp)) + (let ((beg (match-beginning 0))) + (goto-char (match-end 0)) + (if (string-match "\\`[ \n\t]*\\'" (match-string 1)) + (delete-region beg (point))))) + ;; Get rid of leading empty lines. + (goto-char (point-min)) + (when (looking-at "\\([ \t]*\n\\)+") + (delete-region (match-beginning 0) (match-end 0))) ;; Get rid of trailing empty lines (goto-char (point-max)) (skip-syntax-backward " ") @@ -458,12 +500,13 @@ "(Un)Indent the current buffer rigidly to `log-edit-common-indent'." (save-excursion (let ((common (point-max))) - (goto-char (point-min)) + (rfc822-goto-eoh) (while (< (point) (point-max)) (if (not (looking-at "^[ \t]*$")) (setq common (min common (current-indentation)))) (forward-line 1)) - (indent-rigidly (point-min) (point-max) + (rfc822-goto-eoh) + (indent-rigidly (point) (point-max) (- log-edit-common-indent common))))) (defun log-edit-show-diff () @@ -546,6 +589,10 @@ or if the command is repeated a second time in a row, use the first log entry regardless of user name or time." (interactive "P") + (let ((eoh (save-excursion (rfc822-goto-eoh) (point)))) + (when (<= (point) eoh) + (goto-char eoh) + (if (looking-at "\n") (forward-char 1)))) (let ((log-edit-changelog-use-first (or use-first (eq last-command 'log-edit-insert-changelog)))) (log-edit-insert-changelog-entries (log-edit-files))) @@ -731,16 +778,39 @@ (log-edit-changelog-insert-entries (car buffer-entry) (cdr buffer-entry)) (when (cdr buffer-entry) (newline))))) -(defun log-view-process-buffer () - (when log-edit-before-checkin-process - (dolist (crt log-edit-before-checkin-process) - ;; Remove all lines matching (car crt) - ;; Append to `log-edit-extra-flags' the results of (cdr crt). +(defun log-edit-extract-headers (headers comment) + "Extract headers from COMMENT to form command line arguments. +HEADERS should be an alist with elements of the form (HEADER . CMDARG) +associating header names to the corresponding cmdline option name and the +result is then a list of the form (MSG CMDARG1 HDRTEXT1 CMDARG2 HDRTEXT2...). +where MSG is the remaining text from STRING. +If \"Summary\" is not in HEADERS, then the \"Summary\" header is extracted +anyway and put back as the first line of MSG." + (with-temp-buffer + (insert comment) + (rfc822-goto-eoh) + (narrow-to-region (point-min) (point)) + (let ((case-fold-search t) + (summary ()) + (res ())) + (dolist (header (if (assoc "Summary" headers) headers + (cons '("Summary" . t) headers))) + (goto-char (point-min)) + (while (re-search-forward (concat "^" (car header) + ":" log-edit-header-contents-regexp) + nil t) + (if (eq t (cdr header)) + (setq summary (match-string 1)) + (push (match-string 1) res) + (push (or (cdr header) (car header)) res)) + (replace-match "" t t))) + ;; Remove header separator if the header is empty. + (widen) (goto-char (point-min)) - (while (re-search-forward (car crt) nil t) - (when (cdr crt) - (setq log-edit-extra-flags (append log-edit-extra-flags (eval (cdr crt))))) - (replace-match "" nil t))))) + (when (looking-at "\\([ \t]*\n\\)+") + (delete-region (match-beginning 0) (match-end 0))) + (if summary (insert summary "\n")) + (cons (buffer-string) res)))) (provide 'log-edit) diff -r 3ccddf080698 -r 17d3324f96dd lisp/vc-bzr.el --- a/lisp/vc-bzr.el Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/vc-bzr.el Tue Apr 20 22:05:24 2010 -0400 @@ -451,11 +451,16 @@ "Unregister FILE from bzr." (vc-bzr-command "remove" nil 0 file "--keep")) -(defun vc-bzr-checkin (files rev comment &optional extra-args) +(declare-function log-edit-extract-headers "log-edit" (headers string)) + +(defun vc-bzr-checkin (files rev comment) "Check FILE in to bzr with log message COMMENT. REV non-nil gets an error." (if rev (error "Can't check in a specific revision with bzr")) - (apply 'vc-bzr-command "commit" nil 0 files (append (list "-m" comment) extra-args))) + (apply 'vc-bzr-command "commit" nil 'async + files (cons "-m" (log-edit-extract-headers '(("Author" . "--author") + ("Fixes" . "--fixes")) + comment)))) (defun vc-bzr-find-revision (file rev buffer) "Fetch revision REV of file FILE and put it into BUFFER." @@ -552,23 +557,6 @@ (goto-char (point-min))) found))) -(declare-function log-edit-mode "log-edit" ()) -(defvar log-edit-extra-flags) -(defvar log-edit-before-checkin-process) - -(define-derived-mode vc-bzr-log-edit-mode log-edit-mode "Bzr-Log-Edit" - "Mode for editing Bzr commit logs. -If a line like: -Author: NAME -is present in the log, it is removed, and ---author NAME -is passed to the bzr commit command. Similarly with Fixes: and --fixes." - (set (make-local-variable 'log-edit-extra-flags) nil) - (set (make-local-variable 'log-edit-before-checkin-process) - '(("^\\(Author\\|Fixes\\):[ \t]+\\(.*\\)[ \t]*$" . - (list (format "--%s" (downcase (match-string 1))) - (match-string 2)))))) - (defun vc-bzr-diff (files &optional rev1 rev2 buffer) "VC bzr backend for diff." ;; `bzr diff' exits with code 1 if diff is non-empty. @@ -983,6 +971,19 @@ (setq loglines (buffer-substring-no-properties start (point-max)))))) vc-bzr-revisions)) +(defun vc-bzr-conflicted-files (dir) + (let ((default-directory (vc-bzr-root dir)) + (files ())) + (with-temp-buffer + (vc-bzr-command "status" t 0 default-directory) + (goto-char (point-min)) + (when (re-search-forward "^conflicts:\n" nil t) + (while (looking-at " \\(?:Text conflict in \\(.*\\)\\|.*\\)\n") + (if (match-end 1) + (push (expand-file-name (match-string 1)) files)) + (goto-char (match-end 0))))) + files)) + ;;; Revision completion (eval-and-compile diff -r 3ccddf080698 -r 17d3324f96dd lisp/vc-dispatcher.el --- a/lisp/vc-dispatcher.el Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/vc-dispatcher.el Tue Apr 20 22:05:24 2010 -0400 @@ -141,7 +141,6 @@ (defvar vc-log-operation nil) (defvar vc-log-after-operation-hook nil) (defvar vc-log-fileset) -(defvar vc-log-extra) ;; In a log entry buffer, this is a local variable ;; that points to the buffer for which it was made @@ -521,17 +520,20 @@ (with-current-buffer vc-parent-buffer default-directory)) (log-edit 'vc-finish-logentry nil - `((log-edit-listfun . (lambda () ',fileset)) + `((log-edit-listfun . (lambda () + ;; FIXME: Should expand the list + ;; for directories. + (mapcar 'file-relative-name + ',fileset))) (log-edit-diff-function . (lambda () (vc-diff nil)))) nil mode) (set (make-local-variable 'vc-log-fileset) fileset) - (make-local-variable 'vc-log-extra) (set-buffer-modified-p nil) (setq buffer-file-name nil)) -(defun vc-start-logentry (files extra comment initial-contents msg logbuf mode action &optional after-hook) - "Accept a comment for an operation on FILES with extra data EXTRA. +(defun vc-start-logentry (files comment initial-contents msg logbuf mode action &optional after-hook) + "Accept a comment for an operation on FILES. If COMMENT is nil, pop up a LOGBUF buffer, emit MSG, and set the action on close to ACTION. If COMMENT is a string and INITIAL-CONTENTS is non-nil, then COMMENT is used as the initial @@ -561,7 +563,6 @@ (when after-hook (setq vc-log-after-operation-hook after-hook)) (setq vc-log-operation action) - (setq vc-log-extra extra) (when comment (erase-buffer) (when (stringp comment) (insert comment))) @@ -570,10 +571,8 @@ (vc-finish-logentry (eq comment t))))) (declare-function vc-dir-move-to-goal-column "vc-dir" ()) -;; vc-finish-logentry is called from a log-edit buffer (see above). -(declare-function log-view-process-buffer "log-edit" ()) -(defvar log-edit-extra-flags) - +;; vc-finish-logentry is typically called from a log-edit buffer (see +;; vc-start-logentry). (defun vc-finish-logentry (&optional nocomment) "Complete the operation implied by the current log entry. Use the contents of the current buffer as a check-in or registration @@ -590,25 +589,21 @@ (unless vc-log-operation (error "No log operation is pending")) - (log-view-process-buffer) - ;; save the parameters held in buffer-local variables (let ((logbuf (current-buffer)) (log-operation vc-log-operation) + ;; FIXME: When coming from VC-Dir, we should check that the + ;; set of selected files is still equal to vc-log-fileset, + ;; to avoid surprises. (log-fileset vc-log-fileset) - (log-extra vc-log-extra) (log-entry (buffer-string)) - (extra-flags log-edit-extra-flags) (after-hook vc-log-after-operation-hook)) (pop-to-buffer vc-parent-buffer) ;; OK, do it to it (save-excursion (funcall log-operation log-fileset - log-extra - log-entry - extra-flags - )) + log-entry)) ;; Remove checkin window (after the checkin so that if that fails ;; we don't zap the log buffer and the typing therein). ;; -- IMO this should be replaced with quit-window diff -r 3ccddf080698 -r 17d3324f96dd lisp/vc-git.el --- a/lisp/vc-git.el Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/vc-git.el Tue Apr 20 22:05:24 2010 -0400 @@ -118,7 +118,7 @@ :version "23.1" :group 'vc) -(defvar git-commits-coding-system 'utf-8 +(defvar vc-git-commits-coding-system 'utf-8 "Default coding system for git commits.") ;;; BACKEND PROPERTIES @@ -548,11 +548,15 @@ (defun vc-git-unregister (file) (vc-git-command nil 0 file "rm" "-f" "--cached" "--")) +(declare-function log-edit-extract-headers "log-edit" (headers string)) -(defun vc-git-checkin (files rev comment &optional extra-args) - (let ((coding-system-for-write git-commits-coding-system)) +(defun vc-git-checkin (files rev comment) + (let ((coding-system-for-write vc-git-commits-coding-system)) (apply 'vc-git-command nil 0 files - (nconc (list "commit" "-m" comment) extra-args (list "--only" "--"))))) + (nconc (list "commit" "-m") + (log-edit-extract-headers '(("Author" . "--author")) + comment) + (list "--only" "--"))))) (defun vc-git-find-revision (file rev buffer) (let* (process-file-side-effects @@ -582,7 +586,7 @@ "Get change log associated with FILES. Note that using SHORTLOG requires at least Git version 1.5.6, for the --graph option." - (let ((coding-system-for-read git-commits-coding-system)) + (let ((coding-system-for-read vc-git-commits-coding-system)) ;; `vc-do-command' creates the buffer, but we need it before running ;; the command. (vc-setup-buffer buffer) @@ -793,21 +797,6 @@ (progn (forward-line 1) (1- (point))))))))) (or (vc-git-symbolic-commit next-rev) next-rev))) -(declare-function log-edit-mode "log-edit" ()) -(defvar log-edit-extra-flags) -(defvar log-edit-before-checkin-process) - -(define-derived-mode vc-git-log-edit-mode log-edit-mode "Git-log-edit" - "Mode for editing Git commit logs. -If a line like: -Author: NAME -is present in the log, it is removed, and ---author=NAME -is passed to the git commit command." - (set (make-local-variable 'log-edit-extra-flags) nil) - (set (make-local-variable 'log-edit-before-checkin-process) - '(("^Author:[ \t]+\\(.*\\)[ \t]*$" . (list "--author" (match-string 1)))))) - (defun vc-git-delete-file (file) (vc-git-command nil 0 file "rm" "-f" "--")) diff -r 3ccddf080698 -r 17d3324f96dd lisp/vc-hg.el --- a/lisp/vc-hg.el Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/vc-hg.el Tue Apr 20 22:05:24 2010 -0400 @@ -296,20 +296,7 @@ ("^tag: +\\([^ ]+\\)$" (1 'highlight)) ("^summary:[ \t]+\\(.+\\)" (1 'log-view-message))))))) -(declare-function log-edit-mode "log-edit" ()) -(defvar log-edit-extra-flags) -(defvar log-edit-before-checkin-process) - -(define-derived-mode vc-hg-log-edit-mode log-edit-mode "Hg-log-edit" - "Mode for editing Hg commit logs. -If a line like: -Author: NAME -is present in the log, it is removed, and ---author NAME -is passed to the hg commit command." - (set (make-local-variable 'log-edit-extra-flags) nil) - (set (make-local-variable 'log-edit-before-checkin-process) - '(("^Author:[ \t]+\\(.*\\)[ \t]*$" . (list "--user" (match-string 1)))))) +(declare-function log-edit-extract-headers "log-edit" (headers string)) (defun vc-hg-diff (files &optional oldvers newvers buffer) "Get a difference report using hg between two revisions of FILES." @@ -434,11 +421,15 @@ ;; "Unregister FILE from hg." ;; (vc-hg-command nil nil file "remove")) -(defun vc-hg-checkin (files rev comment &optional extra-args) +(declare-function log-edit-extract-headers "log-edit" (headers string)) + +(defun vc-hg-checkin (files rev comment) "Hg-specific version of `vc-backend-checkin'. REV is ignored." (apply 'vc-hg-command nil 0 files - (nconc (list "commit" "-m" comment) extra-args))) + (nconc (list "commit" "-m") + (log-edit-extract-headers '(("Author" . "--user")) + comment)))) (defun vc-hg-find-revision (file rev buffer) (let ((coding-system-for-read 'binary) diff -r 3ccddf080698 -r 17d3324f96dd lisp/vc.el --- a/lisp/vc.el Wed Apr 21 02:49:40 2010 +0200 +++ b/lisp/vc.el Tue Apr 20 22:05:24 2010 -0400 @@ -268,15 +268,12 @@ ;; Unregister FILE from this backend. This is only needed if this ;; backend may be used as a "more local" backend for temporary editing. ;; -;; * checkin (files rev comment &optional extra-args) +;; * checkin (files rev comment) ;; -;; Commit changes in FILES to this backend. If REV is non-nil, that -;; should become the new revision number (not all backends do -;; anything with it). COMMENT is used as a check-in comment. The -;; implementation should pass the value of vc-checkin-switches to -;; the backend command. (Note: in older versions of VC, this -;; command took a single file argument and not a list.) -;; EXTRA-ARGS should be passed to the backend command. +;; Commit changes in FILES to this backend. REV is a historical artifact +;; and should be ignored. COMMENT is used as a check-in comment. +;; The implementation should pass the value of vc-checkin-switches to +;; the backend command. ;; ;; * find-revision (file rev buffer) ;; @@ -548,6 +545,12 @@ ;; makes it possible to provide menu entries for functionality that ;; is specific to a backend and which does not map to any of the VC ;; generic concepts. +;; +;; - conflicted-files (dir) +;; +;; Return the list of files where conflict resolution is needed in +;; the project that contains DIR. +;; FIXME: what should it do with non-text conflicts? ;;; Todo: @@ -1054,8 +1057,7 @@ (state (nth 3 vc-fileset)) ;; The backend should check that the checkout-model is consistent ;; among all the `files'. - (model (nth 4 vc-fileset)) - revision) + (model (nth 4 vc-fileset))) ;; Do the right thing (cond @@ -1070,11 +1072,13 @@ (cond (verbose ;; go to a different revision - (setq revision (read-string "Branch, revision, or backend to move to: ")) - (let ((revision-downcase (downcase revision))) + (let* ((revision + (read-string "Branch, revision, or backend to move to: ")) + (revision-downcase (downcase revision))) (if (member revision-downcase - (mapcar (lambda (arg) (downcase (symbol-name arg))) vc-handled-backends)) + (mapcar (lambda (arg) (downcase (symbol-name arg))) + vc-handled-backends)) (let ((vsym (intern-soft revision-downcase))) (dolist (file files) (vc-transfer-file file vsym))) (dolist (file files) @@ -1119,8 +1123,8 @@ (message "No files remain to be committed") (if (not verbose) (vc-checkin ready-for-commit backend) - (setq revision (read-string "New revision or backend: ")) - (let ((revision-downcase (downcase revision))) + (let* ((revision (read-string "New revision or backend: ")) + (revision-downcase (downcase revision))) (if (member revision-downcase (mapcar (lambda (arg) (downcase (symbol-name arg))) @@ -1365,7 +1369,7 @@ (defun vc-checkin (files backend &optional rev comment initial-contents) "Check in FILES. The optional argument REV may be a string specifying the new revision -level (if nil increment the current level). COMMENT is a comment +level (strongly deprecated). COMMENT is a comment string; if omitted, a buffer is popped up to accept a comment. If INITIAL-CONTENTS is non-nil, then COMMENT is used as the initial contents of the log entry buffer. @@ -1379,28 +1383,30 @@ (lexical-let ((backend backend)) (vc-start-logentry - files rev comment initial-contents + files comment initial-contents "Enter a change comment." "*VC-log*" (lambda () (vc-call-backend backend 'log-edit-mode)) - (lambda (files rev comment extra-flags) - (message "Checking in %s..." (vc-delistify files)) - ;; "This log message intentionally left almost blank". - ;; RCS 5.7 gripes about white-space-only comments too. - (or (and comment (string-match "[^\t\n ]" comment)) - (setq comment "*** empty log message ***")) - (with-vc-properties - files - ;; We used to change buffers to get local value of vc-checkin-switches, - ;; but 'the' local buffer is not a well-defined concept for filesets. - (progn - (vc-call-backend backend 'checkin files rev comment extra-flags) - (mapc 'vc-delete-automatic-version-backups files)) - `((vc-state . up-to-date) - (vc-checkout-time . ,(nth 5 (file-attributes file))) - (vc-working-revision . nil))) - (message "Checking in %s...done" (vc-delistify files))) + (lexical-let ((rev rev)) + (lambda (files comment) + (message "Checking in %s..." (vc-delistify files)) + ;; "This log message intentionally left almost blank". + ;; RCS 5.7 gripes about white-space-only comments too. + (or (and comment (string-match "[^\t\n ]" comment)) + (setq comment "*** empty log message ***")) + (with-vc-properties + files + ;; We used to change buffers to get local value of + ;; vc-checkin-switches, but 'the' local buffer is + ;; not a well-defined concept for filesets. + (progn + (vc-call-backend backend 'checkin files rev comment) + (mapc 'vc-delete-automatic-version-backups files)) + `((vc-state . up-to-date) + (vc-checkout-time . ,(nth 5 (file-attributes file))) + (vc-working-revision . nil))) + (message "Checking in %s...done" (vc-delistify files)))) 'vc-checkin-hook))) ;;; Additional entry points for examining version histories @@ -1772,13 +1778,14 @@ ;; case the more general operation ever becomes meaningful. (let ((backend (vc-responsible-backend (car files)))) (vc-start-logentry - files rev oldcomment t + files oldcomment t "Enter a replacement change comment." "*VC-log*" (lambda () (vc-call-backend backend 'log-edit-mode)) - (lambda (files rev comment ignored) - (vc-call-backend backend - 'modify-change-comment files rev comment))))) + (lexical-let ((rev rev)) + (lambda (files comment) + (vc-call-backend backend + 'modify-change-comment files rev comment)))))) ;;;###autoload (defun vc-merge () @@ -1839,6 +1846,31 @@ ;;;###autoload (defalias 'vc-resolve-conflicts 'smerge-ediff) +;; TODO: This is OK but maybe we could integrate it better. +;; E.g. it could be run semi-automatically (via a prompt?) when saving a file +;; that was conflicted (i.e. upon mark-resolved). +;; FIXME: should we add an "other-window" version? Or maybe we should +;; hook it inside find-file so it automatically works for +;; find-file-other-window as well. E.g. find-file could use a new +;; `default-next-file' variable for its default file (M-n), and +;; we could then set it upon mark-resolve, so C-x C-s C-x C-f M-n would +;; automatically offer the next conflicted file. +(defun vc-find-conflicted-file () + "Visit the next conflicted file in the current project." + (interactive) + (let* ((backend (or (if buffer-file-name (vc-backend buffer-file-name)) + (vc-responsible-backend default-directory) + (error "No VC backend"))) + (files (vc-call-backend backend + 'conflicted-files default-directory))) + ;; Don't try and visit the current file. + (if (equal (car files) buffer-file-name) (pop files)) + (if (null files) + (message "No more conflicted files") + (find-file (pop files)) + (message "%s more conflicted files after this one" + (if files (length files) "No"))))) + ;; Named-configuration entry points (defun vc-tag-precondition (dir)