comparison lisp/vc.el @ 94003:2ecb2ea8d5b5

Change `dir-status' to not take (and pass) status-buffer. (vc-status-create-fileinfo): Make `extra' optional. (vc-status-busy): New fun. (vc-status-menu-map): Use it. (vc-status-crt-marked): Remove. (vc-status-update): Rename from vc-status-add-entries. Add argument so as to prevent addition of entries. Rewrite. (vc-update-vc-status-buffer): Remove. (vc-status-refresh): Don't remove old entries, set them to up-to-date instead. Also do it after the update is complete. (vc-status-marked-files): ¦Ç-reduce.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Fri, 11 Apr 2008 15:17:59 +0000
parents bfc762f0b49c
children c249cf124bd6
comparison
equal deleted inserted replaced
94002:bae1479690d4 94003:2ecb2ea8d5b5
166 ;; rather store the files' states into the corresponding properties. 166 ;; rather store the files' states into the corresponding properties.
167 ;; Two properties are required: `vc-backend' and `vc-state'. (Note: 167 ;; Two properties are required: `vc-backend' and `vc-state'. (Note:
168 ;; in older versions this method was not required to recurse into 168 ;; in older versions this method was not required to recurse into
169 ;; subdirectories.) 169 ;; subdirectories.)
170 ;; 170 ;;
171 ;; - dir-status (dir update-function status-buffer) 171 ;; - dir-status (dir update-function)
172 ;; 172 ;;
173 ;; Produce RESULT: a list of lists of the form (FILE VC-STATE EXTRA) 173 ;; Produce RESULT: a list of lists of the form (FILE VC-STATE EXTRA)
174 ;; for the files in DIR. 174 ;; for the files in DIR.
175 ;; EXTRA can be used for backend specific information about FILE. 175 ;; EXTRA can be used for backend specific information about FILE.
176 ;; If a command needs to be run to compute this list, it should be 176 ;; If a command needs to be run to compute this list, it should be
177 ;; run asynchronously using (current-buffer) as the buffer for the 177 ;; run asynchronously using (current-buffer) as the buffer for the
178 ;; command. When RESULT is computed, it should be passed back by 178 ;; command. When RESULT is computed, it should be passed back by
179 ;; doing: (funcall UPDATE-FUNCTION RESULT STATUS-BUFFER nil). 179 ;; doing: (funcall UPDATE-FUNCTION RESULT nil).
180 ;; If the backend uses a process filter, hence it produces partial results, 180 ;; If the backend uses a process filter, hence it produces partial results,
181 ;; they can be passed back by doing: 181 ;; they can be passed back by doing:
182 ;; (funcall UPDATE-FUNCTION RESULT STATUS-BUFFER t) 182 ;; (funcall UPDATE-FUNCTION RESULT t)
183 ;; and then do a (funcall UPDATE-FUNCTION RESULT STATUS-BUFFER nil) 183 ;; and then do a (funcall UPDATE-FUNCTION RESULT nil)
184 ;; when all the results have been computed. 184 ;; when all the results have been computed.
185 ;; To provide more backend specific functionality for `vc-status' 185 ;; To provide more backend specific functionality for `vc-status'
186 ;; the following functions might be needed: `status-extra-headers', 186 ;; the following functions might be needed: `status-extra-headers',
187 ;; `status-printer', `extra-status-menu' and `status-fileinfo-extra'. 187 ;; `status-printer', `extra-status-menu' and `status-fileinfo-extra'.
188 ;; This function is used by `vc-status', a replacement for 188 ;; This function is used by `vc-status', a replacement for
580 ;; is specific to a backend and which does not map to any of the VC 580 ;; is specific to a backend and which does not map to any of the VC
581 ;; generic concepts. 581 ;; generic concepts.
582 582
583 ;;; Todo: 583 ;;; Todo:
584 584
585 ;; - vc-status-kill-dir-status-process should not be specific to dir-status,
586 ;; it should work for other async commands as well (pull/push/...).
587 ;;
585 ;; - vc-update/vc-merge should deal with VC systems that don't 588 ;; - vc-update/vc-merge should deal with VC systems that don't
586 ;; update/merge on a file basis, but on a whole repository basis. 589 ;; update/merge on a file basis, but on a whole repository basis.
587 ;; 590 ;;
588 ;; - deal with push/pull operations. 591 ;; - deal with push/pull operations.
589 ;; 592 ;;
1436 (dolist (f (cdr marked)) 1439 (dolist (f (cdr marked))
1437 (unless (eq (vc-backend f) firstbackend) 1440 (unless (eq (vc-backend f) firstbackend)
1438 (error "All members of a fileset must be under the same version-control system.")))) 1441 (error "All members of a fileset must be under the same version-control system."))))
1439 marked)) 1442 marked))
1440 ((eq major-mode 'vc-status-mode) 1443 ((eq major-mode 'vc-status-mode)
1441 (let ((marked (vc-status-marked-files))) 1444 (or (vc-status-marked-files)
1442 (if marked 1445 (list (vc-status-current-file))))
1443 marked
1444 (list (vc-status-current-file)))))
1445 ((vc-backend buffer-file-name) 1446 ((vc-backend buffer-file-name)
1446 (list buffer-file-name)) 1447 (list buffer-file-name))
1447 ((and vc-parent-buffer (or (buffer-file-name vc-parent-buffer) 1448 ((and vc-parent-buffer (or (buffer-file-name vc-parent-buffer)
1448 (with-current-buffer vc-parent-buffer 1449 (with-current-buffer vc-parent-buffer
1449 (or vc-dired-mode (eq major-mode 'vc-status-mode))))) 1450 (or vc-dired-mode (eq major-mode 'vc-status-mode)))))
2703 2704
2704 ;; Used to store information for the files displayed in the *VC status* buffer. 2705 ;; Used to store information for the files displayed in the *VC status* buffer.
2705 ;; Each item displayed corresponds to one of these defstructs. 2706 ;; Each item displayed corresponds to one of these defstructs.
2706 (defstruct (vc-status-fileinfo 2707 (defstruct (vc-status-fileinfo
2707 (:copier nil) 2708 (:copier nil)
2709 (:type list) ;So we can use `member' on lists of FIs.
2708 (:constructor 2710 (:constructor
2709 vc-status-create-fileinfo (name state extra &optional marked)) 2711 ;; We could define it as an alias for `list'.
2712 vc-status-create-fileinfo (name state &optional extra marked))
2710 (:conc-name vc-status-fileinfo->)) 2713 (:conc-name vc-status-fileinfo->))
2711 marked 2714 name ;Keep it as first, for `member'.
2712 state 2715 state
2713 name
2714 ;; For storing backend specific information. 2716 ;; For storing backend specific information.
2715 extra) 2717 extra
2718 marked)
2716 2719
2717 (defvar vc-status nil) 2720 (defvar vc-status nil)
2718 2721
2719 (defun vc-default-status-extra-headers (backend dir) 2722 (defun vc-default-status-extra-headers (backend dir)
2720 ;; Be loud by default to remind people to add coded to display 2723 ;; Be loud by default to remind people to add coded to display
2802 (define-key map [quit] 2805 (define-key map [quit]
2803 '(menu-item "Quit" bury-buffer 2806 '(menu-item "Quit" bury-buffer
2804 :help "Quit")) 2807 :help "Quit"))
2805 (define-key map [kill] 2808 (define-key map [kill]
2806 '(menu-item "Kill Update Command" vc-status-kill-dir-status-process 2809 '(menu-item "Kill Update Command" vc-status-kill-dir-status-process
2807 :enable vc-status-process-buffer 2810 :enable (vc-status-busy)
2808 :help "Kill the command that updates VC status buffer")) 2811 :help "Kill the command that updates VC status buffer"))
2809 (define-key map [refresh] 2812 (define-key map [refresh]
2810 '(menu-item "Refresh" vc-status-refresh 2813 '(menu-item "Refresh" vc-status-refresh
2811 :enable (not vc-status-process-buffer) 2814 :enable (not (vc-status-busy))
2812 :help "Refresh the contents of the VC status buffer")) 2815 :help "Refresh the contents of the VC status buffer"))
2813 (define-key map [remup] 2816 (define-key map [remup]
2814 '(menu-item "Hide up-to-date" vc-status-hide-up-to-date 2817 '(menu-item "Hide up-to-date" vc-status-hide-up-to-date
2815 :help "Hide up-to-date items from display")) 2818 :help "Hide up-to-date items from display"))
2816 ;; VC commands. 2819 ;; VC commands.
2972 map)) 2975 map))
2973 2976
2974 (defvar vc-status-process-buffer nil 2977 (defvar vc-status-process-buffer nil
2975 "The buffer used for the asynchronous call that computes the VC status.") 2978 "The buffer used for the asynchronous call that computes the VC status.")
2976 2979
2977 (defvar vc-status-crt-marked nil
2978 "The list of marked files before `vc-status-refresh'.")
2979
2980 (defun vc-status-mode () 2980 (defun vc-status-mode ()
2981 "Major mode for VC status. 2981 "Major mode for VC status.
2982 \\{vc-status-mode-map}" 2982 \\{vc-status-mode-map}"
2983 (setq mode-name "VC Status") 2983 (setq mode-name "VC Status")
2984 (setq major-mode 'vc-status-mode) 2984 (setq major-mode 'vc-status-mode)
2985 (setq buffer-read-only t) 2985 (setq buffer-read-only t)
2986 (set (make-local-variable 'vc-status-crt-marked) nil)
2987 (use-local-map vc-status-mode-map) 2986 (use-local-map vc-status-mode-map)
2988 (set (make-local-variable 'tool-bar-map) vc-status-tool-bar-map) 2987 (set (make-local-variable 'tool-bar-map) vc-status-tool-bar-map)
2989 (let ((buffer-read-only nil) 2988 (let ((buffer-read-only nil)
2990 (backend (vc-responsible-backend default-directory)) 2989 (backend (vc-responsible-backend default-directory))
2991 entries) 2990 entries)
2997 (add-hook 'after-save-hook 'vc-status-mark-buffer-changed) 2996 (add-hook 'after-save-hook 'vc-status-mark-buffer-changed)
2998 (vc-status-refresh))) 2997 (vc-status-refresh)))
2999 2998
3000 (put 'vc-status-mode 'mode-class 'special) 2999 (put 'vc-status-mode 'mode-class 'special)
3001 3000
3002 (defun vc-status-add-entries (entries buffer) 3001 (defun vc-status-update (entries buffer &optional noinsert)
3002 "Update BUFFER's ewoc from the list of ENTRIES.
3003 If NOINSERT, ignore elements on ENTRIES which are not in the ewoc."
3003 ;; Add ENTRIES to the vc-status buffer BUFFER. 3004 ;; Add ENTRIES to the vc-status buffer BUFFER.
3004 (with-current-buffer buffer 3005 (with-current-buffer buffer
3005 (when entries 3006 ;; Insert the entries sorted by name into the ewoc.
3006 ;; Insert the entries sorted by name into the ewoc. 3007 ;; We assume the ewoc is sorted too, which should be the
3007 ;; We assume the ewoc is sorted too, which should be the 3008 ;; case if we always add entries with vc-status-update.
3008 ;; case if we always add entries with vc-status-add-entries. 3009 (setq entries (sort entries
3009 (setq entries (sort (copy-sequence entries) 3010 (lambda (entry1 entry2)
3010 (lambda (entry1 entry2) 3011 (string-lessp (car entry1) (car entry2)))))
3011 (string-lessp (car entry1) (car entry2))))) 3012 (let ((entry (car entries))
3012 (let ((entry (pop entries)) 3013 (node (ewoc-nth vc-status 0)))
3013 (node (ewoc-nth vc-status 0))) 3014 (while (and entry node)
3014 (while entry 3015 (let ((entryfile (car entry))
3015 (while (and vc-status-crt-marked 3016 (nodefile (vc-status-fileinfo->name (ewoc-data node))))
3016 (string-lessp (car vc-status-crt-marked) (car entry))) 3017 (cond
3017 (setq vc-status-crt-marked (cdr vc-status-crt-marked))) 3018 ((string-lessp nodefile entryfile)
3018 (let* ((file (car entry)) 3019 (setq node (ewoc-next vc-status node)))
3019 (state (nth 1 entry)) 3020 ((string-lessp nodefile entryfile)
3020 (extra (nth 2 entry)) 3021 (unless noinsert
3021 (marked (and vc-status-crt-marked 3022 (ewoc-enter-before vc-status node
3022 (string-equal (car vc-status-crt-marked) file)))) 3023 (apply 'vc-status-create-fileinfo entry)))
3023 (cond ((not node) 3024 (setq entries (cdr entries) entry (car entries)))
3024 (setq node (ewoc-enter-last vc-status 3025 (t
3025 (vc-status-create-fileinfo file state extra marked))) 3026 (setf (vc-status-fileinfo->state (ewoc-data node)) (nth 1 entry))
3026 (setq entry (pop entries))) 3027 (setf (vc-status-fileinfo->extra (ewoc-data node)) (nth 2 entry))
3027 ((string-lessp (vc-status-fileinfo->name (ewoc-data node)) file) 3028 (ewoc-invalidate vc-status node)
3028 (setq node (ewoc-next vc-status node))) 3029 (setq entries (cdr entries) entry (car entries))
3029 ((string-equal (vc-status-fileinfo->name (ewoc-data node)) file) 3030 (setq node (ewoc-next vc-status node))))))
3030 (setf (vc-status-fileinfo->state (ewoc-data node)) state) 3031 (unless (or node noinsert)
3031 (setf (vc-status-fileinfo->extra (ewoc-data node)) extra) 3032 ;; We're past the last node, all remaining entries go to the end.
3032 (ewoc-invalidate vc-status node) 3033 (while entries
3033 (setq entry (pop entries))) 3034 (ewoc-enter-last vc-status
3034 (t 3035 (apply 'vc-status-create-fileinfo (pop entries))))))))
3035 (setq node (ewoc-enter-before vc-status node 3036
3036 (vc-status-create-fileinfo file state extra marked))) 3037 (defun vc-status-busy ()
3037 (setq entry (pop entries)))))))))) 3038 (and (buffer-live-p vc-status-process-buffer)
3038 3039 (get-buffer-process vc-status-process-buffer)))
3039 (defun vc-update-vc-status-buffer (entries buffer &optional more-to-come)
3040 ;; ENTRIES is a list of (FILE VC_STATE EXTRA) items.
3041 ;; BUFFER is the *vc-status* buffer to be updated with ENTRIES
3042 ;; If MORE-TO-COME is true, then more updates will come from the
3043 ;; asynchronous process.
3044 (with-current-buffer buffer
3045 (when entries
3046 (vc-status-add-entries entries buffer)
3047 (ewoc-goto-node vc-status (ewoc-nth vc-status 0)))
3048 ;; No more updates are expected from the asynchronous process.
3049 (unless more-to-come
3050 (setq vc-status-process-buffer nil)
3051 ;; We are done, turn off the mode-line "in progress" message.
3052 (setq mode-line-process nil))))
3053 3040
3054 (defun vc-status-refresh () 3041 (defun vc-status-refresh ()
3055 "Refresh the contents of the VC status buffer. 3042 "Refresh the contents of the VC status buffer.
3056 Throw an error if another update process is in progress." 3043 Throw an error if another update process is in progress."
3057 (interactive) 3044 (interactive)
3058 (if vc-status-process-buffer 3045 (if (vc-status-busy)
3059 (error "Another update process is in progress, cannot run two at a time") 3046 (error "Another update process is in progress, cannot run two at a time")
3060 ;; We clear the ewoc, but remember the marked files so that we can
3061 ;; mark them again after the refresh is done.
3062 ;; This is not very efficient; ewoc could use a new function here.
3063 (setq vc-status-crt-marked
3064 (mapcar
3065 (lambda (elem)
3066 (vc-status-fileinfo->name elem))
3067 (ewoc-collect
3068 vc-status
3069 (lambda (crt) (vc-status-fileinfo->marked crt)))))
3070 (ewoc-filter vc-status (lambda (node) nil))
3071
3072 (let ((backend (vc-responsible-backend default-directory)) 3047 (let ((backend (vc-responsible-backend default-directory))
3073 (status-buffer (current-buffer)) 3048 (status-buffer (current-buffer))
3074 (def-dir default-directory)) 3049 (def-dir default-directory))
3075 (vc-set-mode-line-busy-indicator) 3050 (vc-set-mode-line-busy-indicator)
3076 ;; Call the `dir-status' backend function. 3051 ;; Call the `dir-status' backend function.
3082 ;; Create a buffer that can be used by `dir-status' and call 3057 ;; Create a buffer that can be used by `dir-status' and call
3083 ;; `dir-status' with this buffer as the current buffer. Use 3058 ;; `dir-status' with this buffer as the current buffer. Use
3084 ;; `vc-status-process-buffer' to remember this buffer, so that 3059 ;; `vc-status-process-buffer' to remember this buffer, so that
3085 ;; it can be used later to kill the update process in case it 3060 ;; it can be used later to kill the update process in case it
3086 ;; takes too long. 3061 ;; takes too long.
3087 (setq vc-status-process-buffer 3062 (unless (buffer-live-p vc-status-process-buffer)
3088 (get-buffer-create 3063 (setq vc-status-process-buffer
3089 (generate-new-buffer-name (format " *VC-%s* tmp status" backend)))) 3064 (generate-new-buffer (format " *VC-%s* tmp status" backend))))
3090 (with-current-buffer vc-status-process-buffer 3065 (lexical-let ((oldentries (ewoc-collect vc-status (lambda (_) t)))
3091 (cd def-dir) 3066 (buffer (current-buffer)))
3092 (erase-buffer) 3067 (with-current-buffer vc-status-process-buffer
3093 (vc-call-backend backend 'dir-status def-dir 3068 (cd def-dir)
3094 #'vc-update-vc-status-buffer status-buffer))))) 3069 (erase-buffer)
3070 (vc-call-backend
3071 backend 'dir-status def-dir
3072 (lambda (entries &optional more-to-come)
3073 ;; ENTRIES is a list of (FILE VC_STATE EXTRA) items.
3074 ;; If MORE-TO-COME is true, then more updates will come from
3075 ;; the asynchronous process.
3076 (with-current-buffer buffer
3077 (dolist (entry entries)
3078 (setq oldentries
3079 (delq (member (car entry) oldentries) oldentries)))
3080 (vc-status-update entries buffer)
3081 (ewoc-goto-node vc-status (ewoc-nth vc-status 0))
3082 ;; No more updates are expected from the asynchronous process.
3083 (unless more-to-come
3084 ;; We are done, turn off the mode-line "in progress" message.
3085 (setq mode-line-process nil)
3086 ;; Update old entries that were not mentioned, and were
3087 ;; hence implicitly given as uptodate.
3088 (dolist (entry oldentries)
3089 (setf (vc-status-fileinfo->state entry) 'up-to-date))
3090 (vc-status-update oldentries buffer 'noinsert))))))))))
3095 3091
3096 (defun vc-status-kill-dir-status-process () 3092 (defun vc-status-kill-dir-status-process ()
3097 "Kill the temporary buffer and associated process." 3093 "Kill the temporary buffer and associated process."
3098 (interactive) 3094 (interactive)
3099 (when (buffer-live-p vc-status-process-buffer) 3095 (when (buffer-live-p vc-status-process-buffer)
3234 (vc-status-mark-unmark 'vc-status-toggle-mark-file)) 3230 (vc-status-mark-unmark 'vc-status-toggle-mark-file))
3235 3231
3236 (defun vc-status-register () 3232 (defun vc-status-register ()
3237 "Register the marked files, or the current file if no marks." 3233 "Register the marked files, or the current file if no marks."
3238 (interactive) 3234 (interactive)
3239 (let ((files (or (vc-status-marked-files) 3235 ;; FIXME: Just pass the fileset to vc-register.
3240 (list (vc-status-current-file))))) 3236 (mapc 'vc-register (or (vc-status-marked-files)
3241 (dolist (file files) 3237 (list (vc-status-current-file)))))
3242 (vc-register file))))
3243 3238
3244 (defun vc-status-find-file () 3239 (defun vc-status-find-file ()
3245 "Find the file on the current line." 3240 "Find the file on the current line."
3246 (interactive) 3241 (interactive)
3247 (find-file (vc-status-current-file))) 3242 (find-file (vc-status-current-file)))
3258 (expand-file-name (vc-status-fileinfo->name (ewoc-data node))))) 3253 (expand-file-name (vc-status-fileinfo->name (ewoc-data node)))))
3259 3254
3260 (defun vc-status-marked-files () 3255 (defun vc-status-marked-files ()
3261 "Return the list of marked files" 3256 "Return the list of marked files"
3262 (mapcar 3257 (mapcar
3263 (lambda (elem) 3258 (lambda (elem) (expand-file-name (vc-status-fileinfo->name elem)))
3264 (expand-file-name (vc-status-fileinfo->name elem))) 3259 (ewoc-collect vc-status 'vc-status-fileinfo->marked)))
3265 (ewoc-collect
3266 vc-status
3267 (lambda (crt) (vc-status-fileinfo->marked crt)))))
3268 3260
3269 (defun vc-status-hide-up-to-date () 3261 (defun vc-status-hide-up-to-date ()
3270 "Hide up-to-date items from display." 3262 "Hide up-to-date items from display."
3271 (interactive) 3263 (interactive)
3272 (ewoc-filter 3264 (ewoc-filter
3295 (extra 3287 (extra
3296 (and backend 3288 (and backend
3297 (vc-call-backend backend 'status-fileinfo-extra file))) 3289 (vc-call-backend backend 'status-fileinfo-extra file)))
3298 (entry 3290 (entry
3299 (list file-short (if state state 'unregistered) extra))) 3291 (list file-short (if state state 'unregistered) extra)))
3300 (vc-status-add-entries (list entry) status-buf)))))) 3292 (vc-status-update (list entry) status-buf))))))
3301 ;; We didn't find any vc-status buffers, remove the hook, it is 3293 ;; We didn't find any vc-status buffers, remove the hook, it is
3302 ;; not needed. 3294 ;; not needed.
3303 (unless found-vc-status-buf (remove-hook 'after-save-hook 'vc-status-mark-buffer-changed))))) 3295 (unless found-vc-status-buf (remove-hook 'after-save-hook 'vc-status-mark-buffer-changed)))))
3304 3296
3305 ;; Named-configuration entry points 3297 ;; Named-configuration entry points