From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Bob Rogers Newsgroups: gmane.emacs.devel Subject: Updating *vc-dir* marks from *VC-log* Date: Sat, 20 Nov 2010 19:58:00 -0500 Message-ID: <19688.28312.768696.349949@rgr.rgrjr.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Trace: dough.gmane.org 1290301104 5383 80.91.229.12 (21 Nov 2010 00:58:24 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Sun, 21 Nov 2010 00:58:24 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Nov 21 01:58:13 2010 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1PJyFv-0004qx-RS for ged-emacs-devel@m.gmane.org; Sun, 21 Nov 2010 01:58:12 +0100 Original-Received: from localhost ([127.0.0.1]:37187 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PJyFv-00077o-1U for ged-emacs-devel@m.gmane.org; Sat, 20 Nov 2010 19:58:11 -0500 Original-Received: from [140.186.70.92] (port=45228 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PJyFp-00076w-Nz for emacs-devel@gnu.org; Sat, 20 Nov 2010 19:58:07 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PJyFo-0002ZY-95 for emacs-devel@gnu.org; Sat, 20 Nov 2010 19:58:05 -0500 Original-Received: from rgrjr.com ([216.146.47.5]:53233) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PJyFo-0002ZR-3c for emacs-devel@gnu.org; Sat, 20 Nov 2010 19:58:04 -0500 Original-Received: from rgrjr.dyndns.org (c-66-30-196-77.hsd1.ma.comcast.net [66.30.196.77]) by rgrjr.com (Postfix on CentOS) with ESMTP id C0DCD1600E8 for ; Sun, 21 Nov 2010 00:58:02 +0000 (UTC) Original-Received: (qmail 8696 invoked by uid 89); 21 Nov 2010 00:58:02 -0000 Original-Received: from unknown (HELO rgr.rgrjr.com) (192.168.57.1) by home with SMTP; 21 Nov 2010 00:58:01 -0000 Original-Received: by rgr.rgrjr.com (Postfix, from userid 500) id 588D6A4E6E; Sat, 20 Nov 2010 19:58:01 -0500 (EST) X-Mailer: VM 7.19 under Emacs 24.0.50.1 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:132941 Archived-At: Perhaps I'm slow, but I only just noticed that it is possible to work on multiple VC commits for the same working copy in parallel, just by renaming *VC-log* buffers. This is cool; it perfectly suits my working style. I would like to write it up for the Emacs manual so that others can find it. But it lacks something. I often start a commit, then realize that I've left out a file or two, or maybe included one that ought to be committed separately. When doing one commit at a time, this is a simple matter of returning to vc-dir, updating the set, and doing "C-x v v" again. With multiple pending commits, what is needed is a way to return to vc-dir and "swap in" the log buffer fileset. The patch below adds a new log-edit-visit-files-in-vc-dir command to do this. I have tentatively bound it to "C-c @" in log-edit-mode, which I hope is sufficiently mnemonic for "mark". The only problem is that "C-x v v" doesn't know to which of several log buffers it should return from *vc-dir*; it always picks *VC-log*, creating a new one if necessary. I could hack vc-checkin, but one would still need to be able to specify when to go back to the relevant log buffer, and when to create a new one. Comments? -- Bob Rogers http://www.rgrjr.com/ ------------------------------------------------------------------------ diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el index 27290ee..726a074 100644 --- a/lisp/vc/log-edit.el +++ b/lisp/vc/log-edit.el @@ -57,6 +57,7 @@ ("\C-c\C-a" . log-edit-insert-changelog) ("\C-c\C-d" . log-edit-show-diff) ("\C-c\C-f" . log-edit-show-files) + ("\C-c@" . log-edit-visit-files-in-vc-dir) ("\M-n" . log-edit-next-comment) ("\M-p" . log-edit-previous-comment) ("\M-r" . log-edit-comment-search-backward) @@ -533,6 +534,40 @@ If you want to abort the commit, simply delete the buffer." (shrink-window-if-larger-than-buffer) (selected-window))))) +(defun log-edit-visit-files-in-vc-dir () + "Switch to vc-dir, marking the list of files to be committed." + (interactive) + (let ((files (mapcar 'expand-file-name (log-edit-files))) + (buffers nil)) + ;; Find the set of possible vc-dir buffers. + (let ((tail files)) + (while tail + (let* ((buf-and-node (vc-dir-find-buffer-for-file (car tail))) + (buffer (car buf-and-node))) + (message "got %S for %S" buf-and-node (car tail)) + (if (and buffer + (not (member buffer buffers))) + (setq buffers (cons buffer buffers)))) + (setq tail (cdr tail)))) + (cond ((null buffers) + ;; Totally failed, so offer to start vc-dir. + (call-interactively 'vc-dir)) + ((not (null (cdr buffers))) + ;; [not sure what to do here. -- rgr, 20-Nov-10.] + (error "Oops; got buffers %S" buffers)) + (t + ;; Single-buffer case. + (switch-to-buffer-other-window (car buffers)) + ;; [should we go to one of these files? should it be + ;; the first, or the last? -- rgr, 20-Nov-10.] + (let* ((n-files (length files)) + (n-marked (vc-dir-set-marked-files files)) + (plural (if (= n-files 1) "" "s"))) + (if (= n-files n-marked) + (message "Marked %d file%s." n-files plural) + (message "Marked %d out of %d file%s." + n-marked n-files plural))))))) + (defun log-edit-insert-cvs-template () "Insert the template specified by the CVS administrator, if any. This simply uses the local CVS/Template file." diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el index 4397251..556c612 100644 --- a/lisp/vc/vc-dir.el +++ b/lisp/vc/vc-dir.el @@ -714,6 +714,31 @@ that share the same state." (interactive "e") (vc-dir-at-event e (vc-dir-mark-unmark 'vc-dir-toggle-mark-file))) +(defun vc-dir-set-marked-files (files) + ;; Given a list of files, mark each file that appears in the list, + ;; and unmark all the others. No mention is made if a file appears + ;; in the list that does not appear in the vc-dir buffer, but the + ;; number of files actually marked is returned. + (let ((crt (ewoc-nth vc-ewoc 0)) (n-files-marked 0)) + (while crt + (let* ((file (ewoc-data crt)) + (new-mark-state + (cond ((vc-dir-fileinfo->directory file) + ;; Always unmark the directories. + nil) + ((let ((nodefile (vc-dir-fileinfo->name file))) + ;; (message "[checking %S]" nodefile) + (member (expand-file-name nodefile) files)) + t)))) + (unless (eq (not new-mark-state) + (not (vc-dir-fileinfo->marked file))) + (setf (vc-dir-fileinfo->marked file) new-mark-state) + (ewoc-invalidate vc-ewoc crt) + (when new-mark-state + (incf n-files-marked)))) + (setq crt (ewoc-next vc-ewoc crt))) + n-files-marked)) + (defun vc-dir-delete-file () "Delete the marked files, or the current file if no marks." (interactive) @@ -886,6 +911,45 @@ If it is a file, return the corresponding cons for the file itself." fileentries)) (vc-dir-update fileentries (current-buffer))))) +(defun vc-dir-find-buffer-for-file (file) + ;; Look for a vc-dir buffer that includes file, or one that might + ;; contain file if it were visible. Returns nil if no such buffer + ;; was found, or a list of (buffer node) where node might be nil if + ;; file is not visible. + (message "checking %S for file %S" vc-dir-buffers file) + (let ((vc-dir-buffer nil) (vc-dir-default-directory-len 0) + (vc-dir-node nil) (tail vc-dir-buffers)) + (while tail + (if (buffer-live-p (car tail)) + (with-current-buffer (car tail) + ;; Search for a node for file. + (let ((node (ewoc-nth vc-ewoc 0)) + (dd-len (length default-directory))) + (while node + (let ((nodefile (vc-dir-fileinfo->name (ewoc-data node)))) + (if (string-equal (expand-file-name nodefile) + file) + ;; Success. + (setq vc-dir-buffer (current-buffer) + vc-dir-node node + tail nil node nil))) + (setq node (ewoc-next vc-ewoc node))) + ;; If not found, but the directory is a prefix of + ;; file, then remember the buffer as a fallback. + (if (and (null vc-dir-node) + (> (length file) dd-len) + (string-equal (substring file 0 dd-len) + default-directory) + ;; When we have multiple candidates, pick the one + ;; deeper in the directory hierarchy. + (or (null vc-dir-buffer) + (> dd-len vc-dir-default-directory-len))) + (setq vc-dir-buffer (current-buffer) + vc-dir-default-directory-len dd-len))))) + (setq tail (cdr tail))) + (and vc-dir-buffer + (list vc-dir-buffer vc-dir-node)))) + (defun vc-dir-resynch-file (&optional fname) "Update the entries for FNAME in any directory buffers that list it." (let ((file (or fname (expand-file-name buffer-file-name)))