elisp-vcs/dvc/lisp/xgit-annotate.el
2009-10-10 08:02:43 +02:00

139 lines
5.7 KiB
EmacsLisp

;;; xgit-annotate.el --- Git interface for dvc: mode for git-annotate style output
;; Copyright (C) 2007-2009 by all contributors
;; Author: Takuzo O'hara, <takuzo.ohara@gmail.com>
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; The git interface for dvc: a mode to handle git-annotate style output
;;; Code:
(require 'dvc-annotate)
(require 'rect)
(defvar xgit-annotate-mode-map
(let ((map (make-sparse-keymap)))
(define-key map dvc-keyvec-help 'describe-mode)
(define-key map [return] 'xgit-annotate-show-rev)
(define-key map dvc-keyvec-quit 'dvc-buffer-quit)
map)
"Keymap used in `xgit-annotate-mode'.")
(define-derived-mode xgit-annotate-mode fundamental-mode "xgit-annotate"
"Major mode to display git annotate output.
Commands:
\\{xgit-annotate-mode-map}
"
(dvc-annotate-display-autoscale t)
(dvc-annotate-lines (point-max))
(xgit-annotate-hide-revinfo)
(toggle-read-only 1))
;; Matches to
;; e.g.
;; normal commit:
;; "ee6e815b (Takuzo Ohara 2007-02-23 12:24:57 +0900 1) ..."
;; or initial commit:
;; "^de398cf (Takuzo Ohara 2007-02-21 21:28:35 +0900 366) ..."
;; or not yet commited:
;; "00000000 (Not Committed Yet 2007-02-24 15:31:42 +0900 37) ..."
(defconst xgit-annotate-info-regexp "^\\(\\(\\^?\\([[:xdigit:]]+\\)\\)[[:blank:]]+.*(\\(.*?\\)[[:blank:]]+\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\) \\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\) \\([+-][0-9]\\{2\\}\\)\\([0-9]\\{2\\}\\)[[:blank:]]+\\)\\([0-9]+\\))")
(defun xgit-info-to-allbutlinenum () (match-string-no-properties 1))
(defun xgit-info-to-rev () (match-string-no-properties 2))
(defun xgit-info-to-initrev () (match-string-no-properties 3))
(defun xgit-info-to-name () (match-string-no-properties 4))
(defun xgit-info-to-year () (string-to-number (match-string-no-properties 5)))
(defun xgit-info-to-month () (string-to-number (match-string-no-properties 6)))
(defun xgit-info-to-day () (string-to-number (match-string-no-properties 7)))
(defun xgit-info-to-hour () (string-to-number (match-string-no-properties 8)))
(defun xgit-info-to-min () (string-to-number (match-string-no-properties 9)))
(defun xgit-info-to-sec () (string-to-number (match-string-no-properties 10)))
(defun xgit-info-to-zone-hour () (string-to-number (match-string-no-properties 11)))
(defun xgit-info-to-zone-min () (string-to-number (match-string-no-properties 12)))
(defun xgit-info-to-linenum () (string-to-number (match-string-no-properties 13)))
(defconst xgit-annotate-revision-regexp "^^?\\([[:xdigit:]]+\\)")
(defun xgit-annotate-get-rev ()
"Returns git revision at point in annotate buffer."
(if (< (point) (point-max))
(save-excursion
(beginning-of-line)
(if (looking-at xgit-annotate-info-regexp)
(xgit-info-to-rev)))))
(defun xgit-annotate-show-rev ()
"Show the information at the point."
(interactive)
(let ((rev (xgit-annotate-get-rev)))
(if (string-match xgit-annotate-revision-regexp rev)
;; initial version might result too large for git-show, so use
;; git-log.
(xgit-log default-directory nil :rev (match-string-no-properties 1 rev))
(xgit-show default-directory rev))
(xgit-describe default-directory rev)))
(defun _xgit-annotate-hide-revinfo ()
(let ((p_rev (xgit-annotate-get-rev))
(width (- (match-end 12) (line-beginning-position))))
(forward-line 1)
;; When revision of two subsequent lines are same:
(if (string= p_rev (xgit-annotate-get-rev))
(let ((start (line-beginning-position)))
;; forward until revision changes,
(while (string= p_rev (xgit-annotate-get-rev))
(forward-line 1))
;; point is at new revision so move back a line,
(unless (= (point) (point-max))
(previous-line 1))
;; match again to get position of right-bottom corner,
(xgit-annotate-get-rev)
;; rectangular replace by white space, from start to end.
(string-rectangle start (match-end 12) (make-string width ? ))))
))
(defun xgit-annotate-hide-revinfo ()
"Hide revision information when it is same as previous line's info."
(save-excursion
(goto-char (point-min))
(while (< (point) (point-max))
(_xgit-annotate-hide-revinfo))))
(defun xgit-annotate-time ()
(when (< (point) (point-max))
(beginning-of-line)
(if (re-search-forward xgit-annotate-info-regexp nil t)
(let* ((year (xgit-info-to-year))
(month (xgit-info-to-month))
(day (xgit-info-to-day))
(hour (xgit-info-to-hour))
(min (xgit-info-to-min))
(sec (xgit-info-to-sec))
(zone-hour (xgit-info-to-zone-hour))
(zone-min (xgit-info-to-zone-min))
(zone-sec (* 60 (+ (* 60 zone-hour) zone-min))))
(dvc-annotate-convert-time
(encode-time sec min hour day month year zone-sec))
))))
(provide 'xgit-annotate)
;;; xgit-annotate.el ends here