changelog shortlog graph tags branches files raw help

Mercurial > infra > home / changeset: add back official mercurial emacs packages

changeset 40: 2d74d85d7031
parent 31: 85a897f49ad1
child 43: d70be963bfb1
author: Richard Westhaver <ellis@rwest.io>
date: Wed, 05 Jun 2024 23:31:48 +0000
files: .emacs.d/lib/mercurial.el .emacs.d/lib/mq.el
description: add back official mercurial emacs packages
     1.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2+++ b/.emacs.d/lib/mercurial.el	Wed Jun 05 23:31:48 2024 +0000
     1.3@@ -0,0 +1,1293 @@
     1.4+;;; mercurial.el --- Emacs support for the Mercurial distributed SCM
     1.5+
     1.6+;; Copyright (C) 2005, 2006 Bryan O'Sullivan
     1.7+
     1.8+;; Author: Bryan O'Sullivan <bos@serpentine.com>
     1.9+
    1.10+;; mercurial.el is free software; you can redistribute it and/or
    1.11+;; modify it under the terms of the GNU General Public License version
    1.12+;; 2 or any later version.
    1.13+
    1.14+;; mercurial.el is distributed in the hope that it will be useful, but
    1.15+;; WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.17+;; General Public License for more details.
    1.18+
    1.19+;; You should have received a copy of the GNU General Public License
    1.20+;; along with mercurial.el, GNU Emacs, or XEmacs; see the file COPYING
    1.21+;; (`C-h C-l').  If not, see <http://www.gnu.org/licenses/>.
    1.22+
    1.23+;;; Commentary:
    1.24+
    1.25+;; mercurial.el builds upon Emacs's VC mode to provide flexible
    1.26+;; integration with the Mercurial distributed SCM tool.
    1.27+
    1.28+;; To get going as quickly as possible, load mercurial.el into Emacs and
    1.29+;; type `C-c h h'; this runs hg-help-overview, which prints a helpful
    1.30+;; usage overview.
    1.31+
    1.32+;; Much of the inspiration for mercurial.el comes from Rajesh
    1.33+;; Vaidheeswarran's excellent p4.el, which does an admirably thorough
    1.34+;; job for the commercial Perforce SCM product.  In fact, substantial
    1.35+;; chunks of code are adapted from p4.el.
    1.36+
    1.37+;; This code has been developed under XEmacs 21.5, and may not work as
    1.38+;; well under GNU Emacs (albeit tested under 21.4).  Patches to
    1.39+;; enhance the portability of this code, fix bugs, and add features
    1.40+;; are most welcome.
    1.41+
    1.42+;; As of version 22.3, GNU Emacs's VC mode has direct support for
    1.43+;; Mercurial, so this package may not prove as useful there.
    1.44+
    1.45+;; Please send problem reports and suggestions to bos@serpentine.com.
    1.46+
    1.47+
    1.48+;;; Code:
    1.49+
    1.50+(eval-when-compile (require 'cl))
    1.51+(require 'diff-mode)
    1.52+(require 'easymenu)
    1.53+(require 'executable)
    1.54+(require 'vc)
    1.55+
    1.56+(defmacro hg-feature-cond (&rest clauses)
    1.57+  "Test CLAUSES for feature at compile time.
    1.58+Each clause is (FEATURE BODY...)."
    1.59+  (dolist (x clauses)
    1.60+    (let ((feature (car x))
    1.61+	  (body (cdr x)))
    1.62+      (when (or (eq feature t)
    1.63+		(featurep feature))
    1.64+	(return (cons 'progn body))))))
    1.65+
    1.66+
    1.67+;;; XEmacs has view-less, while GNU Emacs has view.  Joy.
    1.68+
    1.69+(hg-feature-cond
    1.70+ (xemacs (require 'view-less))
    1.71+ (t (require 'view)))
    1.72+
    1.73+
    1.74+;;; Variables accessible through the custom system.
    1.75+
    1.76+(defgroup mercurial nil
    1.77+  "Mercurial distributed SCM."
    1.78+  :group 'tools)
    1.79+
    1.80+(defcustom hg-binary
    1.81+    (or (executable-find "hg")
    1.82+	(dolist (path '("~/bin/hg" "/usr/bin/hg" "/usr/local/bin/hg"))
    1.83+	  (when (file-executable-p path)
    1.84+	    (return path))))
    1.85+  "The path to Mercurial's hg executable."
    1.86+  :type '(file :must-match t)
    1.87+  :group 'mercurial)
    1.88+
    1.89+(defcustom hg-mode-hook nil
    1.90+  "Hook run when a buffer enters hg-mode."
    1.91+  :type 'sexp
    1.92+  :group 'mercurial)
    1.93+
    1.94+(defcustom hg-commit-mode-hook nil
    1.95+  "Hook run when a buffer is created to prepare a commit."
    1.96+  :type 'sexp
    1.97+  :group 'mercurial)
    1.98+
    1.99+(defcustom hg-pre-commit-hook nil
   1.100+  "Hook run before a commit is performed.
   1.101+If you want to prevent the commit from proceeding, raise an error."
   1.102+  :type 'sexp
   1.103+  :group 'mercurial)
   1.104+
   1.105+(defcustom hg-log-mode-hook nil
   1.106+  "Hook run after a buffer is filled with log information."
   1.107+  :type 'sexp
   1.108+  :group 'mercurial)
   1.109+
   1.110+(defcustom hg-global-prefix "\C-ch"
   1.111+  "The global prefix for Mercurial keymap bindings."
   1.112+  :type 'sexp
   1.113+  :group 'mercurial)
   1.114+
   1.115+(defcustom hg-commit-allow-empty-message nil
   1.116+  "Whether to allow changes to be committed with empty descriptions."
   1.117+  :type 'boolean
   1.118+  :group 'mercurial)
   1.119+
   1.120+(defcustom hg-commit-allow-empty-file-list nil
   1.121+  "Whether to allow changes to be committed without any modified files."
   1.122+  :type 'boolean
   1.123+  :group 'mercurial)
   1.124+
   1.125+(defcustom hg-rev-completion-limit 100
   1.126+  "The maximum number of revisions that hg-read-rev will offer to complete.
   1.127+This affects memory usage and performance when prompting for revisions
   1.128+in a repository with a lot of history."
   1.129+  :type 'integer
   1.130+  :group 'mercurial)
   1.131+
   1.132+(defcustom hg-log-limit 50
   1.133+  "The maximum number of revisions that hg-log will display."
   1.134+  :type 'integer
   1.135+  :group 'mercurial)
   1.136+
   1.137+(defcustom hg-update-modeline t
   1.138+  "Whether to update the modeline with the status of a file after every save.
   1.139+Set this to nil on platforms with poor process management, such as Windows."
   1.140+  :type 'boolean
   1.141+  :group 'mercurial)
   1.142+
   1.143+(defcustom hg-incoming-repository "default"
   1.144+  "The repository from which changes are pulled from by default.
   1.145+This should be a symbolic repository name, since it is used for all
   1.146+repository-related commands."
   1.147+  :type 'string
   1.148+  :group 'mercurial)
   1.149+
   1.150+(defcustom hg-outgoing-repository ""
   1.151+  "The repository to which changes are pushed to by default.
   1.152+This should be a symbolic repository name, since it is used for all
   1.153+repository-related commands."
   1.154+  :type 'string
   1.155+  :group 'mercurial)
   1.156+
   1.157+
   1.158+;;; Other variables.
   1.159+
   1.160+(defvar hg-mode nil
   1.161+  "Is this file managed by Mercurial?")
   1.162+(make-variable-buffer-local 'hg-mode)
   1.163+(put 'hg-mode 'permanent-local t)
   1.164+
   1.165+(defvar hg-status nil)
   1.166+(make-variable-buffer-local 'hg-status)
   1.167+(put 'hg-status 'permanent-local t)
   1.168+
   1.169+(defvar hg-prev-buffer nil)
   1.170+(make-variable-buffer-local 'hg-prev-buffer)
   1.171+(put 'hg-prev-buffer 'permanent-local t)
   1.172+
   1.173+(defvar hg-root nil)
   1.174+(make-variable-buffer-local 'hg-root)
   1.175+(put 'hg-root 'permanent-local t)
   1.176+
   1.177+(defvar hg-view-mode nil)
   1.178+(make-variable-buffer-local 'hg-view-mode)
   1.179+(put 'hg-view-mode 'permanent-local t)
   1.180+
   1.181+(defvar hg-view-file-name nil)
   1.182+(make-variable-buffer-local 'hg-view-file-name)
   1.183+(put 'hg-view-file-name 'permanent-local t)
   1.184+
   1.185+(defvar hg-output-buffer-name "*Hg*"
   1.186+  "The name to use for Mercurial output buffers.")
   1.187+
   1.188+(defvar hg-file-history nil)
   1.189+(defvar hg-repo-history nil)
   1.190+(defvar hg-rev-history nil)
   1.191+(defvar hg-repo-completion-table nil)	; shut up warnings
   1.192+
   1.193+
   1.194+;;; Random constants.
   1.195+
   1.196+(defconst hg-commit-message-start
   1.197+  "--- Enter your commit message.  Type `C-c C-c' to commit. ---\n")
   1.198+
   1.199+(defconst hg-commit-message-end
   1.200+  "--- Files in bold will be committed.  Click to toggle selection. ---\n")
   1.201+
   1.202+(defconst hg-state-alist
   1.203+  '((?M . modified)
   1.204+    (?A . added)
   1.205+    (?R . removed)
   1.206+    (?! . deleted)
   1.207+    (?C . normal)
   1.208+    (?I . ignored)
   1.209+    (?? . nil)))
   1.210+
   1.211+;;; hg-mode keymap.
   1.212+
   1.213+(defvar hg-prefix-map
   1.214+  (let ((map (make-sparse-keymap)))
   1.215+    (hg-feature-cond (xemacs (set-keymap-name map 'hg-prefix-map))) ; XEmacs
   1.216+    (set-keymap-parent map vc-prefix-map)
   1.217+    (define-key map "=" 'hg-diff)
   1.218+    (define-key map "c" 'hg-undo)
   1.219+    (define-key map "g" 'hg-annotate)
   1.220+    (define-key map "i" 'hg-add)
   1.221+    (define-key map "l" 'hg-log)
   1.222+    (define-key map "n" 'hg-commit-start)
   1.223+    ;; (define-key map "r" 'hg-update)
   1.224+    (define-key map "u" 'hg-revert-buffer)
   1.225+    (define-key map "~" 'hg-version-other-window)
   1.226+    map)
   1.227+  "This keymap overrides some default vc-mode bindings.")
   1.228+
   1.229+(defvar hg-mode-map
   1.230+  (let ((map (make-sparse-keymap)))
   1.231+    (define-key map "\C-xv" hg-prefix-map)
   1.232+    map))
   1.233+
   1.234+(add-minor-mode 'hg-mode 'hg-mode hg-mode-map)
   1.235+
   1.236+
   1.237+;;; Global keymap.
   1.238+
   1.239+(defvar hg-global-map
   1.240+  (let ((map (make-sparse-keymap)))
   1.241+    (define-key map "," 'hg-incoming)
   1.242+    (define-key map "." 'hg-outgoing)
   1.243+    (define-key map "<" 'hg-pull)
   1.244+    (define-key map "=" 'hg-diff-repo)
   1.245+    (define-key map ">" 'hg-push)
   1.246+    (define-key map "?" 'hg-help-overview)
   1.247+    (define-key map "A" 'hg-addremove)
   1.248+    (define-key map "U" 'hg-revert)
   1.249+    (define-key map "a" 'hg-add)
   1.250+    (define-key map "c" 'hg-commit-start)
   1.251+    (define-key map "f" 'hg-forget)
   1.252+    (define-key map "h" 'hg-help-overview)
   1.253+    (define-key map "i" 'hg-init)
   1.254+    (define-key map "l" 'hg-log-repo)
   1.255+    (define-key map "r" 'hg-root)
   1.256+    (define-key map "s" 'hg-status)
   1.257+    (define-key map "u" 'hg-update)
   1.258+    map))
   1.259+
   1.260+(global-set-key hg-global-prefix hg-global-map)
   1.261+
   1.262+;;; View mode keymap.
   1.263+
   1.264+(defvar hg-view-mode-map
   1.265+  (let ((map (make-sparse-keymap)))
   1.266+    (hg-feature-cond (xemacs (set-keymap-name map 'hg-view-mode-map))) ; XEmacs
   1.267+    (define-key map (hg-feature-cond (xemacs [button2])
   1.268+				     (t [mouse-2]))
   1.269+      'hg-buffer-mouse-clicked)
   1.270+    map))
   1.271+
   1.272+(add-minor-mode 'hg-view-mode "" hg-view-mode-map)
   1.273+
   1.274+
   1.275+;;; Commit mode keymaps.
   1.276+
   1.277+(defvar hg-commit-mode-map
   1.278+  (let ((map (make-sparse-keymap)))
   1.279+    (define-key map "\C-c\C-c" 'hg-commit-finish)
   1.280+    (define-key map "\C-c\C-k" 'hg-commit-kill)
   1.281+    (define-key map "\C-xv=" 'hg-diff-repo)
   1.282+    map))
   1.283+
   1.284+(defvar hg-commit-mode-file-map
   1.285+  (let ((map (make-sparse-keymap)))
   1.286+    (define-key map (hg-feature-cond (xemacs [button2])
   1.287+				     (t [mouse-2]))
   1.288+      'hg-commit-mouse-clicked)
   1.289+    (define-key map " " 'hg-commit-toggle-file)
   1.290+    (define-key map "\r" 'hg-commit-toggle-file)
   1.291+    map))
   1.292+
   1.293+
   1.294+;;; Convenience functions.
   1.295+
   1.296+(defsubst hg-binary ()
   1.297+  (if hg-binary
   1.298+      hg-binary
   1.299+    (error "No `hg' executable found!")))
   1.300+
   1.301+(defsubst hg-replace-in-string (str regexp newtext &optional literal)
   1.302+  "Replace all matches in STR for REGEXP with NEWTEXT string.
   1.303+Return the new string.  Optional LITERAL non-nil means do a literal
   1.304+replacement.
   1.305+
   1.306+This function bridges yet another pointless impedance gap between
   1.307+XEmacs and GNU Emacs."
   1.308+  (hg-feature-cond
   1.309+   (xemacs (replace-in-string str regexp newtext literal))
   1.310+   (t (replace-regexp-in-string regexp newtext str nil literal))))
   1.311+
   1.312+(defsubst hg-strip (str)
   1.313+  "Strip leading and trailing blank lines from a string."
   1.314+  (hg-replace-in-string (hg-replace-in-string str "[\r\n][ \t\r\n]*\\'" "")
   1.315+			"\\`[ \t\r\n]*[\r\n]" ""))
   1.316+
   1.317+(defsubst hg-chomp (str)
   1.318+  "Strip trailing newlines from a string."
   1.319+  (hg-replace-in-string str "[\r\n]+\\'" ""))
   1.320+
   1.321+(defun hg-run-command (command &rest args)
   1.322+  "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT).
   1.323+The list ARGS contains a list of arguments to pass to the command."
   1.324+  (let* (exit-code
   1.325+	 (output
   1.326+	  (with-output-to-string
   1.327+	    (with-current-buffer
   1.328+		standard-output
   1.329+	      (setq exit-code
   1.330+		    (apply 'call-process command nil t nil args))))))
   1.331+    (cons exit-code output)))
   1.332+
   1.333+(defun hg-run (command &rest args)
   1.334+  "Run the Mercurial command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT)."
   1.335+  (apply 'hg-run-command (hg-binary) command args))
   1.336+
   1.337+(defun hg-run0 (command &rest args)
   1.338+  "Run the Mercurial command COMMAND, returning its output.
   1.339+If the command does not exit with a zero status code, raise an error."
   1.340+  (let ((res (apply 'hg-run-command (hg-binary) command args)))
   1.341+    (if (not (eq (car res) 0))
   1.342+	(error "Mercurial command failed %s - exit code %s"
   1.343+	       (cons command args)
   1.344+	       (car res))
   1.345+      (cdr res))))
   1.346+
   1.347+(defmacro hg-do-across-repo (path &rest body)
   1.348+  (let ((root-name (make-symbol "root-"))
   1.349+	(buf-name (make-symbol "buf-")))
   1.350+    `(let ((,root-name (hg-root ,path)))
   1.351+       (save-excursion
   1.352+	 (dolist (,buf-name (buffer-list))
   1.353+	   (set-buffer ,buf-name)
   1.354+	   (when (and hg-status (equal (hg-root buffer-file-name) ,root-name))
   1.355+	     ,@body))))))
   1.356+
   1.357+(put 'hg-do-across-repo 'lisp-indent-function 1)
   1.358+
   1.359+(defun hg-sync-buffers (path)
   1.360+  "Sync buffers visiting PATH with their on-disk copies.
   1.361+If PATH is not being visited, but is under the repository root, sync
   1.362+all buffers visiting files in the repository."
   1.363+  (let ((buf (find-buffer-visiting path)))
   1.364+    (if buf
   1.365+	(with-current-buffer buf
   1.366+	  (vc-buffer-sync))
   1.367+      (hg-do-across-repo path
   1.368+	(vc-buffer-sync)))))
   1.369+
   1.370+(defun hg-buffer-commands (pnt)
   1.371+  "Use the properties of a character to do something sensible."
   1.372+  (interactive "d")
   1.373+  (let ((rev (get-char-property pnt 'rev))
   1.374+	(file (get-char-property pnt 'file)))
   1.375+    (cond
   1.376+     (file
   1.377+      (find-file-other-window file))
   1.378+     (rev
   1.379+      (hg-diff hg-view-file-name rev rev))
   1.380+     ((message "I don't know how to do that yet")))))
   1.381+
   1.382+(defsubst hg-event-point (event)
   1.383+  "Return the character position of the mouse event EVENT."
   1.384+  (hg-feature-cond (xemacs (event-point event))
   1.385+		   (t (posn-point (event-start event)))))
   1.386+
   1.387+(defsubst hg-event-window (event)
   1.388+  "Return the window over which mouse event EVENT occurred."
   1.389+  (hg-feature-cond (xemacs (event-window event))
   1.390+		   (t (posn-window (event-start event)))))
   1.391+
   1.392+(defun hg-buffer-mouse-clicked (event)
   1.393+  "Translate the mouse clicks in a HG log buffer to character events.
   1.394+These are then handed off to `hg-buffer-commands'.
   1.395+
   1.396+Handle frickin' frackin' gratuitous event-related incompatibilities."
   1.397+  (interactive "e")
   1.398+  (select-window (hg-event-window event))
   1.399+  (hg-buffer-commands (hg-event-point event)))
   1.400+
   1.401+(defsubst hg-abbrev-file-name (file)
   1.402+  "Portable wrapper around abbreviate-file-name."
   1.403+  (hg-feature-cond (xemacs (abbreviate-file-name file t))
   1.404+		   (t (abbreviate-file-name file))))
   1.405+
   1.406+(defun hg-read-file-name (&optional prompt default)
   1.407+  "Read a file or directory name, or a pattern, to use with a command."
   1.408+  (save-excursion
   1.409+    (while hg-prev-buffer
   1.410+      (set-buffer hg-prev-buffer))
   1.411+    (let ((path (or default
   1.412+                    (buffer-file-name)
   1.413+                    (expand-file-name default-directory))))
   1.414+      (if (or (not path) current-prefix-arg)
   1.415+          (expand-file-name
   1.416+           (eval (list* 'read-file-name
   1.417+                        (format "File, directory or pattern%s: "
   1.418+                                (or prompt ""))
   1.419+                        (and path (file-name-directory path))
   1.420+                        nil nil
   1.421+                        (and path (file-name-nondirectory path))
   1.422+                        (hg-feature-cond
   1.423+			 (xemacs (cons (quote 'hg-file-history) nil))
   1.424+			 (t nil)))))
   1.425+        path))))
   1.426+
   1.427+(defun hg-read-number (&optional prompt default)
   1.428+  "Read a integer value."
   1.429+  (save-excursion
   1.430+    (if (or (not default) current-prefix-arg)
   1.431+        (string-to-number
   1.432+         (eval (list* 'read-string
   1.433+                      (or prompt "")
   1.434+                      (if default (cons (format "%d" default) nil) nil))))
   1.435+      default)))
   1.436+
   1.437+(defun hg-read-config ()
   1.438+  "Return an alist of (key . value) pairs of Mercurial config data.
   1.439+Each key is of the form (section . name)."
   1.440+  (let (items)
   1.441+    (dolist (line (split-string (hg-chomp (hg-run0 "debugconfig")) "\n") items)
   1.442+      (string-match "^\\([^=]*\\)=\\(.*\\)" line)
   1.443+      (let* ((left (substring line (match-beginning 1) (match-end 1)))
   1.444+	     (right (substring line (match-beginning 2) (match-end 2)))
   1.445+	     (key (split-string left "\\."))
   1.446+	     (value (hg-replace-in-string right "\\\\n" "\n" t)))
   1.447+	(setq items (cons (cons (cons (car key) (cadr key)) value) items))))))
   1.448+
   1.449+(defun hg-config-section (section config)
   1.450+  "Return an alist of (name . value) pairs for SECTION of CONFIG."
   1.451+  (let (items)
   1.452+    (dolist (item config items)
   1.453+      (when (equal (caar item) section)
   1.454+	(setq items (cons (cons (cdar item) (cdr item)) items))))))
   1.455+
   1.456+(defun hg-string-starts-with (sub str)
   1.457+  "Indicate whether string STR starts with the substring or character SUB."
   1.458+  (if (not (stringp sub))
   1.459+      (and (> (length str) 0) (equal (elt str 0) sub))
   1.460+    (let ((sub-len (length sub)))
   1.461+      (and (<= sub-len (length str))
   1.462+	   (string= sub (substring str 0 sub-len))))))
   1.463+
   1.464+(defun hg-complete-repo (string predicate all)
   1.465+  "Attempt to complete a repository name.
   1.466+We complete on either symbolic names from Mercurial's config or real
   1.467+directory names from the file system.  We do not penalize URLs."
   1.468+  (or (if all
   1.469+	  (all-completions string hg-repo-completion-table predicate)
   1.470+	(try-completion string hg-repo-completion-table predicate))
   1.471+      (let* ((str (expand-file-name string))
   1.472+	     (dir (file-name-directory str))
   1.473+	     (file (file-name-nondirectory str)))
   1.474+	(if all
   1.475+	    (let (completions)
   1.476+	      (dolist (name (delete "./" (file-name-all-completions file dir))
   1.477+			    completions)
   1.478+		(let ((path (concat dir name)))
   1.479+		  (when (file-directory-p path)
   1.480+		    (setq completions (cons name completions))))))
   1.481+	  (let ((comp (file-name-completion file dir)))
   1.482+	    (if comp
   1.483+		(hg-abbrev-file-name (concat dir comp))))))))
   1.484+
   1.485+(defun hg-read-repo-name (&optional prompt initial-contents default)
   1.486+  "Read the location of a repository."
   1.487+  (save-excursion
   1.488+    (while hg-prev-buffer
   1.489+      (set-buffer hg-prev-buffer))
   1.490+    (let (hg-repo-completion-table)
   1.491+      (if current-prefix-arg
   1.492+	  (progn
   1.493+	    (dolist (path (hg-config-section "paths" (hg-read-config)))
   1.494+	      (setq hg-repo-completion-table
   1.495+		    (cons (cons (car path) t) hg-repo-completion-table))
   1.496+	      (unless (hg-string-starts-with (hg-feature-cond
   1.497+					      (xemacs directory-sep-char)
   1.498+					      (t ?/))
   1.499+					     (cdr path))
   1.500+		(setq hg-repo-completion-table
   1.501+		      (cons (cons (cdr path) t) hg-repo-completion-table))))
   1.502+	    (completing-read (format "Repository%s: " (or prompt ""))
   1.503+			     'hg-complete-repo
   1.504+			     nil
   1.505+			     nil
   1.506+			     initial-contents
   1.507+			     'hg-repo-history
   1.508+			     default))
   1.509+	default))))
   1.510+
   1.511+(defun hg-read-rev (&optional prompt default)
   1.512+  "Read a revision or tag, offering completions."
   1.513+  (save-excursion
   1.514+    (while hg-prev-buffer
   1.515+      (set-buffer hg-prev-buffer))
   1.516+    (let ((rev (or default "tip")))
   1.517+      (if current-prefix-arg
   1.518+	  (let ((revs (split-string
   1.519+		       (hg-chomp
   1.520+			(hg-run0 "-q" "log" "-l"
   1.521+				 (format "%d" hg-rev-completion-limit)))
   1.522+		       "[\n:]")))
   1.523+	    (dolist (line (split-string (hg-chomp (hg-run0 "tags")) "\n"))
   1.524+	      (setq revs (cons (car (split-string line "\\s-")) revs)))
   1.525+	    (completing-read (format "Revision%s (%s): "
   1.526+				     (or prompt "")
   1.527+				     (or default "tip"))
   1.528+			     (mapcar (lambda (x) (cons x x)) revs)
   1.529+			     nil
   1.530+			     nil
   1.531+			     nil
   1.532+			     'hg-rev-history
   1.533+			     (or default "tip")))
   1.534+	rev))))
   1.535+
   1.536+(defun hg-parents-for-mode-line (root)
   1.537+  "Format the parents of the working directory for the mode line."
   1.538+  (let ((parents (split-string (hg-chomp
   1.539+				(hg-run0 "--cwd" root "parents" "--template"
   1.540+					 "{rev}\n")) "\n")))
   1.541+    (mapconcat 'identity parents "+")))
   1.542+
   1.543+(defun hg-buffers-visiting-repo (&optional path)
   1.544+  "Return a list of buffers visiting the repository containing PATH."
   1.545+  (let ((root-name (hg-root (or path (buffer-file-name))))
   1.546+	bufs)
   1.547+    (save-excursion
   1.548+      (dolist (buf (buffer-list) bufs)
   1.549+	(set-buffer buf)
   1.550+	(let ((name (buffer-file-name)))
   1.551+	  (when (and hg-status name (equal (hg-root name) root-name))
   1.552+	    (setq bufs (cons buf bufs))))))))
   1.553+
   1.554+(defun hg-update-mode-lines (path)
   1.555+  "Update the mode lines of all buffers visiting the same repository as PATH."
   1.556+  (let* ((root (hg-root path))
   1.557+	 (parents (hg-parents-for-mode-line root)))
   1.558+    (save-excursion
   1.559+      (dolist (info (hg-path-status
   1.560+		     root
   1.561+		     (mapcar
   1.562+		      (function
   1.563+		       (lambda (buf)
   1.564+			 (substring (buffer-file-name buf) (length root))))
   1.565+		      (hg-buffers-visiting-repo root))))
   1.566+	(let* ((name (car info))
   1.567+	       (status (cdr info))
   1.568+	       (buf (find-buffer-visiting (concat root name))))
   1.569+	  (when buf
   1.570+	    (set-buffer buf)
   1.571+	    (hg-mode-line-internal status parents)))))))
   1.572+
   1.573+
   1.574+;;; View mode bits.
   1.575+
   1.576+(defun hg-exit-view-mode (buf)
   1.577+  "Exit from hg-view-mode.
   1.578+We delete the current window if entering hg-view-mode split the
   1.579+current frame."
   1.580+  (when (and (eq buf (current-buffer))
   1.581+	     (> (length (window-list)) 1))
   1.582+    (delete-window))
   1.583+  (when (buffer-live-p buf)
   1.584+    (kill-buffer buf)))
   1.585+
   1.586+(defun hg-view-mode (prev-buffer &optional file-name)
   1.587+  (goto-char (point-min))
   1.588+  (set-buffer-modified-p nil)
   1.589+  (toggle-read-only t)
   1.590+  (hg-feature-cond (xemacs (view-minor-mode prev-buffer 'hg-exit-view-mode))
   1.591+		   (t (view-mode-enter nil 'hg-exit-view-mode)))
   1.592+  (setq hg-view-mode t)
   1.593+  (setq truncate-lines t)
   1.594+  (when file-name
   1.595+    (setq hg-view-file-name
   1.596+	  (hg-abbrev-file-name file-name))))
   1.597+
   1.598+(defun hg-file-status (file)
   1.599+  "Return status of FILE, or nil if FILE does not exist or is unmanaged."
   1.600+  (let* ((s (hg-run "status" file))
   1.601+	 (exit (car s))
   1.602+	 (output (cdr s)))
   1.603+    (if (= exit 0)
   1.604+	(let ((state (and (>= (length output) 2)
   1.605+			  (= (aref output 1) ? )
   1.606+			  (assq (aref output 0) hg-state-alist))))
   1.607+	  (if state
   1.608+	      (cdr state)
   1.609+	    'normal)))))
   1.610+
   1.611+(defun hg-path-status (root paths)
   1.612+  "Return status of PATHS in repo ROOT as an alist.
   1.613+Each entry is a pair (FILE-NAME . STATUS)."
   1.614+  (let ((s (apply 'hg-run "--cwd" root "status" "-marduc" paths))
   1.615+	result)
   1.616+    (dolist (entry (split-string (hg-chomp (cdr s)) "\n") (nreverse result))
   1.617+      (let (state name)
   1.618+	(cond ((= (aref entry 1) ? )
   1.619+	       (setq state (assq (aref entry 0) hg-state-alist)
   1.620+		     name (substring entry 2)))
   1.621+	      ((string-match "\\(.*\\): " entry)
   1.622+	       (setq name (match-string 1 entry))))
   1.623+	(setq result (cons (cons name state) result))))))
   1.624+
   1.625+(defmacro hg-view-output (args &rest body)
   1.626+  "Execute BODY in a clean buffer, then quickly display that buffer.
   1.627+If the buffer contains one line, its contents are displayed in the
   1.628+minibuffer.  Otherwise, the buffer is displayed in view-mode.
   1.629+ARGS is of the form (BUFFER-NAME &optional FILE), where BUFFER-NAME is
   1.630+the name of the buffer to create, and FILE is the name of the file
   1.631+being viewed."
   1.632+  (let ((prev-buf (make-symbol "prev-buf-"))
   1.633+	(v-b-name (car args))
   1.634+	(v-m-rest (cdr args)))
   1.635+    `(let ((view-buf-name ,v-b-name)
   1.636+	   (,prev-buf (current-buffer)))
   1.637+       (get-buffer-create view-buf-name)
   1.638+       (kill-buffer view-buf-name)
   1.639+       (get-buffer-create view-buf-name)
   1.640+       (set-buffer view-buf-name)
   1.641+       (save-excursion
   1.642+	 ,@body)
   1.643+       (case (count-lines (point-min) (point-max))
   1.644+	 ((0)
   1.645+	  (kill-buffer view-buf-name)
   1.646+	  (message "(No output)"))
   1.647+	 ((1)
   1.648+	  (let ((msg (hg-chomp (buffer-substring (point-min) (point-max)))))
   1.649+	    (kill-buffer view-buf-name)
   1.650+	    (message "%s" msg)))
   1.651+	 (t
   1.652+	  (pop-to-buffer view-buf-name)
   1.653+	  (setq hg-prev-buffer ,prev-buf)
   1.654+	  (hg-view-mode ,prev-buf ,@v-m-rest))))))
   1.655+
   1.656+(put 'hg-view-output 'lisp-indent-function 1)
   1.657+
   1.658+;;; Context save and restore across revert and other operations.
   1.659+
   1.660+(defun hg-position-context (pos)
   1.661+  "Return information to help find the given position again."
   1.662+  (let* ((end (min (point-max) (+ pos 98))))
   1.663+    (list pos
   1.664+	  (buffer-substring (max (point-min) (- pos 2)) end)
   1.665+	  (- end pos))))
   1.666+
   1.667+(defun hg-buffer-context ()
   1.668+  "Return information to help restore a user's editing context.
   1.669+This is useful across reverts and merges, where a context is likely
   1.670+to have moved a little, but not really changed."
   1.671+  (let ((point-context (hg-position-context (point)))
   1.672+	(mark-context (let ((mark (mark-marker)))
   1.673+			(and mark
   1.674+			     ;; make sure active mark
   1.675+			     (marker-buffer mark)
   1.676+			     (marker-position mark)
   1.677+			     (hg-position-context mark)))))
   1.678+    (list point-context mark-context)))
   1.679+
   1.680+(defun hg-find-context (ctx)
   1.681+  "Attempt to find a context in the given buffer.
   1.682+Always returns a valid, hopefully sane, position."
   1.683+  (let ((pos (nth 0 ctx))
   1.684+	(str (nth 1 ctx))
   1.685+	(fixup (nth 2 ctx)))
   1.686+    (save-excursion
   1.687+      (goto-char (max (point-min) (- pos 15000)))
   1.688+      (if (and (not (equal str ""))
   1.689+	       (search-forward str nil t))
   1.690+	  (- (point) fixup)
   1.691+	(max pos (point-min))))))
   1.692+
   1.693+(defun hg-restore-context (ctx)
   1.694+  "Attempt to restore the user's editing context."
   1.695+  (let ((point-context (nth 0 ctx))
   1.696+	(mark-context (nth 1 ctx)))
   1.697+    (goto-char (hg-find-context point-context))
   1.698+    (when mark-context
   1.699+      (set-mark (hg-find-context mark-context)))))
   1.700+
   1.701+
   1.702+;;; Hooks.
   1.703+
   1.704+(defun hg-mode-line-internal (status parents)
   1.705+  (setq hg-status status
   1.706+	hg-mode (and status (concat " Hg:"
   1.707+				    parents
   1.708+				    (cdr (assq status
   1.709+					       '((normal . "")
   1.710+						 (removed . "r")
   1.711+						 (added . "a")
   1.712+						 (deleted . "!")
   1.713+						 (modified . "m"))))))))
   1.714+
   1.715+(defun hg-mode-line (&optional force)
   1.716+  "Update the modeline with the current status of a file.
   1.717+An update occurs if optional argument FORCE is non-nil,
   1.718+hg-update-modeline is non-nil, or we have not yet checked the state of
   1.719+the file."
   1.720+  (let ((root (hg-root)))
   1.721+    (when (and root (or force hg-update-modeline (not hg-mode)))
   1.722+      (let ((status (hg-file-status buffer-file-name))
   1.723+	    (parents (hg-parents-for-mode-line root)))
   1.724+	(hg-mode-line-internal status parents)
   1.725+	status))))
   1.726+
   1.727+(defun hg-mode (&optional toggle)
   1.728+  "Minor mode for Mercurial distributed SCM integration.
   1.729+
   1.730+The Mercurial mode user interface is based on that of VC mode, so if
   1.731+you're already familiar with VC, the same keybindings and functions
   1.732+will generally work.
   1.733+
   1.734+Below is a list of many common SCM tasks.  In the list, `G/L\'
   1.735+indicates whether a key binding is global (G) to a repository or
   1.736+local (L) to a file.  Many commands take a prefix argument.
   1.737+
   1.738+SCM Task                              G/L  Key Binding  Command Name
   1.739+--------                              ---  -----------  ------------
   1.740+Help overview (what you are reading)  G    C-c h h      hg-help-overview
   1.741+
   1.742+Tell Mercurial to manage a file       G    C-c h a      hg-add
   1.743+Commit changes to current file only   L    C-x v n      hg-commit-start
   1.744+Undo changes to file since commit     L    C-x v u      hg-revert-buffer
   1.745+
   1.746+Diff file vs last checkin             L    C-x v =      hg-diff
   1.747+
   1.748+View file change history              L    C-x v l      hg-log
   1.749+View annotated file                   L    C-x v a      hg-annotate
   1.750+
   1.751+Diff repo vs last checkin             G    C-c h =      hg-diff-repo
   1.752+View status of files in repo          G    C-c h s      hg-status
   1.753+Commit all changes                    G    C-c h c      hg-commit-start
   1.754+
   1.755+Undo all changes since last commit    G    C-c h U      hg-revert
   1.756+View repo change history              G    C-c h l      hg-log-repo
   1.757+
   1.758+See changes that can be pulled        G    C-c h ,      hg-incoming
   1.759+Pull changes                          G    C-c h <      hg-pull
   1.760+Update working directory after pull   G    C-c h u      hg-update
   1.761+See changes that can be pushed        G    C-c h .      hg-outgoing
   1.762+Push changes                          G    C-c h >      hg-push"
   1.763+  (unless vc-make-backup-files
   1.764+    (set (make-local-variable 'backup-inhibited) t))
   1.765+  (run-hooks 'hg-mode-hook))
   1.766+
   1.767+(defun hg-find-file-hook ()
   1.768+  (ignore-errors
   1.769+    (when (hg-mode-line)
   1.770+      (hg-mode))))
   1.771+
   1.772+(add-hook 'find-file-hooks 'hg-find-file-hook)
   1.773+
   1.774+(defun hg-after-save-hook ()
   1.775+  (ignore-errors
   1.776+    (let ((old-status hg-status))
   1.777+      (hg-mode-line)
   1.778+      (if (and (not old-status) hg-status)
   1.779+	  (hg-mode)))))
   1.780+
   1.781+(add-hook 'after-save-hook 'hg-after-save-hook)
   1.782+
   1.783+
   1.784+;;; User interface functions.
   1.785+
   1.786+(defun hg-help-overview ()
   1.787+  "This is an overview of the Mercurial SCM mode for Emacs.
   1.788+
   1.789+You can find the source code, license (GPLv2+), and credits for this
   1.790+code by typing `M-x find-library mercurial RET'."
   1.791+  (interactive)
   1.792+  (hg-view-output ("Mercurial Help Overview")
   1.793+    (insert (documentation 'hg-help-overview))
   1.794+    (let ((pos (point)))
   1.795+      (insert (documentation 'hg-mode))
   1.796+      (goto-char pos)
   1.797+      (end-of-line 1)
   1.798+      (delete-region pos (point)))
   1.799+    (let ((hg-root-dir (hg-root)))
   1.800+      (if (not hg-root-dir)
   1.801+	  (error "error: %s: directory is not part of a Mercurial repository."
   1.802+		 default-directory)
   1.803+	(cd hg-root-dir)))))
   1.804+
   1.805+(defun hg-fix-paths ()
   1.806+  "Fix paths reported by some Mercurial commands."
   1.807+  (save-excursion
   1.808+    (goto-char (point-min))
   1.809+    (while (re-search-forward " \\.\\.." nil t)
   1.810+      (replace-match " " nil nil))))
   1.811+
   1.812+(defun hg-add (path)
   1.813+  "Add PATH to the Mercurial repository on the next commit.
   1.814+With a prefix argument, prompt for the path to add."
   1.815+  (interactive (list (hg-read-file-name " to add")))
   1.816+  (let ((buf (current-buffer))
   1.817+	(update (equal buffer-file-name path)))
   1.818+    (hg-view-output (hg-output-buffer-name)
   1.819+      (apply 'call-process (hg-binary) nil t nil (list "add" path))
   1.820+      (hg-fix-paths)
   1.821+      (goto-char (point-min))
   1.822+      (cd (hg-root path)))
   1.823+    (when update
   1.824+      (unless vc-make-backup-files
   1.825+	(set (make-local-variable 'backup-inhibited) t))
   1.826+      (with-current-buffer buf
   1.827+	(hg-mode-line)))))
   1.828+
   1.829+(defun hg-addremove ()
   1.830+  (interactive)
   1.831+  (error "not implemented"))
   1.832+
   1.833+(defun hg-annotate ()
   1.834+  (interactive)
   1.835+  (error "not implemented"))
   1.836+
   1.837+(defun hg-commit-toggle-file (pos)
   1.838+  "Toggle whether or not the file at POS will be committed."
   1.839+  (interactive "d")
   1.840+  (save-excursion
   1.841+    (goto-char pos)
   1.842+    (let (face
   1.843+	  (inhibit-read-only t)
   1.844+	  bol)
   1.845+      (beginning-of-line)
   1.846+      (setq bol (+ (point) 4))
   1.847+      (setq face (get-text-property bol 'face))
   1.848+      (end-of-line)
   1.849+      (if (eq face 'bold)
   1.850+	  (progn
   1.851+	    (remove-text-properties bol (point) '(face nil))
   1.852+	    (message "%s will not be committed"
   1.853+		     (buffer-substring bol (point))))
   1.854+	(add-text-properties bol (point) '(face bold))
   1.855+	(message "%s will be committed"
   1.856+		 (buffer-substring bol (point)))))))
   1.857+
   1.858+(defun hg-commit-mouse-clicked (event)
   1.859+  "Toggle whether or not the file at POS will be committed."
   1.860+  (interactive "@e")
   1.861+  (hg-commit-toggle-file (hg-event-point event)))
   1.862+
   1.863+(defun hg-commit-kill ()
   1.864+  "Kill the commit currently being prepared."
   1.865+  (interactive)
   1.866+  (when (or (not (buffer-modified-p)) (y-or-n-p "Really kill this commit? "))
   1.867+    (let ((buf hg-prev-buffer))
   1.868+      (kill-buffer nil)
   1.869+      (switch-to-buffer buf))))
   1.870+
   1.871+(defun hg-commit-finish ()
   1.872+  "Finish preparing a commit, and perform the actual commit.
   1.873+The hook hg-pre-commit-hook is run before anything else is done.  If
   1.874+the commit message is empty and hg-commit-allow-empty-message is nil,
   1.875+an error is raised.  If the list of files to commit is empty and
   1.876+hg-commit-allow-empty-file-list is nil, an error is raised."
   1.877+  (interactive)
   1.878+  (let ((root hg-root))
   1.879+    (save-excursion
   1.880+      (run-hooks 'hg-pre-commit-hook)
   1.881+      (goto-char (point-min))
   1.882+      (search-forward hg-commit-message-start)
   1.883+      (let (message files)
   1.884+	(let ((start (point)))
   1.885+	  (goto-char (point-max))
   1.886+	  (search-backward hg-commit-message-end)
   1.887+	  (setq message (hg-strip (buffer-substring start (point)))))
   1.888+	(when (and (= (length message) 0)
   1.889+		   (not hg-commit-allow-empty-message))
   1.890+	  (error "Cannot proceed - commit message is empty"))
   1.891+	(forward-line 1)
   1.892+	(beginning-of-line)
   1.893+	(while (< (point) (point-max))
   1.894+	  (let ((pos (+ (point) 4)))
   1.895+	    (end-of-line)
   1.896+	    (when (eq (get-text-property pos 'face) 'bold)
   1.897+	      (end-of-line)
   1.898+	      (setq files (cons (buffer-substring pos (point)) files))))
   1.899+	  (forward-line 1))
   1.900+	(when (and (= (length files) 0)
   1.901+		   (not hg-commit-allow-empty-file-list))
   1.902+	  (error "Cannot proceed - no files to commit"))
   1.903+	(setq message (concat message "\n"))
   1.904+	(apply 'hg-run0 "--cwd" hg-root "commit" "-m" message files))
   1.905+      (let ((buf hg-prev-buffer))
   1.906+	(kill-buffer nil)
   1.907+	(switch-to-buffer buf))
   1.908+      (hg-update-mode-lines root))))
   1.909+
   1.910+(defun hg-commit-mode ()
   1.911+  "Mode for describing a commit of changes to a Mercurial repository.
   1.912+This involves two actions: describing the changes with a commit
   1.913+message, and choosing the files to commit.
   1.914+
   1.915+To describe the commit, simply type some text in the designated area.
   1.916+
   1.917+By default, all modified, added and removed files are selected for
   1.918+committing.  Files that will be committed are displayed in bold face\;
   1.919+those that will not are displayed in normal face.
   1.920+
   1.921+To toggle whether a file will be committed, move the cursor over a
   1.922+particular file and hit space or return.  Alternatively, middle click
   1.923+on the file.
   1.924+
   1.925+Key bindings
   1.926+------------
   1.927+\\[hg-commit-finish]		proceed with commit
   1.928+\\[hg-commit-kill]		kill commit
   1.929+
   1.930+\\[hg-diff-repo]		view diff of pending changes"
   1.931+  (interactive)
   1.932+  (use-local-map hg-commit-mode-map)
   1.933+  (set-syntax-table text-mode-syntax-table)
   1.934+  (setq local-abbrev-table text-mode-abbrev-table
   1.935+	major-mode 'hg-commit-mode
   1.936+	mode-name "Hg-Commit")
   1.937+  (set-buffer-modified-p nil)
   1.938+  (setq buffer-undo-list nil)
   1.939+  (run-hooks 'text-mode-hook 'hg-commit-mode-hook))
   1.940+
   1.941+(defun hg-commit-start ()
   1.942+  "Prepare a commit of changes to the repository containing the current file."
   1.943+  (interactive)
   1.944+  (while hg-prev-buffer
   1.945+    (set-buffer hg-prev-buffer))
   1.946+  (let ((root (hg-root))
   1.947+	(prev-buffer (current-buffer))
   1.948+	modified-files)
   1.949+    (unless root
   1.950+      (error "Cannot commit outside a repository!"))
   1.951+    (hg-sync-buffers root)
   1.952+    (setq modified-files (hg-chomp (hg-run0 "--cwd" root "status" "-arm")))
   1.953+    (when (and (= (length modified-files) 0)
   1.954+	       (not hg-commit-allow-empty-file-list))
   1.955+      (error "No pending changes to commit"))
   1.956+    (let* ((buf-name (format "*Mercurial: Commit %s*" root)))
   1.957+      (pop-to-buffer (get-buffer-create buf-name))
   1.958+      (when (= (point-min) (point-max))
   1.959+	(set (make-local-variable 'hg-root) root)
   1.960+	(setq hg-prev-buffer prev-buffer)
   1.961+	(insert "\n")
   1.962+	(let ((bol (point)))
   1.963+	  (insert hg-commit-message-end)
   1.964+	  (add-text-properties bol (point) '(face bold-italic)))
   1.965+	(let ((file-area (point)))
   1.966+	  (insert modified-files)
   1.967+	  (goto-char file-area)
   1.968+	  (while (< (point) (point-max))
   1.969+	    (let ((bol (point)))
   1.970+	      (forward-char 1)
   1.971+	      (insert "  ")
   1.972+	      (end-of-line)
   1.973+	      (add-text-properties (+ bol 4) (point)
   1.974+				   '(face bold mouse-face highlight)))
   1.975+	    (forward-line 1))
   1.976+	  (goto-char file-area)
   1.977+	  (add-text-properties (point) (point-max)
   1.978+			       `(keymap ,hg-commit-mode-file-map))
   1.979+	  (goto-char (point-min))
   1.980+	  (insert hg-commit-message-start)
   1.981+	  (add-text-properties (point-min) (point) '(face bold-italic))
   1.982+	  (insert "\n\n")
   1.983+	  (forward-line -1)
   1.984+	  (save-excursion
   1.985+	    (goto-char (point-max))
   1.986+	    (search-backward hg-commit-message-end)
   1.987+	    (add-text-properties (match-beginning 0) (point-max)
   1.988+				 '(read-only t))
   1.989+	    (goto-char (point-min))
   1.990+	    (search-forward hg-commit-message-start)
   1.991+	    (add-text-properties (match-beginning 0) (match-end 0)
   1.992+				 '(read-only t)))
   1.993+	  (hg-commit-mode)
   1.994+          (cd root))))))
   1.995+
   1.996+(defun hg-diff (path &optional rev1 rev2)
   1.997+  "Show the differences between REV1 and REV2 of PATH.
   1.998+When called interactively, the default behaviour is to treat REV1 as
   1.999+the \"parent\" revision, REV2 as the current edited version of the file, and
  1.1000+PATH as the file edited in the current buffer.
  1.1001+With a prefix argument, prompt for all of these."
  1.1002+  (interactive (list (hg-read-file-name " to diff")
  1.1003+                     (let ((rev1 (hg-read-rev " to start with" 'parent)))
  1.1004+		       (and (not (eq rev1 'parent)) rev1))
  1.1005+		     (let ((rev2 (hg-read-rev " to end with" 'working-dir)))
  1.1006+		       (and (not (eq rev2 'working-dir)) rev2))))
  1.1007+  (hg-sync-buffers path)
  1.1008+  (let ((a-path (hg-abbrev-file-name path))
  1.1009+        ;; none revision is specified explicitly
  1.1010+        (none (and (not rev1) (not rev2)))
  1.1011+        ;; only one revision is specified explicitly
  1.1012+        (one (or (and (or (equal rev1 rev2) (not rev2)) rev1)
  1.1013+                 (and (not rev1) rev2)))
  1.1014+	diff)
  1.1015+    (hg-view-output ((cond
  1.1016+		      (none
  1.1017+		       (format "Mercurial: Diff against parent of %s" a-path))
  1.1018+		      (one
  1.1019+		       (format "Mercurial: Diff of rev %s of %s" one a-path))
  1.1020+		      (t
  1.1021+		       (format "Mercurial: Diff from rev %s to %s of %s"
  1.1022+			       rev1 rev2 a-path))))
  1.1023+      (cond
  1.1024+       (none
  1.1025+        (call-process (hg-binary) nil t nil "diff" path))
  1.1026+       (one
  1.1027+        (call-process (hg-binary) nil t nil "diff" "-r" one path))
  1.1028+       (t
  1.1029+        (call-process (hg-binary) nil t nil "diff" "-r" rev1 "-r" rev2 path)))
  1.1030+      (diff-mode)
  1.1031+      (setq diff (not (= (point-min) (point-max))))
  1.1032+      (font-lock-fontify-buffer)
  1.1033+      (cd (hg-root path)))
  1.1034+    diff))
  1.1035+
  1.1036+(defun hg-diff-repo (path &optional rev1 rev2)
  1.1037+  "Show the differences between REV1 and REV2 of repository containing PATH.
  1.1038+When called interactively, the default behaviour is to treat REV1 as
  1.1039+the \"parent\" revision, REV2 as the current edited version of the file, and
  1.1040+PATH as the `hg-root' of the current buffer.
  1.1041+With a prefix argument, prompt for all of these."
  1.1042+  (interactive (list (hg-read-file-name " to diff")
  1.1043+                     (let ((rev1 (hg-read-rev " to start with" 'parent)))
  1.1044+		       (and (not (eq rev1 'parent)) rev1))
  1.1045+		     (let ((rev2 (hg-read-rev " to end with" 'working-dir)))
  1.1046+		       (and (not (eq rev2 'working-dir)) rev2))))
  1.1047+  (hg-diff (hg-root path) rev1 rev2))
  1.1048+
  1.1049+(defun hg-forget (path)
  1.1050+  "Lose track of PATH, which has been added, but not yet committed.
  1.1051+This will prevent the file from being incorporated into the Mercurial
  1.1052+repository on the next commit.
  1.1053+With a prefix argument, prompt for the path to forget."
  1.1054+  (interactive (list (hg-read-file-name " to forget")))
  1.1055+  (let ((buf (current-buffer))
  1.1056+	(update (equal buffer-file-name path)))
  1.1057+    (hg-view-output (hg-output-buffer-name)
  1.1058+      (apply 'call-process (hg-binary) nil t nil (list "forget" path))
  1.1059+      ;; "hg forget" shows pathes relative NOT TO ROOT BUT TO REPOSITORY
  1.1060+      (hg-fix-paths)
  1.1061+      (goto-char (point-min))
  1.1062+      (cd (hg-root path)))
  1.1063+    (when update
  1.1064+      (with-current-buffer buf
  1.1065+        (when (local-variable-p 'backup-inhibited)
  1.1066+          (kill-local-variable 'backup-inhibited))
  1.1067+	(hg-mode-line)))))
  1.1068+
  1.1069+(defun hg-incoming (&optional repo)
  1.1070+  "Display changesets present in REPO that are not present locally."
  1.1071+  (interactive (list (hg-read-repo-name " where changes would come from")))
  1.1072+  (hg-view-output ((format "Mercurial: Incoming from %s to %s"
  1.1073+			   (hg-abbrev-file-name (hg-root))
  1.1074+			   (hg-abbrev-file-name
  1.1075+			    (or repo hg-incoming-repository))))
  1.1076+    (call-process (hg-binary) nil t nil "incoming"
  1.1077+		  (or repo hg-incoming-repository))
  1.1078+    (hg-log-mode)
  1.1079+    (cd (hg-root))))
  1.1080+
  1.1081+(defun hg-init ()
  1.1082+  (interactive)
  1.1083+  (error "not implemented"))
  1.1084+
  1.1085+(defun hg-log-mode ()
  1.1086+  "Mode for viewing a Mercurial change log."
  1.1087+  (goto-char (point-min))
  1.1088+  (when (looking-at "^searching for changes.*$")
  1.1089+    (delete-region (match-beginning 0) (match-end 0)))
  1.1090+  (run-hooks 'hg-log-mode-hook))
  1.1091+
  1.1092+(defun hg-log (path &optional rev1 rev2 log-limit)
  1.1093+  "Display the revision history of PATH.
  1.1094+History is displayed between REV1 and REV2.
  1.1095+Number of displayed changesets is limited to LOG-LIMIT.
  1.1096+REV1 defaults to the tip, while REV2 defaults to 0.
  1.1097+LOG-LIMIT defaults to `hg-log-limit'.
  1.1098+With a prefix argument, prompt for each parameter."
  1.1099+  (interactive (list (hg-read-file-name " to log")
  1.1100+                     (hg-read-rev " to start with"
  1.1101+                                  "tip")
  1.1102+                     (hg-read-rev " to end with"
  1.1103+				  "0")
  1.1104+                     (hg-read-number "Output limited to: "
  1.1105+                                     hg-log-limit)))
  1.1106+  (let ((a-path (hg-abbrev-file-name path))
  1.1107+        (r1 (or rev1 "tip"))
  1.1108+        (r2 (or rev2 "0"))
  1.1109+        (limit (format "%d" (or log-limit hg-log-limit))))
  1.1110+    (hg-view-output ((if (equal r1 r2)
  1.1111+                         (format "Mercurial: Log of rev %s of %s" rev1 a-path)
  1.1112+                       (format
  1.1113+                        "Mercurial: at most %s log(s) from rev %s to %s of %s"
  1.1114+                        limit r1 r2 a-path)))
  1.1115+      (eval (list* 'call-process (hg-binary) nil t nil
  1.1116+                   "log"
  1.1117+                   "-r" (format "%s:%s" r1 r2)
  1.1118+                   "-l" limit
  1.1119+                   (if (> (length path) (length (hg-root path)))
  1.1120+                       (cons path nil)
  1.1121+                     nil)))
  1.1122+      (hg-log-mode)
  1.1123+      (cd (hg-root path)))))
  1.1124+
  1.1125+(defun hg-log-repo (path &optional rev1 rev2 log-limit)
  1.1126+  "Display the revision history of the repository containing PATH.
  1.1127+History is displayed between REV1 and REV2.
  1.1128+Number of displayed changesets is limited to LOG-LIMIT,
  1.1129+REV1 defaults to the tip, while REV2 defaults to 0.
  1.1130+LOG-LIMIT defaults to `hg-log-limit'.
  1.1131+With a prefix argument, prompt for each parameter."
  1.1132+  (interactive (list (hg-read-file-name " to log")
  1.1133+                     (hg-read-rev " to start with"
  1.1134+                                  "tip")
  1.1135+                     (hg-read-rev " to end with"
  1.1136+				  "0")
  1.1137+                     (hg-read-number "Output limited to: "
  1.1138+                                     hg-log-limit)))
  1.1139+  (hg-log (hg-root path) rev1 rev2 log-limit))
  1.1140+
  1.1141+(defun hg-outgoing (&optional repo)
  1.1142+  "Display changesets present locally that are not present in REPO."
  1.1143+  (interactive (list (hg-read-repo-name " where changes would go to" nil
  1.1144+					hg-outgoing-repository)))
  1.1145+  (hg-view-output ((format "Mercurial: Outgoing from %s to %s"
  1.1146+			   (hg-abbrev-file-name (hg-root))
  1.1147+			   (hg-abbrev-file-name
  1.1148+			    (or repo hg-outgoing-repository))))
  1.1149+    (call-process (hg-binary) nil t nil "outgoing"
  1.1150+		  (or repo hg-outgoing-repository))
  1.1151+    (hg-log-mode)
  1.1152+    (cd (hg-root))))
  1.1153+
  1.1154+(defun hg-pull (&optional repo)
  1.1155+  "Pull changes from repository REPO.
  1.1156+This does not update the working directory."
  1.1157+  (interactive (list (hg-read-repo-name " to pull from")))
  1.1158+  (hg-view-output ((format "Mercurial: Pull to %s from %s"
  1.1159+			   (hg-abbrev-file-name (hg-root))
  1.1160+			   (hg-abbrev-file-name
  1.1161+			    (or repo hg-incoming-repository))))
  1.1162+    (call-process (hg-binary) nil t nil "pull"
  1.1163+		  (or repo hg-incoming-repository))
  1.1164+    (cd (hg-root))))
  1.1165+
  1.1166+(defun hg-push (&optional repo)
  1.1167+  "Push changes to repository REPO."
  1.1168+  (interactive (list (hg-read-repo-name " to push to")))
  1.1169+  (hg-view-output ((format "Mercurial: Push from %s to %s"
  1.1170+			   (hg-abbrev-file-name (hg-root))
  1.1171+			   (hg-abbrev-file-name
  1.1172+			    (or repo hg-outgoing-repository))))
  1.1173+    (call-process (hg-binary) nil t nil "push"
  1.1174+		  (or repo hg-outgoing-repository))
  1.1175+    (cd (hg-root))))
  1.1176+
  1.1177+(defun hg-revert-buffer-internal ()
  1.1178+  (let ((ctx (hg-buffer-context)))
  1.1179+    (message "Reverting %s..." buffer-file-name)
  1.1180+    (hg-run0 "revert" buffer-file-name)
  1.1181+    (revert-buffer t t t)
  1.1182+    (hg-restore-context ctx)
  1.1183+    (hg-mode-line)
  1.1184+    (message "Reverting %s...done" buffer-file-name)))
  1.1185+
  1.1186+(defun hg-revert-buffer ()
  1.1187+  "Revert current buffer's file back to the latest committed version.
  1.1188+If the file has not changed, nothing happens.  Otherwise, this
  1.1189+displays a diff and asks for confirmation before reverting."
  1.1190+  (interactive)
  1.1191+  (let ((vc-suppress-confirm nil)
  1.1192+	(obuf (current-buffer))
  1.1193+	diff)
  1.1194+    (vc-buffer-sync)
  1.1195+    (unwind-protect
  1.1196+	(setq diff (hg-diff buffer-file-name))
  1.1197+      (when diff
  1.1198+	(unless (yes-or-no-p "Discard changes? ")
  1.1199+	  (error "Revert cancelled")))
  1.1200+      (when diff
  1.1201+	(let ((buf (current-buffer)))
  1.1202+	  (delete-window (selected-window))
  1.1203+	  (kill-buffer buf))))
  1.1204+    (set-buffer obuf)
  1.1205+    (when diff
  1.1206+      (hg-revert-buffer-internal))))
  1.1207+
  1.1208+(defun hg-root (&optional path)
  1.1209+  "Return the root of the repository that contains the given path.
  1.1210+If the path is outside a repository, return nil.
  1.1211+When called interactively, the root is printed.  A prefix argument
  1.1212+prompts for a path to check."
  1.1213+  (interactive (list (hg-read-file-name)))
  1.1214+  (if (or path (not hg-root))
  1.1215+      (let ((root (do ((prev nil dir)
  1.1216+		       (dir (file-name-directory
  1.1217+                             (or
  1.1218+                              path
  1.1219+                              buffer-file-name
  1.1220+                              (expand-file-name default-directory)))
  1.1221+			    (file-name-directory (directory-file-name dir))))
  1.1222+		      ((equal prev dir))
  1.1223+		    (when (file-directory-p (concat dir ".hg"))
  1.1224+		      (return dir)))))
  1.1225+	(when (interactive-p)
  1.1226+	  (if root
  1.1227+	      (message "The root of this repository is `%s'." root)
  1.1228+	    (message "The path `%s' is not in a Mercurial repository."
  1.1229+		     (hg-abbrev-file-name path))))
  1.1230+	root)
  1.1231+    hg-root))
  1.1232+
  1.1233+(defun hg-cwd (&optional path)
  1.1234+  "Return the current directory of PATH within the repository."
  1.1235+  (do ((stack nil (cons (file-name-nondirectory
  1.1236+			 (directory-file-name dir))
  1.1237+			stack))
  1.1238+       (prev nil dir)
  1.1239+       (dir (file-name-directory (or path buffer-file-name
  1.1240+				     (expand-file-name default-directory)))
  1.1241+	    (file-name-directory (directory-file-name dir))))
  1.1242+      ((equal prev dir))
  1.1243+    (when (file-directory-p (concat dir ".hg"))
  1.1244+      (let ((cwd (mapconcat 'identity stack "/")))
  1.1245+	(unless (equal cwd "")
  1.1246+	  (return (file-name-as-directory cwd)))))))
  1.1247+
  1.1248+(defun hg-status (path)
  1.1249+  "Print revision control status of a file or directory.
  1.1250+With prefix argument, prompt for the path to give status for.
  1.1251+Names are displayed relative to the repository root."
  1.1252+  (interactive (list (hg-read-file-name " for status" (hg-root))))
  1.1253+  (let ((root (hg-root)))
  1.1254+    (hg-view-output ((format "Mercurial: Status of %s in %s"
  1.1255+			     (let ((name (substring (expand-file-name path)
  1.1256+						    (length root))))
  1.1257+			       (if (> (length name) 0)
  1.1258+				   name
  1.1259+				 "*"))
  1.1260+			     (hg-abbrev-file-name root)))
  1.1261+      (apply 'call-process (hg-binary) nil t nil
  1.1262+	     (list "--cwd" root "status" path))
  1.1263+      (cd (hg-root path)))))
  1.1264+
  1.1265+(defun hg-undo ()
  1.1266+  (interactive)
  1.1267+  (error "not implemented"))
  1.1268+
  1.1269+(defun hg-update ()
  1.1270+  (interactive)
  1.1271+  (error "not implemented"))
  1.1272+
  1.1273+(defun hg-version-other-window (rev)
  1.1274+  "Visit version REV of the current file in another window.
  1.1275+If the current file is named `F', the version is named `F.~REV~'.
  1.1276+If `F.~REV~' already exists, use it instead of checking it out again."
  1.1277+  (interactive "sVersion to visit (default is workfile version): ")
  1.1278+  (let* ((file buffer-file-name)
  1.1279+       	 (version (if (string-equal rev "")
  1.1280+		       "tip"
  1.1281+		        rev))
  1.1282+ 	 (automatic-backup (vc-version-backup-file-name file version))
  1.1283+          (manual-backup (vc-version-backup-file-name file version 'manual)))
  1.1284+     (unless (file-exists-p manual-backup)
  1.1285+       (if (file-exists-p automatic-backup)
  1.1286+           (rename-file automatic-backup manual-backup nil)
  1.1287+         (hg-run0 "-q" "cat" "-r" version "-o" manual-backup file)))
  1.1288+     (find-file-other-window manual-backup)))
  1.1289+
  1.1290+
  1.1291+(provide 'mercurial)
  1.1292+
  1.1293+
  1.1294+;;; Local Variables:
  1.1295+;;; prompt-to-byte-compile: nil
  1.1296+;;; end:
     2.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2+++ b/.emacs.d/lib/mq.el	Wed Jun 05 23:31:48 2024 +0000
     2.3@@ -0,0 +1,417 @@
     2.4+;;; mq.el --- Emacs support for Mercurial Queues
     2.5+
     2.6+;; Copyright (C) 2006 Bryan O'Sullivan
     2.7+
     2.8+;; Author: Bryan O'Sullivan <bos@serpentine.com>
     2.9+
    2.10+;; mq.el is free software; you can redistribute it and/or modify it
    2.11+;; under the terms of the GNU General Public License version 2 or any
    2.12+;; later version.
    2.13+
    2.14+;; mq.el is distributed in the hope that it will be useful, but
    2.15+;; WITHOUT ANY WARRANTY; without even the implied warranty of
    2.16+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    2.17+;; General Public License for more details.
    2.18+
    2.19+;; You should have received a copy of the GNU General Public License
    2.20+;; along with mq.el, GNU Emacs, or XEmacs; see the file COPYING (`C-h
    2.21+;; C-l').  If not, see <http://www.gnu.org/licenses/>.
    2.22+
    2.23+(eval-when-compile (require 'cl))
    2.24+(require 'mercurial)
    2.25+
    2.26+
    2.27+(defcustom mq-mode-hook nil
    2.28+  "Hook run when a buffer enters mq-mode."
    2.29+  :type 'sexp
    2.30+  :group 'mercurial)
    2.31+
    2.32+(defcustom mq-global-prefix "\C-cq"
    2.33+  "The global prefix for Mercurial Queues keymap bindings."
    2.34+  :type 'sexp
    2.35+  :group 'mercurial)
    2.36+
    2.37+(defcustom mq-edit-mode-hook nil
    2.38+  "Hook run after a buffer is populated to edit a patch description."
    2.39+  :type 'sexp
    2.40+  :group 'mercurial)
    2.41+
    2.42+(defcustom mq-edit-finish-hook nil
    2.43+  "Hook run before a patch description is finished up with."
    2.44+  :type 'sexp
    2.45+  :group 'mercurial)
    2.46+
    2.47+(defcustom mq-signoff-address nil
    2.48+  "Address with which to sign off on a patch."
    2.49+  :type 'string
    2.50+  :group 'mercurial)
    2.51+
    2.52+
    2.53+;;; Internal variables.
    2.54+
    2.55+(defvar mq-mode nil
    2.56+  "Is this file managed by MQ?")
    2.57+(make-variable-buffer-local 'mq-mode)
    2.58+(put 'mq-mode 'permanent-local t)
    2.59+
    2.60+(defvar mq-patch-history nil)
    2.61+
    2.62+(defvar mq-top-patch '(nil))
    2.63+
    2.64+(defvar mq-prev-buffer nil)
    2.65+(make-variable-buffer-local 'mq-prev-buffer)
    2.66+(put 'mq-prev-buffer 'permanent-local t)
    2.67+
    2.68+(defvar mq-top nil)
    2.69+(make-variable-buffer-local 'mq-top)
    2.70+(put 'mq-top 'permanent-local t)
    2.71+
    2.72+;;; Global keymap.
    2.73+
    2.74+(defvar mq-global-map
    2.75+  (let ((map (make-sparse-keymap)))
    2.76+    (define-key map "." 'mq-push)
    2.77+    (define-key map ">" 'mq-push-all)
    2.78+    (define-key map "," 'mq-pop)
    2.79+    (define-key map "<" 'mq-pop-all)
    2.80+    (define-key map "=" 'mq-diff)
    2.81+    (define-key map "r" 'mq-refresh)
    2.82+    (define-key map "e" 'mq-refresh-edit)
    2.83+    (define-key map "i" 'mq-new)
    2.84+    (define-key map "n" 'mq-next)
    2.85+    (define-key map "o" 'mq-signoff)
    2.86+    (define-key map "p" 'mq-previous)
    2.87+    (define-key map "s" 'mq-edit-series)
    2.88+    (define-key map "t" 'mq-top)
    2.89+    map))
    2.90+
    2.91+(global-set-key mq-global-prefix mq-global-map)
    2.92+
    2.93+(add-minor-mode 'mq-mode 'mq-mode)
    2.94+
    2.95+
    2.96+;;; Refresh edit mode keymap.
    2.97+
    2.98+(defvar mq-edit-mode-map
    2.99+  (let ((map (make-sparse-keymap)))
   2.100+    (define-key map "\C-c\C-c" 'mq-edit-finish)
   2.101+    (define-key map "\C-c\C-k" 'mq-edit-kill)
   2.102+    (define-key map "\C-c\C-s" 'mq-signoff)
   2.103+    map))
   2.104+
   2.105+
   2.106+;;; Helper functions.
   2.107+
   2.108+(defun mq-read-patch-name (&optional source prompt force)
   2.109+  "Read a patch name to use with a command.
   2.110+May return nil, meaning \"use the default\"."
   2.111+  (let ((patches (split-string
   2.112+		  (hg-chomp (hg-run0 (or source "qseries"))) "\n")))
   2.113+    (when force
   2.114+      (completing-read (format "Patch%s: " (or prompt ""))
   2.115+		       (mapcar (lambda (x) (cons x x)) patches)
   2.116+		       nil
   2.117+		       nil
   2.118+		       nil
   2.119+		       'mq-patch-history))))
   2.120+
   2.121+(defun mq-refresh-buffers (root)
   2.122+  (save-excursion
   2.123+    (dolist (buf (hg-buffers-visiting-repo root))
   2.124+      (when (not (verify-visited-file-modtime buf))
   2.125+	(set-buffer buf)
   2.126+	(let ((ctx (hg-buffer-context)))
   2.127+	  (message "Refreshing %s..." (buffer-name))
   2.128+	  (revert-buffer t t t)
   2.129+	  (hg-restore-context ctx)
   2.130+	  (message "Refreshing %s...done" (buffer-name))))))
   2.131+  (hg-update-mode-lines root)
   2.132+  (mq-update-mode-lines root))
   2.133+
   2.134+(defun mq-last-line ()
   2.135+  (goto-char (point-max))
   2.136+  (beginning-of-line)
   2.137+  (when (looking-at "^$")
   2.138+    (forward-line -1))
   2.139+  (let ((bol (point)))
   2.140+    (end-of-line)
   2.141+    (let ((line (buffer-substring bol (point))))
   2.142+      (when (> (length line) 0)
   2.143+	line))))
   2.144+
   2.145+(defun mq-push (&optional patch)
   2.146+  "Push patches until PATCH is reached.
   2.147+If PATCH is nil, push at most one patch."
   2.148+  (interactive (list (mq-read-patch-name "qunapplied" " to push"
   2.149+					 current-prefix-arg)))
   2.150+  (let ((root (hg-root))
   2.151+	(prev-buf (current-buffer))
   2.152+	last-line ok)
   2.153+    (unless root
   2.154+      (error "Cannot push outside a repository!"))
   2.155+    (hg-sync-buffers root)
   2.156+    (let ((buf-name (format "MQ: Push %s" (or patch "next patch"))))
   2.157+      (kill-buffer (get-buffer-create buf-name))
   2.158+      (split-window-vertically)
   2.159+      (other-window 1)
   2.160+      (switch-to-buffer (get-buffer-create buf-name))
   2.161+      (cd root)
   2.162+      (message "Pushing...")
   2.163+      (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpush"
   2.164+			   (if patch (list patch))))
   2.165+	    last-line (mq-last-line))
   2.166+      (let ((lines (count-lines (point-min) (point-max))))
   2.167+	(if (or (<= lines 1)
   2.168+		(and (equal lines 2) (string-match "Now at:" last-line)))
   2.169+	    (progn
   2.170+	      (kill-buffer (current-buffer))
   2.171+	      (delete-window))
   2.172+	  (hg-view-mode prev-buf))))
   2.173+    (mq-refresh-buffers root)
   2.174+    (sit-for 0)
   2.175+    (when last-line
   2.176+      (if ok
   2.177+	  (message "Pushing... %s" last-line)
   2.178+	(error "Pushing... %s" last-line)))))
   2.179+
   2.180+(defun mq-push-all ()
   2.181+  "Push patches until all are applied."
   2.182+  (interactive)
   2.183+  (mq-push "-a"))
   2.184+
   2.185+(defun mq-pop (&optional patch)
   2.186+  "Pop patches until PATCH is reached.
   2.187+If PATCH is nil, pop at most one patch."
   2.188+  (interactive (list (mq-read-patch-name "qapplied" " to pop to"
   2.189+					 current-prefix-arg)))
   2.190+  (let ((root (hg-root))
   2.191+	last-line ok)
   2.192+    (unless root
   2.193+      (error "Cannot pop outside a repository!"))
   2.194+    (hg-sync-buffers root)
   2.195+    (set-buffer (generate-new-buffer "qpop"))
   2.196+    (cd root)
   2.197+    (message "Popping...")
   2.198+    (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpop"
   2.199+			 (if patch (list patch))))
   2.200+	  last-line (mq-last-line))
   2.201+    (kill-buffer (current-buffer))
   2.202+    (mq-refresh-buffers root)
   2.203+    (sit-for 0)
   2.204+    (when last-line
   2.205+      (if ok
   2.206+	  (message "Popping... %s" last-line)
   2.207+	(error "Popping... %s" last-line)))))
   2.208+
   2.209+(defun mq-pop-all ()
   2.210+  "Push patches until none are applied."
   2.211+  (interactive)
   2.212+  (mq-pop "-a"))
   2.213+
   2.214+(defun mq-refresh-internal (root &rest args)
   2.215+  (hg-sync-buffers root)
   2.216+  (let ((patch (mq-patch-info "qtop")))
   2.217+    (message "Refreshing %s..." patch)
   2.218+    (let ((ret (apply 'hg-run "qrefresh" args)))
   2.219+      (if (equal (car ret) 0)
   2.220+	  (message "Refreshing %s... done." patch)
   2.221+	(error "Refreshing %s... %s" patch (hg-chomp (cdr ret)))))))
   2.222+
   2.223+(defun mq-refresh (&optional git)
   2.224+  "Refresh the topmost applied patch.
   2.225+With a prefix argument, generate a git-compatible patch."
   2.226+  (interactive "P")
   2.227+  (let ((root (hg-root)))
   2.228+    (unless root
   2.229+      (error "Cannot refresh outside of a repository!"))
   2.230+    (apply 'mq-refresh-internal root (if git '("--git")))))
   2.231+
   2.232+(defun mq-patch-info (cmd &optional msg)
   2.233+  (let* ((ret (hg-run cmd))
   2.234+	 (info (hg-chomp (cdr ret))))
   2.235+    (if (equal (car ret) 0)
   2.236+	(if msg
   2.237+	    (message "%s patch: %s" msg info)
   2.238+	  info)
   2.239+      (error "%s" info))))
   2.240+
   2.241+(defun mq-top ()
   2.242+  "Print the name of the topmost applied patch."
   2.243+  (interactive)
   2.244+  (mq-patch-info "qtop" "Top"))
   2.245+
   2.246+(defun mq-next ()
   2.247+  "Print the name of the next patch to be pushed."
   2.248+  (interactive)
   2.249+  (mq-patch-info "qnext" "Next"))
   2.250+
   2.251+(defun mq-previous ()
   2.252+  "Print the name of the first patch below the topmost applied patch.
   2.253+This would become the active patch if popped to."
   2.254+  (interactive)
   2.255+  (mq-patch-info "qprev" "Previous"))
   2.256+
   2.257+(defun mq-edit-finish ()
   2.258+  "Finish editing the description of this patch, and refresh the patch."
   2.259+  (interactive)
   2.260+  (unless (equal (mq-patch-info "qtop") mq-top)
   2.261+    (error "Topmost patch has changed!"))
   2.262+  (hg-sync-buffers hg-root)
   2.263+  (run-hooks 'mq-edit-finish-hook)
   2.264+  (mq-refresh-internal hg-root "-m" (buffer-substring (point-min) (point-max)))
   2.265+  (let ((buf mq-prev-buffer))
   2.266+    (kill-buffer nil)
   2.267+    (switch-to-buffer buf)))
   2.268+
   2.269+(defun mq-edit-kill ()
   2.270+  "Kill the edit currently being prepared."
   2.271+  (interactive)
   2.272+  (when (or (not (buffer-modified-p)) (y-or-n-p "Really kill this edit? "))
   2.273+    (let ((buf mq-prev-buffer))
   2.274+      (kill-buffer nil)
   2.275+      (switch-to-buffer buf))))
   2.276+
   2.277+(defun mq-get-top (root)
   2.278+  (let ((entry (assoc root mq-top-patch)))
   2.279+    (if entry
   2.280+        (cdr entry))))
   2.281+
   2.282+(defun mq-set-top (root patch)
   2.283+  (let ((entry (assoc root mq-top-patch)))
   2.284+    (if entry
   2.285+        (if patch
   2.286+            (setcdr entry patch)
   2.287+          (setq mq-top-patch (delq entry mq-top-patch)))
   2.288+      (setq mq-top-patch (cons (cons root patch) mq-top-patch)))))
   2.289+
   2.290+(defun mq-update-mode-lines (root)
   2.291+  (let ((cwd default-directory))
   2.292+    (cd root)
   2.293+    (condition-case nil
   2.294+        (mq-set-top root (mq-patch-info "qtop"))
   2.295+      (error (mq-set-top root nil)))
   2.296+    (cd cwd))
   2.297+  (let ((patch (mq-get-top root)))
   2.298+    (save-excursion
   2.299+      (dolist (buf (hg-buffers-visiting-repo root))
   2.300+        (set-buffer buf)
   2.301+        (if mq-mode
   2.302+            (setq mq-mode (or (and patch (concat " MQ:" patch)) " MQ")))))))
   2.303+	
   2.304+(defun mq-mode (&optional arg)
   2.305+  "Minor mode for Mercurial repositories with an MQ patch queue"
   2.306+  (interactive "i")
   2.307+  (cond ((hg-root)
   2.308+         (setq mq-mode (if (null arg) (not mq-mode)
   2.309+                         arg))
   2.310+         (mq-update-mode-lines (hg-root))))
   2.311+  (run-hooks 'mq-mode-hook))
   2.312+
   2.313+(defun mq-edit-mode ()
   2.314+  "Mode for editing the description of a patch.
   2.315+
   2.316+Key bindings
   2.317+------------
   2.318+\\[mq-edit-finish]	use this description
   2.319+\\[mq-edit-kill]	abandon this description"
   2.320+  (interactive)
   2.321+  (use-local-map mq-edit-mode-map)
   2.322+  (set-syntax-table text-mode-syntax-table)
   2.323+  (setq local-abbrev-table text-mode-abbrev-table
   2.324+	major-mode 'mq-edit-mode
   2.325+	mode-name "MQ-Edit")
   2.326+  (set-buffer-modified-p nil)
   2.327+  (setq buffer-undo-list nil)
   2.328+  (run-hooks 'text-mode-hook 'mq-edit-mode-hook))
   2.329+
   2.330+(defun mq-refresh-edit ()
   2.331+  "Refresh the topmost applied patch, editing the patch description."
   2.332+  (interactive)
   2.333+  (while mq-prev-buffer
   2.334+    (set-buffer mq-prev-buffer))
   2.335+  (let ((root (hg-root))
   2.336+	(prev-buffer (current-buffer))
   2.337+	(patch (mq-patch-info "qtop")))
   2.338+    (hg-sync-buffers root)
   2.339+    (let ((buf-name (format "*MQ: Edit description of %s*" patch)))
   2.340+      (switch-to-buffer (get-buffer-create buf-name))
   2.341+      (when (= (point-min) (point-max))
   2.342+	(set (make-local-variable 'hg-root) root)
   2.343+	(set (make-local-variable 'mq-top) patch)
   2.344+	(setq mq-prev-buffer prev-buffer)
   2.345+	(insert (hg-run0 "qheader"))
   2.346+	(goto-char (point-min)))
   2.347+      (mq-edit-mode)
   2.348+      (cd root)))
   2.349+  (message "Type `C-c C-c' to finish editing and refresh the patch."))
   2.350+
   2.351+(defun mq-new (name)
   2.352+  "Create a new empty patch named NAME.
   2.353+The patch is applied on top of the current topmost patch.
   2.354+With a prefix argument, forcibly create the patch even if the working
   2.355+directory is modified."
   2.356+  (interactive (list (mq-read-patch-name "qseries" " to create" t)))
   2.357+  (message "Creating patch...")
   2.358+  (let ((ret (if current-prefix-arg
   2.359+		 (hg-run "qnew" "-f" name)
   2.360+	       (hg-run "qnew" name))))
   2.361+    (if (equal (car ret) 0)
   2.362+	(progn
   2.363+	  (hg-update-mode-lines (buffer-file-name))
   2.364+	  (message "Creating patch... done."))
   2.365+      (error "Creating patch... %s" (hg-chomp (cdr ret))))))
   2.366+
   2.367+(defun mq-edit-series ()
   2.368+  "Edit the MQ series file directly."
   2.369+  (interactive)
   2.370+  (let ((root (hg-root)))
   2.371+    (unless root
   2.372+      (error "Not in an MQ repository!"))
   2.373+    (find-file (concat root ".hg/patches/series"))))
   2.374+
   2.375+(defun mq-diff (&optional git)
   2.376+  "Display a diff of the topmost applied patch.
   2.377+With a prefix argument, display a git-compatible diff."
   2.378+  (interactive "P")
   2.379+  (hg-view-output ((format "MQ: Diff of %s" (mq-patch-info "qtop")))
   2.380+    (if git
   2.381+	(call-process (hg-binary) nil t nil "qdiff" "--git")
   2.382+    (call-process (hg-binary) nil t nil "qdiff"))
   2.383+    (diff-mode)
   2.384+    (font-lock-fontify-buffer)))
   2.385+
   2.386+(defun mq-signoff ()
   2.387+  "Sign off on the current patch, in the style used by the Linux kernel.
   2.388+If the variable mq-signoff-address is non-nil, it will be used, otherwise
   2.389+the value of the ui.username item from your hgrc will be used."
   2.390+  (interactive)
   2.391+  (let ((was-editing (eq major-mode 'mq-edit-mode))
   2.392+	signed)
   2.393+    (unless was-editing
   2.394+      (mq-refresh-edit))
   2.395+    (save-excursion
   2.396+      (let* ((user (or mq-signoff-address
   2.397+		       (hg-run0 "debugconfig" "ui.username")))
   2.398+	     (signoff (concat "Signed-off-by: " user)))
   2.399+	(if (search-forward signoff nil t)
   2.400+	    (message "You have already signed off on this patch.")
   2.401+	  (goto-char (point-max))
   2.402+	  (let ((case-fold-search t))
   2.403+	    (if (re-search-backward "^Signed-off-by: " nil t)
   2.404+		(forward-line 1)
   2.405+	      (insert "\n")))
   2.406+	  (insert signoff)
   2.407+	  (message "%s" signoff)
   2.408+	  (setq signed t))))
   2.409+    (unless was-editing
   2.410+      (if signed
   2.411+	  (mq-edit-finish)
   2.412+	(mq-edit-kill)))))
   2.413+
   2.414+
   2.415+(provide 'mq)
   2.416+
   2.417+
   2.418+;;; Local Variables:
   2.419+;;; prompt-to-byte-compile: nil
   2.420+;;; end: