From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Thien-Thi Nguyen Newsgroups: gmane.emacs.devel Subject: Re: vc-*-root finctions Date: Wed, 20 Feb 2008 19:21:45 +0100 Message-ID: <87mypvxzd2.fsf@ambire.localdomain> References: <87skzn3mq9.fsf@ambire.localdomain> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: ger.gmane.org 1203531882 16697 80.91.229.12 (20 Feb 2008 18:24:42 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 20 Feb 2008 18:24:42 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Feb 20 19:25:06 2008 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.50) id 1JRtcv-0002kQ-Mu for ged-emacs-devel@m.gmane.org; Wed, 20 Feb 2008 19:25:06 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JRtcQ-0007Ra-Ij for ged-emacs-devel@m.gmane.org; Wed, 20 Feb 2008 13:24:34 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JRtbo-00076W-GR for emacs-devel@gnu.org; Wed, 20 Feb 2008 13:23:56 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JRtbk-00072m-Pu for emacs-devel@gnu.org; Wed, 20 Feb 2008 13:23:54 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JRtbj-00072M-7l for emacs-devel@gnu.org; Wed, 20 Feb 2008 13:23:51 -0500 Original-Received: from [151.61.141.122] (helo=ambire.localdomain) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1JRtbh-0000bU-NC for emacs-devel@gnu.org; Wed, 20 Feb 2008 13:23:50 -0500 Original-Received: from ttn by ambire.localdomain with local (Exim 4.63) (envelope-from ) id 1JRtZh-0003ls-Sg; Wed, 20 Feb 2008 19:21:45 +0100 In-Reply-To: (Stefan Monnier's message of "Wed, 20 Feb 2008 12:21:55 -0500") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.60 (gnu/linux) X-detected-kernel: by monty-python.gnu.org: Genre and OS details not recognized. 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:89721 Archived-At: --=-=-= () Stefan Monnier () Wed, 20 Feb 2008 12:21:55 -0500 This part I inferred, but of course it is necessary (weren't you the guy complaining harshly about lack of comments in VC's in-development code ;-)? I said i find under-commenting obnoxious. Now i add: everyone is free to be obnoxious -- makes life interesting. If these IMHOs sound like harsh complaining, i must introduce you someday to my two-year-old... > I am using vc-BACKEND-root for (work-in-progress, see below) > `vc-status-mode' munging. I don't understand what for (in terms of user-level feature)? Please see the `vc-status-mode' docstring in the updated code below. This time i include a full patch for anyone interested in trying it out. In terms of user experience, this means that doing: M-x vc-status RET ~/build/MISC/ferm/examples RET shows a buffer where the first line reads: Directory: ~/build/MISC/ferm/examples/ and "ferm" (the project's "root" directory) is a button, which means (for me) underlined and clickable, whose action is to do `(vc-status "~/build/MISC/ferm")'. If this explanation makes sense to you and the docstring doesn't, could you suggest another wording? thi ________________________________________________________________ one edit * vc.el (vc-overview-p): New defsubst. (vc-start-entry, vc-finish-logentry): Use it. another edit * vc.el (vc-status-headers): Delete func. (vc-status, vc-status-mode, vc-status-refresh): Rewrite. (vc-update-vc-status-buffer): Delete func. * vc-svn.el (vc-svn-after-dir-status): Incorporate into... (vc-svn-dir-status): ...here; update calling sequence. * vc-hg.el (vc-hg-after-dir-status): Incorporate into... (vc-hg-dir-status): ...here; update calling sequence. * vc-git.el (vc-git-after-dir-status): Delete func. (vc-git-dir-status): Rewrite. full munging --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=.ttn.diff Content-Description: two edits Index: vc-git.el =================================================================== RCS file: /sources/emacs/emacs/lisp/vc-git.el,v retrieving revision 1.38 diff -c -r1.38 vc-git.el *** vc-git.el 18 Feb 2008 07:46:14 -0000 1.38 --- vc-git.el 20 Feb 2008 18:15:50 -0000 *************** *** 207,258 **** ;; fall back to the default VC representation (vc-default-dired-state-info 'Git file)))) ! ;;; vc-dir-status support (EXPERIMENTAL) ! ;;; If vc-directory (which is not half bad under Git, w/ some tweaking) ! ;;; is to go away, vc-dir-status must at least support the same operations. ! ;;; At the moment, vc-dir-status design is still fluid (a kind way to say ! ;;; half-baked, undocumented, and spottily-supported), so the following ! ;;; should be considered likewise ripe for sudden unannounced change. ! ;;; YHBW, HAND. --ttn ! ! (defun vc-git-after-dir-status (callback buffer) ! (sort-regexp-fields t "^. \\(.+\\)$" "\\1" (point-min) (point-max)) ! (let ((map '((?H . cached) ! (?M . unmerged) ! (?R . removed) ! (?C . edited) ! (?K . removed) ; ??? "to be killed" ! (?? . unregistered))) ! status filename result) ! (goto-char (point-min)) ! (while (> (point-max) (point)) ! (setq status (string-to-char (buffer-substring (point) (1+ (point)))) ! status (cdr (assq status map)) ! filename (buffer-substring (+ 2 (point)) (line-end-position))) ! ;; TODO: Add dynamic selection of which status(es) to display, and ! ;; bubble that up to vc-dir-status. For now, we consider `cached' ! ;; to be uninteresting, to mimic vc-directory (somewhat). ! (unless (eq 'cached status) (push (cons filename status) result)) ! (forward-line 1)) ! (funcall callback result buffer))) ! ! (defun vc-git-dir-status (dir update-function status-buffer) ! "Return a list of conses (file . state) for DIR." ! (with-current-buffer ! (get-buffer-create ! (expand-file-name " *VC-Git* tmp status" dir)) ! (erase-buffer) ! (vc-git-command (current-buffer) 'async dir "ls-files" "-t" ! "-c" ; cached ! "-d" ; deleted ! "-k" ; killed ! "-m" ; modified ! "-o" ; others ! "--directory" ! "--exclude-per-directory=.gitignore") ! (vc-exec-after ! `(vc-git-after-dir-status (quote ,update-function) ,status-buffer)))) ;;; STATE-CHANGING FUNCTIONS --- 207,258 ---- ;; fall back to the default VC representation (vc-default-dired-state-info 'Git file)))) ! (defun vc-git-dir-status (&optional kickp) ! "Return a list of conses (FILE . STATE) for the default directory." ! (if kickp ! ;; Don't do it asynchronously; git is fast and always local. ! ;; Avoid "-a" so as to be able to distinguish "in index". ! (call-process "git" nil t nil "status") ! (let* ((root (vc-git-root default-directory)) ! (sub (file-relative-name default-directory root)) ! ;; If we are not in the project's root dir, discard ! ;; lines that do not have the relative-dir prefix. ! (keep-rx (concat "^#\t\\([^:]+\\): +" ! (if (member sub '("." "./")) ! "" ! (file-name-as-directory sub)))) ! (pair-rx (concat keep-rx "\\(.+\\)$")) ! status filename result) ! (goto-char (point-min)) ! ;; Encode "in index" in the state; eg: `modified' vs `modified/in'. ! (when (search-forward "\n# Changes to be committed:\n" nil t) ! (search-forward "#\t") ! (forward-char -2) ! (while (looking-at "#\t[^:]+\\(:\\)") ! (replace-match "/in:" t t nil 1) ! (forward-line 1))) ! (when (search-forward "\n# Untracked files:\n" nil t) ! (while (re-search-forward "^#\t" nil t) ! (insert "untracked: "))) ! (keep-lines keep-rx (point-min) (point-max)) ! ;; This sorting is purely cosmetic. We will probably remove it a ! ;; little further down the road, when VC Status learns to manage ! ;; total ordering and all that jazz. --ttn ! (sort-regexp-fields t pair-rx "\\2" (point-min) (point-max)) ! (goto-char (point-min)) ! (while (re-search-forward pair-rx nil t) ! (setq status (match-string 1) ! status (if (string-match "new file" status) ! (replace-match "new" t t status) ! status) ! status (intern status) ! filename (match-string 2)) ! (when (memq status '(renamed renamed/in copied copied/in)) ! ;; Discard first name: "ONE -> TWO" becomes "TWO". ! (setq filename (substring filename ! (+ 4 (string-match " -> " filename))))) (push (cons filename status) result)) ! result))) ;;; STATE-CHANGING FUNCTIONS Index: vc-hg.el =================================================================== RCS file: /sources/emacs/emacs/lisp/vc-hg.el,v retrieving revision 1.50 diff -c -r1.50 vc-hg.el *** vc-hg.el 20 Feb 2008 15:21:55 -0000 1.50 --- vc-hg.el 20 Feb 2008 18:15:50 -0000 *************** *** 483,524 **** (define-derived-mode vc-hg-incoming-mode vc-hg-log-view-mode "Hg-Incoming") ! ;; XXX Experimental function for the vc-dired replacement. ! (defun vc-hg-after-dir-status (update-function buff) ! (let ((status-char nil) ! (file nil) ! (translation '((?= . up-to-date) ! (?C . up-to-date) ! (?A . added) ! (?R . removed) ! (?M . edited) ! (?I . ignored) ! (?! . deleted) ! (?? . unregistered))) ! (translated nil) ! (result nil)) (goto-char (point-min)) (while (not (eobp)) ! (setq status-char (char-after)) ! (setq file ! (buffer-substring-no-properties (+ (point) 2) ! (line-end-position))) ! (setq translated (assoc status-char translation)) ! (when (and translated (not (eq (cdr translated) 'up-to-date))) ! (push (cons file (cdr translated)) result)) ! (forward-line)) ! (funcall update-function result buff))) ! ! ;; XXX Experimental function for the vc-dired replacement. ! (defun vc-hg-dir-status (dir update-function status-buffer) ! "Return a list of conses (file . state) for DIR." ! (with-current-buffer ! (get-buffer-create ! (expand-file-name " *VC-hg* tmp status" dir)) ! (erase-buffer) ! (vc-hg-command (current-buffer) 'async dir "status") ! (vc-exec-after ! `(vc-hg-after-dir-status (quote ,update-function) ,status-buffer)))) ;; XXX this adds another top level menu, instead figure out how to ;; replace the Log-View menu. --- 483,516 ---- (define-derived-mode vc-hg-incoming-mode vc-hg-log-view-mode "Hg-Incoming") ! (defun vc-hg-dir-status (&optional kickp) ! "Return a list of conses (FILE . STATE) for the default directory." ! (if kickp ! ;; TODO: Conditionally synchronous. ! (vc-hg-command (current-buffer) 'async default-directory "status") ! (let ((status-char nil) ! (file nil) ! (translation '((?= . up-to-date) ! (?C . up-to-date) ! (?A . added) ! (?R . removed) ! (?M . edited) ! (?I . ignored) ! (?! . deleted) ! (?? . unregistered))) ! (translated nil) ! (result nil)) (goto-char (point-min)) (while (not (eobp)) ! (setq status-char (char-after)) ! (setq file ! (buffer-substring-no-properties (+ (point) 2) ! (line-end-position))) ! (setq translated (assoc status-char translation)) ! (when (and translated (not (eq (cdr translated) 'up-to-date))) ! (push (cons file (cdr translated)) result)) ! (forward-line)) ! result))) ;; XXX this adds another top level menu, instead figure out how to ;; replace the Log-View menu. Index: vc-svn.el =================================================================== RCS file: /sources/emacs/emacs/lisp/vc-svn.el,v retrieving revision 1.69 diff -c -r1.69 vc-svn.el *** vc-svn.el 20 Feb 2008 10:40:46 -0000 1.69 --- vc-svn.el 20 Feb 2008 18:15:50 -0000 *************** *** 158,191 **** (vc-svn-command t 0 nil "status" (if localp "-v" "-u")) (vc-svn-parse-status)))) ! (defun vc-svn-after-dir-status (callback buffer) ! (let ((state-map '((?A . added) ! (?C . edited) ! (?D . removed) ! (?I . ignored) ! (?M . edited) ! (?R . removed) ! (?? . unregistered) ! ;; This is what vc-svn-parse-status does. ! (?~ . edited))) ! result) ! (goto-char (point-min)) ! (while (re-search-forward "^\\(.\\)..... \\(.*\\)$" nil t) ! (let ((state (cdr (assq (aref (match-string 1) 0) state-map))) ! (filename (match-string 2))) ! (when state ! (setq result (cons (cons filename state) result))))) ! (funcall callback result buffer))) ! ! (defun vc-svn-dir-status (dir callback buffer) ! "Run 'svn status' for DIR and update BUFFER via CALLBACK. ! CALLBACK is called as (CALLBACK RESULT BUFFER), where ! RESULT is a list of conses (FILE . STATE) for directory DIR." ! (with-current-buffer (get-buffer-create ! (generate-new-buffer-name " *vc svn status*")) ! (vc-svn-command (current-buffer) 'async nil "status") ! (vc-exec-after ! `(vc-svn-after-dir-status (quote ,callback) ,buffer)))) (defun vc-svn-working-revision (file) "SVN-specific version of `vc-working-revision'." --- 158,185 ---- (vc-svn-command t 0 nil "status" (if localp "-v" "-u")) (vc-svn-parse-status)))) ! (defun vc-svn-dir-status (&optional kickp) ! "Return a list of conses (FILE . STATE) for the default directory." ! (if kickp ! ;; TODO: Conditionally synchronous. ! (vc-svn-command (current-buffer) 'async nil "status") ! (let ((state-map '((?A . added) ! (?C . edited) ! (?D . removed) ! (?I . ignored) ! (?M . edited) ! (?R . removed) ! (?? . unregistered) ! ;; This is what vc-svn-parse-status does. ! (?~ . edited))) ! result) ! (goto-char (point-min)) ! (while (re-search-forward "^\\(.\\)..... \\(.*\\)$" nil t) ! (let ((state (cdr (assq (aref (match-string 1) 0) state-map))) ! (filename (match-string 2))) ! (when state ! (setq result (cons (cons filename state) result))))) ! result))) (defun vc-svn-working-revision (file) "SVN-specific version of `vc-working-revision'." Index: vc.el =================================================================== RCS file: /sources/emacs/emacs/lisp/vc.el,v retrieving revision 1.537 diff -c -r1.537 vc.el *** vc.el 20 Feb 2008 18:11:15 -0000 1.537 --- vc.el 20 Feb 2008 18:15:50 -0000 *************** *** 167,184 **** ;; in older versions this method was not required to recurse into ;; subdirectories.) ;; ! ;; - dir-status (dir update-function status-buffer) ;; - ;; Produce RESULT: a list of conses of the form (file . vc-state) - ;; for the files in DIR. If a command needs to be run to compute - ;; this list, it should be run asynchronously. When RESULT is - ;; computed, it should be passed back by doing: - ;; (funcall UPDATE-FUNCTION RESULT STATUS-BUFFER) ;; This function is used by vc-status, a replacement for vc-dired. ;; vc-status is still under development, and is NOT feature ;; complete. As such, the requirements for this function might ! ;; change. ! ;; This is a replacement for dir-state. ;; ;; * working-revision (file) ;; --- 167,186 ---- ;; in older versions this method was not required to recurse into ;; subdirectories.) ;; ! ;; - dir-status (&optional kickp) ;; ;; This function is used by vc-status, a replacement for vc-dired. ;; vc-status is still under development, and is NOT feature ;; complete. As such, the requirements for this function might ! ;; change. This is a replacement for dir-state. ! ;; ! ;; Produce RESULT: a list of conses of the form (file . vc-state) ! ;; for the files in DIR. This function is called twice, the first ! ;; time with KICKP t, the second time, with KICKP nil. In both calls, ! ;; the current buffer is a scratch buffer with `default-directory' ! ;; set appropriately. If the backend workings are asynchronous, it ! ;; must use the current buffer as its process buffer. The return ! ;; value of the second call is RESULT. ;; ;; * working-revision (file) ;; *************** *** 918,923 **** --- 920,929 ---- (defvar vc-dired-mode nil) (make-variable-buffer-local 'vc-dired-mode) + (defsubst vc-overview-p () + "Return non-nil if current buffer is in VC Dired or VC Status mode." + (memq major-mode '(vc-dired-mode vc-status-mode))) + ;; File property caching (defun vc-clear-context () *************** *** 1794,1802 **** \(current one if no file). AFTER-HOOK specifies the local value for `vc-log-after-operation-hook'." (let ((parent ! (if (eq major-mode 'vc-dired-mode) ! ;; If we are called from VC dired, the parent buffer is ! ;; the current buffer. (current-buffer) (if (and files (equal (length files) 1)) (get-file-buffer (car files)) --- 1800,1806 ---- \(current one if no file). AFTER-HOOK specifies the local value for `vc-log-after-operation-hook'." (let ((parent ! (if (vc-overview-p) (current-buffer) (if (and files (equal (length files) 1)) (get-file-buffer (car files)) *************** *** 1934,1940 **** ;; Sync parent buffer in case the user modified it while editing the comment. ;; But not if it is a vc-dired buffer. (with-current-buffer vc-parent-buffer ! (or vc-dired-mode (vc-buffer-sync))) (if (not vc-log-operation) (error "No log operation is pending")) ;; save the parameters held in buffer-local variables --- 1938,1944 ---- ;; Sync parent buffer in case the user modified it while editing the comment. ;; But not if it is a vc-dired buffer. (with-current-buffer vc-parent-buffer ! (unless (vc-overview-p) (vc-buffer-sync))) (if (not vc-log-operation) (error "No log operation is pending")) ;; save the parameters held in buffer-local variables *************** *** 2642,2653 **** (defvar vc-status nil) - (defun vc-status-headers (backend dir) - (concat - (format "VC backend : %s\n" backend) - "Repository : The repository goes here\n" - (format "Working dir: %s\n" dir))) - (defun vc-status-printer (fileentry) "Pretty print FILEENTRY." ;; If you change the layout here, change vc-status-move-to-goal-column. --- 2646,2651 ---- *************** *** 2673,2684 **** ;;;###autoload (defun vc-status (dir) ! "Show the VC status for DIR." (interactive "DVC status for directory: ") ! (vc-setup-buffer "*vc-status*") ! (switch-to-buffer "*vc-status*") ! (cd dir) ! (vc-status-mode)) (defvar vc-status-mode-map (let ((map (make-keymap))) --- 2671,2697 ---- ;;;###autoload (defun vc-status (dir) ! "Show the VC status for DIR in its own buffer. ! Reuse an existing buffer if possible, otherwise create a new one ! and place it in `vc-status-mode'. Lastly, run `vc-status-refresh'." (interactive "DVC status for directory: ") ! (setq dir (file-name-as-directory dir)) ! (let ((ls (buffer-list)) ! buf) ! (while (and ls (not buf)) ! (with-current-buffer (car ls) ! (when (and vc-status (string= dir default-directory)) ! (setq buf (car ls))) ! (setq ls (cdr ls)))) ! (unless buf ! (set-buffer (setq buf (get-buffer-create ! (generate-new-buffer-name ! (file-name-nondirectory ! (directory-file-name dir)))))) ! (setq default-directory dir) ! (vc-status-mode)) ! (switch-to-buffer buf)) ! (vc-status-refresh)) (defvar vc-status-mode-map (let ((map (make-keymap))) *************** *** 2777,2818 **** (defun vc-status-mode () "Major mode for VC status. \\{vc-status-mode-map}" ! (setq mode-name "*VC Status*") ! (setq major-mode 'vc-status-mode) ! (setq buffer-read-only t) ! (use-local-map vc-status-mode-map) ! (let ((buffer-read-only nil) ! (backend (vc-responsible-backend default-directory)) ! entries) ! (erase-buffer) (set (make-local-variable 'vc-status) ! (ewoc-create #'vc-status-printer ! (vc-status-headers backend default-directory))) ! (vc-status-refresh))) (put 'vc-status-mode 'mode-class 'special) - (defun vc-update-vc-status-buffer (entries buffer) - (with-current-buffer buffer - (dolist (entry entries) - (ewoc-enter-last vc-status - (vc-status-create-fileinfo (cdr entry) (car entry)))) - (ewoc-goto-node vc-status (ewoc-nth vc-status 0)))) - (defun vc-status-refresh () ! "Refresh the contents of the VC status buffer." (interactive) ! ;; This is not very efficient; ewoc could use a new function here. ! (ewoc-filter vc-status (lambda (node) nil)) ! (let ((backend (vc-responsible-backend default-directory))) ! ;; Call the dir-status backend function. dir-status is supposed to ! ;; be asynchronous. It should compute the results and call the ! ;; function passed as a an arg to update the vc-status buffer with ! ;; the results. ! (vc-call-backend ! backend 'dir-status default-directory ! #'vc-update-vc-status-buffer (current-buffer)))) (defun vc-status-next-line (arg) "Go to the next line. --- 2790,2887 ---- (defun vc-status-mode () "Major mode for VC status. + Prepare the buffer to begin with the lines: + + Directory: DEFAULT-DIRECTORY + Updated: YYYY-MM-DD HH:MM:SS + + If the `default-directory' is under the project's \"root\" + directory, make its root component a button whose action is + to run command `vc-status' there. + + Keys do not self-insert; instead they do different things: \\{vc-status-mode-map}" ! (buffer-disable-undo) ! (erase-buffer) ! (let* ((backend (vc-responsible-backend default-directory)) ! (find-root (vc-find-backend-function backend 'root)) ! (root (if find-root ! (funcall find-root default-directory) ! default-directory))) ! (setq major-mode 'vc-status-mode) ! (setq mode-name (format "VC-%s Status" backend)) ! (insert "Directory: ") ! (if (or (not root) (string= root default-directory)) ! (insert root) ! (let* ((root-fn (directory-file-name root)) ! (parent (file-name-directory root-fn)) ! (leaf (file-name-nondirectory root-fn))) ! (insert parent) ! ;; As of 2007-08-21, loadup.el includes button, so this ! ;; check is just future-proofing; not strictly necessary. ! (if (featurep 'button) ! (insert-text-button ! leaf ! 'root root ! 'action (lambda (button) ! (vc-status (button-get button 'root))) ! 'follow-link t) ! (insert leaf)) ! (insert (substring default-directory (1- (length root)))))) ! (insert "\n") (set (make-local-variable 'vc-status) ! (ewoc-create #'vc-status-printer ! (format-time-string " Updated: %F %T\n"))) ! (use-local-map vc-status-mode-map) ! (setq buffer-read-only t))) (put 'vc-status-mode 'mode-class 'special) (defun vc-status-refresh () ! "Refresh the contents of the VC Status buffer." (interactive) ! (unless vc-status ! (error "Not in a VC Status buffer")) ! (ewoc-filter vc-status 'ignore) ! (let* ((backend (vc-responsible-backend default-directory)) ! (get-status (cond ((vc-find-backend-function backend 'dir-status)) ! (t (kill-buffer nil) ! (error "No vc-status support for %s" ! backend)))) ! (here (current-buffer)) ! (scratch (get-buffer-create (format " vc status: %s" ! default-directory))) ! notice) ! ;; Call the backend function in two-phase style. First, kick... ! (with-current-buffer scratch ! (erase-buffer) ! (funcall get-status t)) ! ;; Clue in the user if things are working asynchronously. ! (when (setq notice (buffer-local-value 'mode-line-process scratch)) ! (setq mode-line-process notice) ! (ewoc-set-hf vc-status ! (format " Updated: %s -- %s working...\n" ! (format-time-string "%F %T") ! backend) ! "")) ! (with-current-buffer scratch ! (vc-exec-after ! ;; ... then collect. ! `(let ((entries (,get-status))) ! (when (buffer-live-p ,here) ! (with-current-buffer ,here ! (dolist (entry entries) ! (ewoc-enter-last vc-status (vc-status-create-fileinfo ! (cdr entry) (car entry)))) ! (let ((first (ewoc-nth vc-status 0))) ! (when first ! (ewoc-goto-node vc-status first) ! (vc-status-move-to-goal-column)) ! (ewoc-set-hf vc-status ! (format-time-string " Updated: %F %T\n") ! (if first "" "(no entries)")) ! (setq mode-line-process nil)))) ! (kill-buffer nil)))))) (defun vc-status-next-line (arg) "Go to the next line. --=-=-=--