238 lines
8.9 KiB
EmacsLisp
238 lines
8.9 KiB
EmacsLisp
;;; xhg-log.el --- Mercurial interface for dvc: mode for hg log style output
|
|
|
|
;; Copyright (C) 2005-2008 by all contributors
|
|
|
|
;; Author: Stefan Reichoer, <stefan@xsteve.at>
|
|
|
|
;; 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 mercurial interface for dvc: a mode to handle xhg log style output
|
|
|
|
;;; Commands:
|
|
;;
|
|
;; Below is a complete command list:
|
|
;;
|
|
;; `xhg-log-mode'
|
|
;; Major mode to display hg log output with embedded diffs. Derives from `diff-mode'.
|
|
;; `xhg-log-next'
|
|
;; Move to the next changeset header of the next diff hunk
|
|
;; `xhg-log-previous'
|
|
;; Move to the previous changeset header of the previous diff hunk
|
|
;; `xhg-log-dwim-next'
|
|
;; Either move to the next changeset via `xhg-log-next' or call `scroll-up'.
|
|
;; `xhg-log-toggle-diff-for-changeset'
|
|
;; Toggle displaying the diff for the current changeset.
|
|
;; `xhg-log-review-next-diff'
|
|
;; Close the previous viewed inline diff and open the next one for reviewing.
|
|
;; `xhg-log-review-previous-diff'
|
|
;; Close the previous viewed inline diff and open the previous one for reviewing.
|
|
;;
|
|
|
|
;;; History:
|
|
|
|
;;
|
|
|
|
;;; Code:
|
|
|
|
(require 'diff-mode)
|
|
|
|
(defvar xhg-log-mode-map
|
|
(let ((map (copy-keymap diff-mode-shared-map)))
|
|
(define-key map dvc-keyvec-help 'describe-mode)
|
|
(define-key map [?g] 'xhg-log)
|
|
(define-key map [?R] 'xhg-rollback)
|
|
(define-key map [?T] 'xhg-log-toggle-verbose)
|
|
(define-key map [?G] 'xhg-search-regexp-in-log)
|
|
(define-key map [?h] 'dvc-buffer-pop-to-partner-buffer)
|
|
(define-key map [?e] 'xhg-export)
|
|
(define-key map [?E] 'xhg-export-via-mail)
|
|
(define-key map [?s] 'xhg-status)
|
|
(define-key map [?=] 'xhg-log-toggle-diff-for-changeset)
|
|
(define-key map [?v] 'xhg-log-review-next-diff)
|
|
(define-key map [?V] 'xhg-log-review-previous-diff)
|
|
(define-key map dvc-keyvec-next 'xhg-log-next)
|
|
(define-key map dvc-keyvec-previous 'xhg-log-previous)
|
|
(define-key map [?\ ] 'xhg-log-dwim-next)
|
|
(define-key map dvc-keyvec-quit 'dvc-buffer-quit)
|
|
|
|
;; the merge group
|
|
(define-key map (dvc-prefix-merge ?u) 'dvc-update)
|
|
(define-key map (dvc-prefix-merge ?f) 'dvc-pull) ;; hint: fetch, p is reserved for push
|
|
(define-key map (dvc-prefix-merge ?m) '(lambda () (interactive) (dvc-missing nil default-directory)))
|
|
map)
|
|
"Keymap used in `xhg-log-mode'.")
|
|
|
|
(easy-menu-define xhg-log-mode-menu xhg-log-mode-map
|
|
"`xhg-log-mode' menu"
|
|
`("hg-log"
|
|
["Show status" dvc-status t] ;; `xhg-status' is not defined at compile time.
|
|
["Toggle embedded diff" xhg-log-toggle-diff-for-changeset t]
|
|
["Start Commiting" dvc-log-edit t]
|
|
["Export Changeset" xhg-export t]
|
|
["Export Changeset via Email" xhg-export-via-mail t]
|
|
))
|
|
|
|
|
|
(defvar xhg-log-font-lock-keywords
|
|
(append
|
|
'(("^changeset:" . font-lock-function-name-face)
|
|
("^branch:" . font-lock-function-name-face)
|
|
("^tag:" . font-lock-function-name-face)
|
|
("^user:" . font-lock-function-name-face)
|
|
("^date:" . font-lock-function-name-face)
|
|
("^summary:" . font-lock-function-name-face)
|
|
("^parent:" . font-lock-function-name-face))
|
|
diff-font-lock-keywords)
|
|
"Keywords in `xhg-log-mode' mode.")
|
|
|
|
(defvar xhg-log-review-current-diff-revision nil)
|
|
(defvar xhg-log-review-recenter-position-on-next-diff 5)
|
|
|
|
(define-derived-mode xhg-log-mode fundamental-mode "xhg-log"
|
|
"Major mode to display hg log output with embedded diffs. Derives from `diff-mode'.
|
|
|
|
Commands:
|
|
\\{xhg-log-mode-map}
|
|
"
|
|
(let ((diff-mode-shared-map (copy-keymap xhg-log-mode-map))
|
|
major-mode mode-name)
|
|
(diff-mode))
|
|
(set (make-local-variable 'font-lock-defaults)
|
|
(list 'xhg-log-font-lock-keywords t nil nil))
|
|
(set (make-local-variable 'xhg-log-review-current-diff-revision) nil))
|
|
|
|
(defconst xhg-log-start-regexp "^ *changeset: +\\([0-9]+:[0-9a-f]+\\)")
|
|
(defun xhg-log-next (n)
|
|
"Move to the next changeset header of the next diff hunk"
|
|
(interactive "p")
|
|
(end-of-line)
|
|
(re-search-forward xhg-log-start-regexp nil t n)
|
|
(beginning-of-line)
|
|
(when xhg-log-review-recenter-position-on-next-diff
|
|
(recenter xhg-log-review-recenter-position-on-next-diff)))
|
|
;; TODO: add (diff-hunk-next)
|
|
|
|
(defun xhg-log-previous (n)
|
|
"Move to the previous changeset header of the previous diff hunk"
|
|
(interactive "p")
|
|
(end-of-line)
|
|
(when (save-excursion
|
|
(beginning-of-line)
|
|
(looking-at xhg-log-start-regexp))
|
|
(re-search-backward xhg-log-start-regexp))
|
|
(re-search-backward xhg-log-start-regexp nil t n)
|
|
(when xhg-log-review-recenter-position-on-next-diff
|
|
(recenter xhg-log-review-recenter-position-on-next-diff)))
|
|
;; TODO: add (diff-hunk-prev)
|
|
|
|
(defun xhg-log-dwim-next ()
|
|
"Either move to the next changeset via `xhg-log-next' or call `scroll-up'.
|
|
When the beginning of the next changeset is already visible, call `xhg-log-next',
|
|
otherwise call `scroll-up'."
|
|
(interactive)
|
|
(let* ((start-pos (point))
|
|
(window-line (count-lines (window-start) start-pos))
|
|
(window-height (dvc-window-body-height))
|
|
(distance-to-next-changeset (save-window-excursion (xhg-log-next 1) (count-lines start-pos (point)))))
|
|
(goto-char start-pos)
|
|
(when (eq distance-to-next-changeset 0) ; last changeset
|
|
(setq distance-to-next-changeset (count-lines start-pos (point-max))))
|
|
(if (< (- window-height window-line) distance-to-next-changeset)
|
|
(scroll-up)
|
|
(xhg-log-next 1))))
|
|
|
|
(defun xhg-log-revision-at-point ()
|
|
(save-excursion
|
|
(end-of-line)
|
|
(re-search-backward xhg-log-start-regexp)
|
|
(match-string-no-properties 1)))
|
|
|
|
(defun xhg-log-inline-diff-opened-here ()
|
|
(save-excursion
|
|
(end-of-line)
|
|
(re-search-backward xhg-log-start-regexp)
|
|
(re-search-forward "^$")
|
|
(forward-line 1)
|
|
(looking-at "diff")))
|
|
|
|
(defun xhg-log-toggle-diff-for-changeset ()
|
|
"Toggle displaying the diff for the current changeset."
|
|
(interactive)
|
|
(let ((rev (xhg-log-revision-at-point))
|
|
(insert-diff))
|
|
(dvc-trace "xhg-log-toggle-diff-for-changeset %s" rev)
|
|
(save-excursion
|
|
(end-of-line)
|
|
(re-search-backward xhg-log-start-regexp)
|
|
(re-search-forward "^$")
|
|
(forward-line 1)
|
|
(setq insert-diff (not (looking-at "diff")))
|
|
(let ((buffer-read-only nil))
|
|
(save-excursion
|
|
(if insert-diff
|
|
(progn (save-excursion
|
|
(insert
|
|
(dvc-run-dvc-sync 'xhg (list "log" "-r" rev "-p")
|
|
:finished 'dvc-output-buffer-handler)))
|
|
(delete-region (point) (- (re-search-forward "^diff") 4)))
|
|
(delete-region (point)
|
|
(or (and (re-search-forward xhg-log-start-regexp nil t) (line-beginning-position))
|
|
(goto-char (point-max))))))))))
|
|
|
|
(defun xhg-log-goto-revision (rev)
|
|
"Move point to the revision REV. If REV is not found in the log buffer, do nothing."
|
|
(let ((rev-pos))
|
|
(save-excursion
|
|
(when
|
|
(re-search-forward (concat "^changeset: +" rev) nil t)
|
|
(setq rev-pos (point))))
|
|
(when rev-pos
|
|
(goto-char rev-pos))))
|
|
|
|
(defun xhg-log-review-next-diff (n)
|
|
"Close the previous viewed inline diff and open the next one for reviewing.
|
|
When invoked the first time, just open the diff at point via `xhg-log-toggle-diff-for-changeset'.
|
|
For every further invocation close the previously opened diff and open the next one.
|
|
N is the number of revisions to skip. Per default advance 1 revision."
|
|
(interactive "p")
|
|
(when (and (numberp n) (< n 0))
|
|
(setq n (- n 1)))
|
|
(let ((cur-pos (point)))
|
|
(when xhg-log-review-current-diff-revision
|
|
;; close the previous diff
|
|
(xhg-log-goto-revision xhg-log-review-current-diff-revision)
|
|
(when (xhg-log-inline-diff-opened-here)
|
|
(xhg-log-toggle-diff-for-changeset))
|
|
(if (eq n 0)
|
|
(goto-char cur-pos)
|
|
(xhg-log-next n)))
|
|
(setq xhg-log-review-current-diff-revision (xhg-log-revision-at-point))
|
|
(unless (xhg-log-inline-diff-opened-here)
|
|
(xhg-log-toggle-diff-for-changeset))
|
|
(when xhg-log-review-recenter-position-on-next-diff
|
|
(recenter xhg-log-review-recenter-position-on-next-diff))))
|
|
|
|
(defun xhg-log-review-previous-diff (n)
|
|
"Close the previous viewed inline diff and open the previous one for reviewing.
|
|
See `xhg-log-review-next-diff' for details."
|
|
(interactive "p")
|
|
(xhg-log-review-next-diff (- n)))
|
|
|
|
(provide 'xhg-log)
|
|
;;; xhg-log.el ends here
|