|
80 | 80 |
|
81 | 81 | (eval-when-compile (require 'cl)) ; to use `push', `pop'
|
82 | 82 |
|
| 83 | +(defface git-blame-prefix-face |
| 84 | + '((((background dark)) (:foreground "gray" |
| 85 | + :background "black")) |
| 86 | + (((background light)) (:foreground "gray" |
| 87 | + :background "white")) |
| 88 | + (t (:weight bold))) |
| 89 | + "The face used for the hash prefix." |
| 90 | + :group 'git-blame) |
| 91 | + |
| 92 | +(defgroup git-blame nil |
| 93 | + "A minor mode showing Git blame information." |
| 94 | + :group 'git |
| 95 | + :link '(function-link git-blame-mode)) |
| 96 | + |
| 97 | + |
| 98 | +(defcustom git-blame-use-colors t |
| 99 | + "Use colors to indicate commits in `git-blame-mode'." |
| 100 | + :type 'boolean |
| 101 | + :group 'git-blame) |
| 102 | + |
| 103 | +(defcustom git-blame-prefix-format |
| 104 | + "%h %20A:" |
| 105 | + "The format of the prefix added to each line in `git-blame' |
| 106 | +mode. The format is passed to `format-spec' with the following format keys: |
| 107 | +
|
| 108 | + %h - the abbreviated hash |
| 109 | + %H - the full hash |
| 110 | + %a - the author name |
| 111 | + %A - the author email |
| 112 | + %c - the committer name |
| 113 | + %C - the committer email |
| 114 | + %s - the commit summary |
| 115 | +" |
| 116 | + :group 'git-blame) |
| 117 | + |
| 118 | +(defcustom git-blame-mouseover-format |
| 119 | + "%h %a %A: %s" |
| 120 | + "The format of the description shown when pointing at a line in |
| 121 | +`git-blame' mode. The format string is passed to `format-spec' |
| 122 | +with the following format keys: |
| 123 | +
|
| 124 | + %h - the abbreviated hash |
| 125 | + %H - the full hash |
| 126 | + %a - the author name |
| 127 | + %A - the author email |
| 128 | + %c - the committer name |
| 129 | + %C - the committer email |
| 130 | + %s - the commit summary |
| 131 | +" |
| 132 | + :group 'git-blame) |
| 133 | + |
83 | 134 |
|
84 | 135 | (defun git-blame-color-scale (&rest elements)
|
85 | 136 | "Given a list, returns a list of triples formed with each
|
@@ -302,72 +353,69 @@ See also function `git-blame-mode'."
|
302 | 353 | (src-line (string-to-number (match-string 2)))
|
303 | 354 | (res-line (string-to-number (match-string 3)))
|
304 | 355 | (num-lines (string-to-number (match-string 4))))
|
305 |
| - (setq git-blame-current |
306 |
| - (if (string= hash "0000000000000000000000000000000000000000") |
307 |
| - nil |
308 |
| - (git-blame-new-commit |
309 |
| - hash src-line res-line num-lines)))) |
310 |
| - (delete-region (point) (match-end 0)) |
311 |
| - t) |
312 |
| - ((looking-at "filename \\(.+\\)\n") |
313 |
| - (let ((filename (match-string 1))) |
314 |
| - (git-blame-add-info "filename" filename)) |
315 |
| - (delete-region (point) (match-end 0)) |
| 356 | + (delete-region (point) (match-end 0)) |
| 357 | + (setq git-blame-current (list (git-blame-new-commit hash) |
| 358 | + src-line res-line num-lines))) |
316 | 359 | t)
|
317 | 360 | ((looking-at "\\([a-z-]+\\) \\(.+\\)\n")
|
318 | 361 | (let ((key (match-string 1))
|
319 | 362 | (value (match-string 2)))
|
320 |
| - (git-blame-add-info key value)) |
321 |
| - (delete-region (point) (match-end 0)) |
322 |
| - t) |
323 |
| - ((looking-at "boundary\n") |
324 |
| - (setq git-blame-current nil) |
325 |
| - (delete-region (point) (match-end 0)) |
| 363 | + (delete-region (point) (match-end 0)) |
| 364 | + (git-blame-add-info (car git-blame-current) key value) |
| 365 | + (when (string= key "filename") |
| 366 | + (git-blame-create-overlay (car git-blame-current) |
| 367 | + (caddr git-blame-current) |
| 368 | + (cadddr git-blame-current)) |
| 369 | + (setq git-blame-current nil))) |
326 | 370 | t)
|
327 | 371 | (t
|
328 | 372 | nil)))
|
329 | 373 |
|
330 |
| -(defun git-blame-new-commit (hash src-line res-line num-lines) |
| 374 | +(defun git-blame-new-commit (hash) |
| 375 | + (with-current-buffer git-blame-file |
| 376 | + (or (gethash hash git-blame-cache) |
| 377 | + ;; Assign a random color to each new commit info |
| 378 | + ;; Take care not to select the same color multiple times |
| 379 | + (let* ((color (if git-blame-colors |
| 380 | + (git-blame-random-pop git-blame-colors) |
| 381 | + git-blame-ancient-color)) |
| 382 | + (info `(,hash (color . ,color)))) |
| 383 | + (puthash hash info git-blame-cache) |
| 384 | + info)))) |
| 385 | + |
| 386 | +(defun git-blame-create-overlay (info start-line num-lines) |
331 | 387 | (save-excursion
|
332 | 388 | (set-buffer git-blame-file)
|
333 |
| - (let ((info (gethash hash git-blame-cache)) |
334 |
| - (inhibit-point-motion-hooks t) |
| 389 | + (let ((inhibit-point-motion-hooks t) |
335 | 390 | (inhibit-modification-hooks t))
|
336 |
| - (when (not info) |
337 |
| - ;; Assign a random color to each new commit info |
338 |
| - ;; Take care not to select the same color multiple times |
339 |
| - (let ((color (if git-blame-colors |
340 |
| - (git-blame-random-pop git-blame-colors) |
341 |
| - git-blame-ancient-color))) |
342 |
| - (setq info (list hash src-line res-line num-lines |
343 |
| - (git-describe-commit hash) |
344 |
| - (cons 'color color)))) |
345 |
| - (puthash hash info git-blame-cache)) |
346 |
| - (goto-line res-line) |
347 |
| - (while (> num-lines 0) |
348 |
| - (if (get-text-property (point) 'git-blame) |
349 |
| - (forward-line) |
350 |
| - (let* ((start (point)) |
351 |
| - (end (progn (forward-line 1) (point))) |
352 |
| - (ovl (make-overlay start end))) |
353 |
| - (push ovl git-blame-overlays) |
354 |
| - (overlay-put ovl 'git-blame info) |
355 |
| - (overlay-put ovl 'help-echo hash) |
| 391 | + (goto-line start-line) |
| 392 | + (let* ((start (point)) |
| 393 | + (end (progn (forward-line num-lines) (point))) |
| 394 | + (ovl (make-overlay start end)) |
| 395 | + (hash (car info)) |
| 396 | + (spec `((?h . ,(substring hash 0 6)) |
| 397 | + (?H . ,hash) |
| 398 | + (?a . ,(git-blame-get-info info 'author)) |
| 399 | + (?A . ,(git-blame-get-info info 'author-mail)) |
| 400 | + (?c . ,(git-blame-get-info info 'committer)) |
| 401 | + (?C . ,(git-blame-get-info info 'committer-mail)) |
| 402 | + (?s . ,(git-blame-get-info info 'summary))))) |
| 403 | + (push ovl git-blame-overlays) |
| 404 | + (overlay-put ovl 'git-blame info) |
| 405 | + (overlay-put ovl 'help-echo |
| 406 | + (format-spec git-blame-mouseover-format spec)) |
| 407 | + (if git-blame-use-colors |
356 | 408 | (overlay-put ovl 'face (list :background
|
357 |
| - (cdr (assq 'color (nthcdr 5 info))))) |
358 |
| - ;; the point-entered property doesn't seem to work in overlays |
359 |
| - ;;(overlay-put ovl 'point-entered |
360 |
| - ;; `(lambda (x y) (git-blame-identify ,hash))) |
361 |
| - (let ((modified (buffer-modified-p))) |
362 |
| - (put-text-property (if (= start 1) start (1- start)) (1- end) |
363 |
| - 'point-entered |
364 |
| - `(lambda (x y) (git-blame-identify ,hash))) |
365 |
| - (set-buffer-modified-p modified)))) |
366 |
| - (setq num-lines (1- num-lines)))))) |
367 |
| - |
368 |
| -(defun git-blame-add-info (key value) |
369 |
| - (if git-blame-current |
370 |
| - (nconc git-blame-current (list (cons (intern key) value))))) |
| 409 | + (cdr (assq 'color (cdr info)))))) |
| 410 | + (overlay-put ovl 'line-prefix |
| 411 | + (propertize (format-spec git-blame-prefix-format spec) |
| 412 | + 'face 'git-blame-prefix-face)))))) |
| 413 | + |
| 414 | +(defun git-blame-add-info (info key value) |
| 415 | + (nconc info (list (cons (intern key) value)))) |
| 416 | + |
| 417 | +(defun git-blame-get-info (info key) |
| 418 | + (cdr (assq key (cdr info)))) |
371 | 419 |
|
372 | 420 | (defun git-blame-current-commit ()
|
373 | 421 | (let ((info (get-char-property (point) 'git-blame)))
|
|
0 commit comments