All of lore.kernel.org
 help / color / mirror / Atom feed
* git-blame.el
@ 2007-01-31 13:04 David Kågedal
  2007-01-31 18:22 ` git-blame.el Randal L. Schwartz
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: David Kågedal @ 2007-01-31 13:04 UTC (permalink / raw)
  To: git

Here's another version of git-blame.el that automatically tries to
create a sensible list of colors to use for both light and dark
backgrounds.  Plus a few minor fixes.

To use:

  1) Load into emacs: M-x load-file RET git-blame.el RET
  2) Open a git-controlled file
  3) Blame: M-x git-blame-mode

;;; git-blame.el
;; David Kågedal

(defun color-scale (l)
  (let* ((colors ())
         r g b)
    (setq r l)
    (while r
      (setq g l)
      (while g
        (setq b l)
        (while b
          (push (concat "#" (car r) (car g) (car b)) colors)
          (pop b))
        (pop g))
      (pop r))
    colors))

(defvar git-blame-dark-colors
  (color-scale '("00" "04" "08" "0c"
                 "10" "14" "18" "1c"
                 "20" "24" "28" "2c"
                 "30" "34" "38" "3c")))

(defvar git-blame-light-colors
  (color-scale '("c0" "c4" "c8" "cc"
                 "d0" "d4" "d8" "dc"
                 "e0" "e4" "e8" "ec"
                 "f0" "f4" "f8" "fc")))

(defvar git-blame-ancient-color "dark green")

(defvar git-blame-overlays nil)
(defvar git-blame-cache nil)

(defvar git-blame-mode nil)
(make-variable-buffer-local 'git-blame-mode)
(push (list 'git-blame-mode " blame") minor-mode-alist)

(defun git-blame-mode (&optional arg)
  (interactive "P")
  (if arg
      (setq git-blame-mode (eq arg 1))
    (setq git-blame-mode (not git-blame-mode)))
  (make-local-variable 'git-blame-overlays)
  (make-local-variable 'git-blame-colors)
  (make-local-variable 'git-blame-cache)
  (let ((bgmode (cdr (assoc 'background-mode (frame-parameters)))))
    (if (eq bgmode 'dark)
        (setq git-blame-colors git-blame-dark-colors)
      (setq git-blame-colors git-blame-light-colors)))
  (if git-blame-mode
      (git-blame-run)
    (git-blame-cleanup)))

(defun git-blame-run ()
  (let* ((display-buf (current-buffer))
         (blame-buf (get-buffer-create
                     (concat " git blame for " (buffer-name))))
         (proc (start-process "git-blame" blame-buf
                             "git" "blame" "--incremental"
                             (file-name-nondirectory buffer-file-name))))
    (mapcar 'delete-overlay git-blame-overlays)
    (setq git-blame-overlays nil)
    (setq git-blame-cache (make-hash-table :test 'equal))
    (with-current-buffer blame-buf
      (erase-buffer)
      (make-local-variable 'git-blame-file)
      (make-local-variable 'git-blame-current)
      (setq git-blame-file display-buf)
      (setq git-blame-current nil))
    (set-process-filter proc 'git-blame-filter)
    (set-process-sentinel proc 'git-blame-sentinel)))

(defun git-blame-cleanup ()
  "Remove all blame properties"
    (mapcar 'delete-overlay git-blame-overlays)
    (setq git-blame-overlays nil)
    (let ((modified (buffer-modified-p)))
      (remove-text-properties (point-min) (point-max) '(point-entered nil))
      (set-buffer-modified-p modified)))
    

(defun git-blame-sentinel (proc status)
  ;;(kill-buffer (process-buffer proc))
  (message "git blame finished"))

(defvar in-blame-filter nil)

(defun git-blame-filter (proc str)
  (save-excursion
    (set-buffer (process-buffer proc))
    (goto-char (process-mark proc))
    (insert-before-markers str)
    (goto-char 0)
    (unless in-blame-filter
      (let ((more t)
            (in-blame-filter t))
        (while more
          (setq more (git-blame-parse)))))))

(defun git-blame-parse ()
  (cond ((looking-at "\\([0-9a-f]\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)\n")
         (let ((hash (match-string 1))
               (src-line (string-to-number (match-string 2)))
               (res-line (string-to-number (match-string 3)))
               (num-lines (string-to-number (match-string 4))))
           (setq git-blame-current
                 (git-blame-new-commit
                  hash src-line res-line num-lines)))
         (delete-region (point) (match-end 0))
         t)
        ((looking-at "filename \\(.+\\)\n")
         (let ((filename (match-string 1)))
           (git-blame-add-info "filename" filename))
         (delete-region (point) (match-end 0))
         t)
        ((looking-at "\\([a-z-]+\\) \\(.+\\)\n")
         (let ((key (match-string 1))
               (value (match-string 2)))
           (git-blame-add-info key value))
         (delete-region (point) (match-end 0))
         t)
        ((looking-at "boundary\n")
         (setq git-blame-current nil)
         (delete-region (point) (match-end 0))
         t)
        (t
         nil)))


(defun git-blame-new-commit (hash src-line res-line num-lines)
  (save-excursion
    (set-buffer git-blame-file)
    (let ((info (gethash hash git-blame-cache))
          (inhibit-point-motion-hooks t))
      (when (not info)
        (let ((color (pop git-blame-colors)))
          (unless color
            (setq color git-blame-ancient-color))
          (setq info (list hash src-line res-line num-lines
                           (cons 'color color))))
        (puthash hash info git-blame-cache))
      (goto-line res-line)
      (while (> num-lines 0)
        (if (get-text-property (point) 'git-blame)
            (forward-line)
          (let* ((start (point))
                 (end (progn (forward-line 1) (point)))
                 (ovl (make-overlay start end)))
            (push ovl git-blame-overlays)
            (overlay-put ovl 'git-blame info)
            (overlay-put ovl 'help-echo hash)
            (overlay-put ovl 'face (list :background
                                         (cdr (assq 'color (cddddr info)))))
            ;;(overlay-put ovl 'point-entered
            ;;             `(lambda (x y) (git-blame-identify ,hash)))
            (let ((modified (buffer-modified-p)))
              (put-text-property (if (= start 1) start (1- start)) (1- end)
                                 'point-entered
                                 `(lambda (x y) (git-blame-identify ,hash)))
              (set-buffer-modified-p modified))))
        (setq num-lines (1- num-lines))))))

(defun git-blame-add-info (key value)
  (if git-blame-current
      (nconc git-blame-current (list (cons (intern key) value)))))

(defun git-blame-current-commit ()
  (let ((info (get-char-property (point) 'git-blame)))
    (if info
        (car info)
      (error "No commit info"))))

(defun git-blame-identify (&optional hash)
  (interactive)
  (shell-command
   (format "git log -1 --pretty=oneline %s" (or hash
                                                (git-blame-current-commit)))))

-- 
David Kågedal

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git-blame.el
  2007-01-31 13:04 git-blame.el David Kågedal
@ 2007-01-31 18:22 ` Randal L. Schwartz
  2007-01-31 20:53   ` git-blame.el David Kågedal
  2007-01-31 20:07 ` git-blame.el Junio C Hamano
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Randal L. Schwartz @ 2007-01-31 18:22 UTC (permalink / raw)
  To: David Kågedal; +Cc: git

>>>>> "David" == David Kågedal <davidk@lysator.liu.se> writes:

David> Here's another version of git-blame.el that automatically tries to
David> create a sensible list of colors to use for both light and dark
David> backgrounds.  Plus a few minor fixes.

If this gets traction, this should be what vc-annotate uses on a git file.

-- 
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git-blame.el
  2007-01-31 13:04 git-blame.el David Kågedal
  2007-01-31 18:22 ` git-blame.el Randal L. Schwartz
@ 2007-01-31 20:07 ` Junio C Hamano
  2007-01-31 20:27   ` git-blame.el David Kågedal
  2007-02-01 13:12 ` git-blame.el Karl Hasselström
  2007-02-04 20:04 ` [PATCH] git-blame.el --- Minor mode for incremental blame for Git Jakub Narebski
  3 siblings, 1 reply; 9+ messages in thread
From: Junio C Hamano @ 2007-01-31 20:07 UTC (permalink / raw)
  To: David Kågedal; +Cc: git

I seem to be getting tons of these; wouldn't you want some (require)?

error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr
error in process filter: assq: Symbol's function definition is void: cddddr
error in process filter: Symbol's function definition is void: cddddr

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git-blame.el
  2007-01-31 20:07 ` git-blame.el Junio C Hamano
@ 2007-01-31 20:27   ` David Kågedal
  0 siblings, 0 replies; 9+ messages in thread
From: David Kågedal @ 2007-01-31 20:27 UTC (permalink / raw)
  To: git

Junio C Hamano <junkio@cox.net> writes:

> I seem to be getting tons of these; wouldn't you want some (require)?

Yeah, I apparently need a (require 'cl)

I try to stay away from cl by habit, but since I usually have it
required by something I use, I might use it without noticing.

So, to try it, add (require 'cl) to the top of the file.

-- 
David Kågedal

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git-blame.el
  2007-01-31 18:22 ` git-blame.el Randal L. Schwartz
@ 2007-01-31 20:53   ` David Kågedal
  0 siblings, 0 replies; 9+ messages in thread
From: David Kågedal @ 2007-01-31 20:53 UTC (permalink / raw)
  To: git

merlyn@stonehenge.com (Randal L. Schwartz) writes:

>>>>>> "David" == David Kågedal <davidk@lysator.liu.se> writes:
>
> David> Here's another version of git-blame.el that automatically tries to
> David> create a sensible list of colors to use for both light and dark
> David> backgrounds.  Plus a few minor fixes.
>
> If this gets traction, this should be what vc-annotate uses on a git file.

I only had a very quick glance, but one "problem" is that vc-annotate
assumes that what you want to do is to run an annotate/blame command
and show the output in another buffer.  My solution is a minor-mode
that shows the blame directly in the edit buffer, and I'm not sure how
easy it would be to convince vc that this is what I want.  And I need
a way to turn it off again, and maybe some local key bindings when it
is active.  This all points to the fact that a minor mode is really
the thing to use.  So maybe I should simply rebind C-x v g to
git-blame-mode instead of vc-annotate...

-- 
David Kågedal

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git-blame.el
  2007-01-31 13:04 git-blame.el David Kågedal
  2007-01-31 18:22 ` git-blame.el Randal L. Schwartz
  2007-01-31 20:07 ` git-blame.el Junio C Hamano
@ 2007-02-01 13:12 ` Karl Hasselström
  2007-02-01 13:21   ` git-blame.el David Kågedal
  2007-02-04 20:04 ` [PATCH] git-blame.el --- Minor mode for incremental blame for Git Jakub Narebski
  3 siblings, 1 reply; 9+ messages in thread
From: Karl Hasselström @ 2007-02-01 13:12 UTC (permalink / raw)
  To: David Kågedal; +Cc: git

On 2007-01-31 14:04:06 +0100, David Kågedal wrote:

> Here's another version of git-blame.el that automatically tries to
> create a sensible list of colors to use for both light and dark
> backgrounds. Plus a few minor fixes.

I've tried it, like the concept of in-buffer blame and the pretty
colors, and have a few comments and suggestions:

  1. For some files, but not all, emacs is unresponsive (and consumes
     lots of CPU) right after git-blame-mode is activated. Once
     git-blame has finished, it becomes responsive again, but this
     kind of defeats the whole "incremental" idea.

     This is most easily seen by holdnig down Ctrl+N or similar, to
     make the cursor move constantly.

  2. Getting to see the sha1 of the commit is not so useful when it
     can't be selected for copy-pasting. Maybe a keyboard shortcut for
     "copy-sha1-to-kill-ring"?

  3. Even after I've edited a line, or added a new line, they continue
     to be attributed to the same existing commits. They should either
     have no attribution, or possibly just "local edit" or something.
     I seem to recall this kind of functionality for git-blame being
     discussed very recently?

  4. It would be nice with a keyboard shortcut that (in a new buffer)
     printed more details about the commit under the cursor, kind of
     like the output from git-log. (Having this available would
     obviate the need for (2).)

  5. It would be nice with a keyboard shortcut for displaying the
     commit under the cursor in gitk. (For extra points: successive
     uses of this command should reuse the same gitk window if it's
     still open.)

  6. It would be nice with a keyboard shortcut for displaying (in a
     separate buffer) the diff to that file introduced by the commit
     under the cursor. This could be combined with (3) by having
     commit details followed by diff.

Oh, and try to have it done by Monday. ;-)

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git-blame.el
  2007-02-01 13:12 ` git-blame.el Karl Hasselström
@ 2007-02-01 13:21   ` David Kågedal
  2007-02-01 14:26     ` git-blame.el Karl Hasselström
  0 siblings, 1 reply; 9+ messages in thread
From: David Kågedal @ 2007-02-01 13:21 UTC (permalink / raw)
  To: git

Karl Hasselström <kha@treskal.com> writes:

> On 2007-01-31 14:04:06 +0100, David Kågedal wrote:
>
>> Here's another version of git-blame.el that automatically tries to
>> create a sensible list of colors to use for both light and dark
>> backgrounds. Plus a few minor fixes.
>
> I've tried it, like the concept of in-buffer blame and the pretty
> colors, and have a few comments and suggestions:
>
>   1. For some files, but not all, emacs is unresponsive (and consumes
>      lots of CPU) right after git-blame-mode is activated. Once
>      git-blame has finished, it becomes responsive again, but this
>      kind of defeats the whole "incremental" idea.
>
>      This is most easily seen by holdnig down Ctrl+N or similar, to
>      make the cursor move constantly.

Don't know why this happens.  I haven't seen it myself.

>   2. Getting to see the sha1 of the commit is not so useful when it
>      can't be selected for copy-pasting. Maybe a keyboard shortcut for
>      "copy-sha1-to-kill-ring"?

Sure.  It's a trivial addition.

>   3. Even after I've edited a line, or added a new line, they continue
>      to be attributed to the same existing commits. They should either
>      have no attribution, or possibly just "local edit" or something.
>      I seem to recall this kind of functionality for git-blame being
>      discussed very recently?

I saw it was discussed, but I don't think it was added.  Currently, it
probably makes most sense to verify that the file hasn't been
modified, and then switch to read-only mode while viewing the blame.

>   4. It would be nice with a keyboard shortcut that (in a new buffer)
>      printed more details about the commit under the cursor, kind of
>      like the output from git-log. (Having this available would
>      obviate the need for (2).)
>
>   5. It would be nice with a keyboard shortcut for displaying the
>      commit under the cursor in gitk. (For extra points: successive
>      uses of this command should reuse the same gitk window if it's
>      still open.)

This is almost as trivial as 2, since the hash is available, you can
simply run shell-command.

>   6. It would be nice with a keyboard shortcut for displaying (in a
>      separate buffer) the diff to that file introduced by the commit
>      under the cursor. This could be combined with (3) by having
>      commit details followed by diff.

As in "git log -p", you mean?

> Oh, and try to have it done by Monday. ;-)

Sorry Kalle.  I won't have any more spare cycles until next week.

-- 
David Kågedal

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git-blame.el
  2007-02-01 13:21   ` git-blame.el David Kågedal
@ 2007-02-01 14:26     ` Karl Hasselström
  0 siblings, 0 replies; 9+ messages in thread
From: Karl Hasselström @ 2007-02-01 14:26 UTC (permalink / raw)
  To: David Kågedal; +Cc: git

On 2007-02-01 14:21:29 +0100, David Kågedal wrote:

> Karl Hasselström <kha@treskal.com> writes:
>
> >   3. Even after I've edited a line, or added a new line, they
> >      continue to be attributed to the same existing commits. They
> >      should either have no attribution, or possibly just "local
> >      edit" or something. I seem to recall this kind of
> >      functionality for git-blame being discussed very recently?
>
> I saw it was discussed, but I don't think it was added. Currently,
> it probably makes most sense to verify that the file hasn't been
> modified, and then switch to read-only mode while viewing the blame.

Hmm, probably, yes. But it'll be kind of limiting to not be able to
run blame on a file that has local modifications. I think I understand
why vc-annotate opens a new buffer ...

> >   6. It would be nice with a keyboard shortcut for displaying (in
> >      a separate buffer) the diff to that file introduced by the
> >      commit under the cursor. This could be combined with (3) by
> >      having commit details followed by diff.
>
> As in "git log -p", you mean?

Yes. I was thinking of exactly what "git log -p $hash^..$hash"
produces. The Emacs windows should be split in two frames, with the
commit details + diff in the lower frame, just like vc-diff.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH] git-blame.el --- Minor mode for incremental blame for Git
  2007-01-31 13:04 git-blame.el David Kågedal
                   ` (2 preceding siblings ...)
  2007-02-01 13:12 ` git-blame.el Karl Hasselström
@ 2007-02-04 20:04 ` Jakub Narebski
  3 siblings, 0 replies; 9+ messages in thread
From: Jakub Narebski @ 2007-02-04 20:04 UTC (permalink / raw)
  To: git; +Cc: David Kagedal, Alexandre Julliard, Jakub Narebski

Here is an Emacs implementation of incremental git-blame.  When you
turn it on while viewing a file, the editor buffer will be updated by
setting the background of individual lines to a color that reflects
which commit it comes from.  And when you move around the buffer, a
one-line summary will be shown in the echo area.

Created by David Kågedal, header and comments added by Jakub Narębski.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
Signed-off-by: David KÃ¥gedal <davidk@lysator.liu.se>
---
Here it is as a proper git patch, and with some headers and comments
added. As compared to latest version sent by David KÃ¥gedal,
  Message-ID: <87iren2vqx.fsf@morpheus.local>
  http://permalink.gmane.org/gmane.comp.version-control.git/38246
it has elisp header and description by David KÃ¥gedal, has (require 'cl)
with explanation added, and (provide 'git-blame) at the end; no other
changes (as of now).

David, is it released as GPL? If it is, GPL boilerplate (as in git.el)
could be added to the header.

 contrib/emacs/git-blame.el |  222 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 222 insertions(+), 0 deletions(-)

diff --git a/contrib/emacs/git-blame.el b/contrib/emacs/git-blame.el
new file mode 100644
index 0000000..fa89889
--- /dev/null
+++ b/contrib/emacs/git-blame.el
@@ -0,0 +1,222 @@
+;;; git-blame.el --- Minor mode for incremental blame for Git  -*- coding: utf-8 -*-
+;;
+;; Copyright (C) 2007 by David KÃ¥gedal
+;;
+;; Authors:    David KÃ¥gedal <davidk@lysator.liu.se>
+;; Created:    31 Jan 2007
+;; Keywords:   git, version control, release management
+;;
+;; Compatibility: Emacs21
+
+;;; Commentary:
+;;
+;; Here is an Emacs implementation of incremental git-blame.  When you
+;; turn it on while viewing a file, the editor buffer will be updated by
+;; setting the background of individual lines to a color that reflects
+;; which commit it comes from.  And when you move around the buffer, a
+;; one-line summary will be shown in the echo area.
+
+;;; Installation:
+;;
+;;  1) Load into emacs: M-x load-file RET git-blame.el RET
+;;  2) Open a git-controlled file
+;;  3) Blame: M-x git-blame-mode
+
+;;; Compatibility:
+;;
+;; It requires GNU Emacs 21.  If you'are using Emacs 20, try
+;; changing this:
+;;
+;;            (overlay-put ovl 'face (list :background
+;;                                         (cdr (assq 'color (cddddr info)))))
+;;
+;; to
+;;
+;;            (overlay-put ovl 'face (cons 'background-color
+;;                                         (cdr (assq 'color (cddddr info)))))
+
+
+;;; Code:
+
+(require 'cl)			      ; to use `cddddr', `push', `pop'
+
+(defun color-scale (l)
+  (let* ((colors ())
+         r g b)
+    (setq r l)
+    (while r
+      (setq g l)
+      (while g
+        (setq b l)
+        (while b
+          (push (concat "#" (car r) (car g) (car b)) colors)
+          (pop b))
+        (pop g))
+      (pop r))
+    colors))
+
+(defvar git-blame-dark-colors
+  (color-scale '("00" "04" "08" "0c"
+                 "10" "14" "18" "1c"
+                 "20" "24" "28" "2c"
+                 "30" "34" "38" "3c")))
+
+(defvar git-blame-light-colors
+  (color-scale '("c0" "c4" "c8" "cc"
+                 "d0" "d4" "d8" "dc"
+                 "e0" "e4" "e8" "ec"
+                 "f0" "f4" "f8" "fc")))
+
+(defvar git-blame-ancient-color "dark green")
+
+(defvar git-blame-overlays nil)
+(defvar git-blame-cache nil)
+
+(defvar git-blame-mode nil)
+(make-variable-buffer-local 'git-blame-mode)
+(push (list 'git-blame-mode " blame") minor-mode-alist)
+
+(defun git-blame-mode (&optional arg)
+  (interactive "P")
+  (if arg
+      (setq git-blame-mode (eq arg 1))
+    (setq git-blame-mode (not git-blame-mode)))
+  (make-local-variable 'git-blame-overlays)
+  (make-local-variable 'git-blame-colors)
+  (make-local-variable 'git-blame-cache)
+   (let ((bgmode (cdr (assoc 'background-mode (frame-parameters)))))
+    (if (eq bgmode 'dark)
+        (setq git-blame-colors git-blame-dark-colors)
+      (setq git-blame-colors git-blame-light-colors)))
+  (if git-blame-mode
+      (git-blame-run)
+    (git-blame-cleanup)))
+
+(defun git-blame-run ()
+  (let* ((display-buf (current-buffer))
+         (blame-buf (get-buffer-create
+                     (concat " git blame for " (buffer-name))))
+         (proc (start-process "git-blame" blame-buf
+                             "git" "blame" "--incremental"
+                             (file-name-nondirectory buffer-file-name))))
+    (mapcar 'delete-overlay git-blame-overlays)
+    (setq git-blame-overlays nil)
+    (setq git-blame-cache (make-hash-table :test 'equal))
+    (with-current-buffer blame-buf
+      (erase-buffer)
+      (make-local-variable 'git-blame-file)
+      (make-local-variable 'git-blame-current)
+      (setq git-blame-file display-buf)
+      (setq git-blame-current nil))
+    (set-process-filter proc 'git-blame-filter)
+    (set-process-sentinel proc 'git-blame-sentinel)))
+
+(defun git-blame-cleanup ()
+  "Remove all blame properties"
+    (mapcar 'delete-overlay git-blame-overlays)
+    (setq git-blame-overlays nil)
+    (let ((modified (buffer-modified-p)))
+      (remove-text-properties (point-min) (point-max) '(point-entered nil))
+      (set-buffer-modified-p modified)))
+
+
+(defun git-blame-sentinel (proc status)
+  ;;(kill-buffer (process-buffer proc))
+  (message "git blame finished"))
+
+(defvar in-blame-filter nil)
+
+(defun git-blame-filter (proc str)
+  (save-excursion
+    (set-buffer (process-buffer proc))
+    (goto-char (process-mark proc))
+    (insert-before-markers str)
+    (goto-char 0)
+    (unless in-blame-filter
+      (let ((more t)
+            (in-blame-filter t))
+        (while more
+          (setq more (git-blame-parse)))))))
+
+(defun git-blame-parse ()
+  (cond ((looking-at "\\([0-9a-f]\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)\n")
+         (let ((hash (match-string 1))
+               (src-line (string-to-number (match-string 2)))
+               (res-line (string-to-number (match-string 3)))
+               (num-lines (string-to-number (match-string 4))))
+           (setq git-blame-current
+                 (git-blame-new-commit
+                  hash src-line res-line num-lines)))
+         (delete-region (point) (match-end 0))
+         t)
+        ((looking-at "filename \\(.+\\)\n")
+         (let ((filename (match-string 1)))
+           (git-blame-add-info "filename" filename))
+         (delete-region (point) (match-end 0))
+         t)
+        ((looking-at "\\([a-z-]+\\) \\(.+\\)\n")
+         (let ((key (match-string 1))
+               (value (match-string 2)))
+           (git-blame-add-info key value))
+         (delete-region (point) (match-end 0))
+         t)
+        ((looking-at "boundary\n")
+         (setq git-blame-current nil)
+         (delete-region (point) (match-end 0))
+         t)
+        (t
+         nil)))
+
+
+(defun git-blame-new-commit (hash src-line res-line num-lines)
+  (save-excursion
+    (set-buffer git-blame-file)
+    (let ((info (gethash hash git-blame-cache))
+          (inhibit-point-motion-hooks t))
+      (when (not info)
+        (let ((color (pop git-blame-colors)))
+          (unless color
+            (setq color git-blame-ancient-color))
+          (setq info (list hash src-line res-line num-lines
+                           (cons 'color color))))
+        (puthash hash info git-blame-cache))
+      (goto-line res-line)
+      (while (> num-lines 0)
+        (if (get-text-property (point) 'git-blame)
+            (forward-line)
+          (let* ((start (point))
+                 (end (progn (forward-line 1) (point)))
+                 (ovl (make-overlay start end)))
+            (push ovl git-blame-overlays)
+            (overlay-put ovl 'git-blame info)
+            (overlay-put ovl 'help-echo hash)
+            (overlay-put ovl 'face (list :background
+                                         (cdr (assq 'color (cddddr info)))))
+            ;;(overlay-put ovl 'point-entered
+            ;;             `(lambda (x y) (git-blame-identify ,hash)))
+            (let ((modified (buffer-modified-p)))
+              (put-text-property (if (= start 1) start (1- start)) (1- end)
+                                 'point-entered
+                                 `(lambda (x y) (git-blame-identify ,hash)))
+              (set-buffer-modified-p modified))))
+        (setq num-lines (1- num-lines))))))
+
+(defun git-blame-add-info (key value)
+  (if git-blame-current
+      (nconc git-blame-current (list (cons (intern key) value)))))
+
+(defun git-blame-current-commit ()
+  (let ((info (get-char-property (point) 'git-blame)))
+    (if info
+        (car info)
+      (error "No commit info"))))
+
+(defun git-blame-identify (&optional hash)
+  (interactive)
+  (shell-command
+   (format "git log -1 --pretty=oneline %s" (or hash
+                                                (git-blame-current-commit)))))
+
+(provide 'git-blame)
+
+;;; git-blame.el ends here
-- 
1.4.4.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2007-02-04 20:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-01-31 13:04 git-blame.el David Kågedal
2007-01-31 18:22 ` git-blame.el Randal L. Schwartz
2007-01-31 20:53   ` git-blame.el David Kågedal
2007-01-31 20:07 ` git-blame.el Junio C Hamano
2007-01-31 20:27   ` git-blame.el David Kågedal
2007-02-01 13:12 ` git-blame.el Karl Hasselström
2007-02-01 13:21   ` git-blame.el David Kågedal
2007-02-01 14:26     ` git-blame.el Karl Hasselström
2007-02-04 20:04 ` [PATCH] git-blame.el --- Minor mode for incremental blame for Git Jakub Narebski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.