aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Nicolaescu2008-03-30 15:44:34 +0000
committerDan Nicolaescu2008-03-30 15:44:34 +0000
commit236b5827555913694962172b56a3fa91c3b2de6b (patch)
tree3552d15c5edd75c659f5addb01c245f00ac43469
parent58f10bffac5fa90a35685a06f284f5a38d279987 (diff)
downloademacs-236b5827555913694962172b56a3fa91c3b2de6b.tar.gz
emacs-236b5827555913694962172b56a3fa91c3b2de6b.zip
* vc-git.el: Make vc-status display information about copies,
renames and permission changes. (vc-git-extra-fileinfo): New defstruct. (vc-git-escape-file-name, vc-git-file-type-as-string) (vc-git-rename-as-string, vc-git-permissions-as-string) (vc-git-status-printer): New functions. (vc-git-after-dir-status-stage2): Also return vc-git-extra-fileinfo. (vc-git-after-dir-status-stage1): Look for copies, renames and permission changes. (vc-git-after-dir-status-stage1-empty-db): Set permissions. (vc-git-dir-status): Ask for staged files and renames.
-rw-r--r--lisp/ChangeLog14
-rw-r--r--lisp/vc-git.el130
2 files changed, 135 insertions, 9 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index e6bfdbac49a..fa92b9c04d1 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,17 @@
12008-03-30 Alexandre Julliard <julliard@winehq.org>
2
3 * vc-git.el: Make vc-status display information about copies,
4 renames and permission changes.
5 (vc-git-extra-fileinfo): New defstruct.
6 (vc-git-escape-file-name, vc-git-file-type-as-string)
7 (vc-git-rename-as-string, vc-git-permissions-as-string)
8 (vc-git-status-printer): New functions.
9 (vc-git-after-dir-status-stage2): Also return vc-git-extra-fileinfo.
10 (vc-git-after-dir-status-stage1): Look for copies, renames and
11 permission changes.
12 (vc-git-after-dir-status-stage1-empty-db): Set permissions.
13 (vc-git-dir-status): Ask for staged files and renames.
14
12008-03-30 Dan Nicolaescu <dann@ics.uci.edu> 152008-03-30 Dan Nicolaescu <dann@ics.uci.edu>
2 16
3 * vc.el: Allow backends to display backend specific information in 17 * vc.el: Allow backends to display backend specific information in
diff --git a/lisp/vc-git.el b/lisp/vc-git.el
index 795f57c245d..f3765aaba6f 100644
--- a/lisp/vc-git.el
+++ b/lisp/vc-git.el
@@ -208,23 +208,133 @@
208 (propertize def-ml 208 (propertize def-ml
209 'help-echo (concat help-echo "\nCurrent branch: " branch))))) 209 'help-echo (concat help-echo "\nCurrent branch: " branch)))))
210 210
211(defstruct (vc-git-extra-fileinfo
212 (:copier nil)
213 (:constructor vc-git-create-extra-fileinfo (old-perm new-perm &optional rename-state orig-name))
214 (:conc-name vc-git-extra-fileinfo->))
215 old-perm new-perm ;; permission flags
216 rename-state ;; rename or copy state
217 orig-name) ;; original name for renames or copies
218
219(defun vc-git-escape-file-name (name)
220 "Escape a file name if necessary."
221 (if (string-match "[\n\t\"\\]" name)
222 (concat "\""
223 (mapconcat (lambda (c)
224 (case c
225 (?\n "\\n")
226 (?\t "\\t")
227 (?\\ "\\\\")
228 (?\" "\\\"")
229 (t (char-to-string c))))
230 name "")
231 "\"")
232 name))
233
234(defun vc-git-file-type-as-string (old-perm new-perm)
235 "Return a string describing the file type based on its permissions."
236 (let* ((old-type (lsh (or old-perm 0) -9))
237 (new-type (lsh (or new-perm 0) -9))
238 (str (case new-type
239 (?\100 ;; file
240 (case old-type
241 (?\100 nil)
242 (?\120 " (type change symlink -> file)")
243 (?\160 " (type change subproject -> file)")))
244 (?\120 ;; symlink
245 (case old-type
246 (?\100 " (type change file -> symlink)")
247 (?\160 " (type change subproject -> symlink)")
248 (t " (symlink)")))
249 (?\160 ;; subproject
250 (case old-type
251 (?\100 " (type change file -> subproject)")
252 (?\120 " (type change symlink -> subproject)")
253 (t " (subproject)")))
254 (?\110 nil) ;; directory (internal, not a real git state)
255 (?\000 ;; deleted or unknown
256 (case old-type
257 (?\120 " (symlink)")
258 (?\160 " (subproject)")))
259 (t (format " (unknown type %o)" new-type)))))
260 (cond (str (propertize str 'face 'font-lock-comment-face))
261 ((eq new-type ?\110) "/")
262 (t ""))))
263
264(defun vc-git-rename-as-string (state extra)
265 "Return a string describing the copy or rename associated with INFO, or an empty string if none."
266 (let ((rename-state (when extra
267 (vc-git-extra-fileinfo->rename-state extra))))
268 (if rename-state
269 (propertize
270 (concat " ("
271 (if (eq rename-state 'copy) "copied from "
272 (if (eq state 'added) "renamed from "
273 "renamed to "))
274 (vc-git-escape-file-name (vc-git-extra-fileinfo->orig-name extra))
275 ")") 'face 'font-lock-comment-face)
276 "")))
277
278(defun vc-git-permissions-as-string (old-perm new-perm)
279 "Format a permission change as string."
280 (propertize
281 (if (or (not old-perm)
282 (not new-perm)
283 (eq 0 (logand ?\111 (logxor old-perm new-perm))))
284 " "
285 (if (eq 0 (logand ?\111 old-perm)) "+x" "-x"))
286 'face 'font-lock-type-face))
287
288(defun vc-git-status-printer (info)
289 "Pretty-printer for the vc-status-fileinfo structure."
290 (let* ((state (vc-status-fileinfo->state info))
291 (extra (vc-status-fileinfo->extra info))
292 (old-perm (when extra (vc-git-extra-fileinfo->old-perm extra)))
293 (new-perm (when extra (vc-git-extra-fileinfo->new-perm extra))))
294 (insert
295 " "
296 (propertize (format "%c" (if (vc-status-fileinfo->marked info) ?* ? ))
297 'face 'font-lock-type-face)
298 " "
299 (propertize
300 (format "%-12s" state)
301 'face (cond ((eq state 'up-to-date) 'font-lock-builtin-face)
302 ((eq state 'missing) 'font-lock-warning-face)
303 (t 'font-lock-variable-name-face))
304 'mouse-face 'highlight)
305 " " (vc-git-permissions-as-string old-perm new-perm)
306 " "
307 (propertize (vc-git-escape-file-name (vc-status-fileinfo->name info))
308 'face 'font-lock-function-name-face
309 'mouse-face 'highlight)
310 (vc-git-file-type-as-string old-perm new-perm)
311 (vc-git-rename-as-string state extra))))
312
211;; Variable used to keep the intermediate results for vc-git-status. 313;; Variable used to keep the intermediate results for vc-git-status.
212(defvar vc-git-status-result nil) 314(defvar vc-git-status-result nil)
213 315
214(defun vc-git-after-dir-status-stage2 (update-function status-buffer) 316(defun vc-git-after-dir-status-stage2 (update-function status-buffer)
215 (goto-char (point-min)) 317 (goto-char (point-min))
216 (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) 318 (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
217 (push (cons (match-string 1) 'unregistered) vc-git-status-result)) 319 (push (list (match-string 1) 'unregistered (vc-git-create-extra-fileinfo 0 0)) vc-git-status-result))
218 (funcall update-function (nreverse vc-git-status-result) status-buffer)) 320 (funcall update-function (nreverse vc-git-status-result) status-buffer))
219 321
220(defun vc-git-after-dir-status-stage1 (update-function status-buffer) 322(defun vc-git-after-dir-status-stage1 (update-function status-buffer)
221 (goto-char (point-min)) 323 (goto-char (point-min))
222 (while (re-search-forward 324 (while (re-search-forward
223 ":[0-7]\\{6\\} [0-7]\\{6\\} [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\([ADMUT]\\)\0\\([^\0]+\\)\0" 325 ":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMUT]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0"
224 nil t 1) 326 nil t 1)
225 (let ((filename (match-string 2)) 327 (let ((old-perm (string-to-number (match-string 1) 8))
226 (status (vc-git--state-code (match-string 1)))) 328 (new-perm (string-to-number (match-string 2) 8))
227 (push (cons filename status) vc-git-status-result))) 329 (state (or (match-string 4) (match-string 6)))
330 (name (or (match-string 5) (match-string 7)))
331 (new-name (match-string 8)))
332 (if new-name ; copy or rename
333 (if (eq ?C (string-to-char state))
334 (push (list new-name 'added (vc-git-create-extra-fileinfo old-perm new-perm 'copy name)) vc-git-status-result)
335 (push (list name 'removed (vc-git-create-extra-fileinfo 0 0 'rename new-name)) vc-git-status-result)
336 (push (list new-name 'added (vc-git-create-extra-fileinfo old-perm new-perm 'rename name)) vc-git-status-result))
337 (push (list name (vc-git--state-code state) (vc-git-create-extra-fileinfo old-perm new-perm)) vc-git-status-result))))
228 (erase-buffer) 338 (erase-buffer)
229 (vc-git-command (current-buffer) 'async nil "ls-files" "-z" "-o" 339 (vc-git-command (current-buffer) 'async nil "ls-files" "-z" "-o"
230 "--directory" "--no-empty-directory" "--exclude-standard") 340 "--directory" "--no-empty-directory" "--exclude-standard")
@@ -233,8 +343,10 @@
233 343
234(defun vc-git-after-dir-status-stage1-empty-db (update-function status-buffer) 344(defun vc-git-after-dir-status-stage1-empty-db (update-function status-buffer)
235 (goto-char (point-min)) 345 (goto-char (point-min))
236 (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) 346 (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t)
237 (push (cons (match-string 1) 'added) vc-git-status-result)) 347 (let ((new-perm (string-to-number (match-string 1) 8))
348 (name (match-string 2)))
349 (push (list name 'added (vc-git-create-extra-fileinfo 0 new-perm)) vc-git-status-result)))
238 (erase-buffer) 350 (erase-buffer)
239 (vc-git-command (current-buffer) 'async nil "ls-files" "-z" "-o" 351 (vc-git-command (current-buffer) 'async nil "ls-files" "-z" "-o"
240 "--directory" "--no-empty-directory" "--exclude-standard") 352 "--directory" "--no-empty-directory" "--exclude-standard")
@@ -249,11 +361,11 @@
249 (set (make-local-variable 'vc-git-status-result) nil) 361 (set (make-local-variable 'vc-git-status-result) nil)
250 (if (vc-git--empty-db-p) 362 (if (vc-git--empty-db-p)
251 (progn 363 (progn
252 (vc-git-command (current-buffer) 'async nil "ls-files" "-z" "-c") 364 (vc-git-command (current-buffer) 'async nil "ls-files" "-z" "-c" "-s")
253 (vc-exec-after 365 (vc-exec-after
254 `(vc-git-after-dir-status-stage1-empty-db 366 `(vc-git-after-dir-status-stage1-empty-db
255 (quote ,update-function) ,status-buffer))) 367 (quote ,update-function) ,status-buffer)))
256 (vc-git-command (current-buffer) 'async nil "diff-index" "-z" "HEAD") 368 (vc-git-command (current-buffer) 'async nil "diff-index" "-z" "-M" "HEAD")
257 (vc-exec-after 369 (vc-exec-after
258 `(vc-git-after-dir-status-stage1 (quote ,update-function) ,status-buffer)))) 370 `(vc-git-after-dir-status-stage1 (quote ,update-function) ,status-buffer))))
259 371