*** empty log message ***
[bpt/emacs.git] / lisp / vc-hg.el
CommitLineData
61223448
DN
1;;; vc-hg.el --- VC backend for the mercurial version control system
2
409cc4a3 3;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
248c6645 4
61223448 5;; Author: Ivan Kanis
248c6645 6;; Keywords: tools
a58b1e40
GM
7
8;; This file is part of GNU Emacs.
9
eb3fa2cf 10;; GNU Emacs is free software: you can redistribute it and/or modify
61223448 11;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
a58b1e40
GM
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
61223448 20;; You should have received a copy of the GNU General Public License
eb3fa2cf 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
61223448
DN
22
23;;; Commentary:
24
25;; This is a mercurial version control backend
26
248c6645
DN
27;;; Thanks:
28
29;;; Bugs:
30
31;;; Installation:
32
33;;; Todo:
34
ec4149ff 35;; 1) Implement the rest of the vc interface. See the comment at the
a07e665b
DN
36;; beginning of vc.el. The current status is:
37
38;; FUNCTION NAME STATUS
a6ea7ffc
DN
39;; BACKEND PROPERTIES
40;; * revision-granularity OK
41;; STATE-QUERYING FUNCTIONS
a07e665b
DN
42;; * registered (file) OK
43;; * state (file) OK
ec4149ff 44;; - state-heuristic (file) NOT NEEDED
ac3f4c6f 45;; * working-revision (file) OK
a07e665b 46;; - latest-on-branch-p (file) ??
70e2f6c7 47;; * checkout-model (files) OK
a272e668 48;; - workfile-unchanged-p (file) OK
a07e665b 49;; - mode-line-string (file) NOT NEEDED
0a299408 50;; - prettify-state-info (file) OK
a07e665b 51;; STATE-CHANGING FUNCTIONS
8cdd17b4 52;; * register (files &optional rev comment) OK
a6ea7ffc 53;; * create-repo () OK
ec4149ff 54;; - init-revision () NOT NEEDED
a07e665b
DN
55;; - responsible-p (file) OK
56;; - could-register (file) OK
57;; - receive-file (file rev) ?? PROBABLY NOT NEEDED
58;; - unregister (file) COMMENTED OUT, MAY BE INCORRECT
8cdd17b4 59;; * checkin (files rev comment) OK
ec4149ff 60;; * find-revision (file rev buffer) OK
a6ea7ffc 61;; * checkout (file &optional editable rev) OK
a07e665b 62;; * revert (file &optional contents-done) OK
62754d29 63;; - rollback (files) ?? PROBABLY NOT NEEDED
a07e665b
DN
64;; - merge (file rev1 rev2) NEEDED
65;; - merge-news (file) NEEDED
ec4149ff 66;; - steal-lock (file &optional revision) NOT NEEDED
a07e665b 67;; HISTORY FUNCTIONS
8cdd17b4 68;; * print-log (files &optional buffer) OK
a07e665b 69;; - log-view-mode () OK
ec4149ff 70;; - show-log-entry (revision) NOT NEEDED, DEFAULT IS GOOD
a07e665b
DN
71;; - comment-history (file) NOT NEEDED
72;; - update-changelog (files) NOT NEEDED
8cdd17b4 73;; * diff (files &optional rev1 rev2 buffer) OK
54a2247d 74;; - revision-completion-table (files) OK?
a07e665b
DN
75;; - annotate-command (file buf &optional rev) OK
76;; - annotate-time () OK
ec4149ff 77;; - annotate-current-time () NOT NEEDED
a07e665b 78;; - annotate-extract-revision-at-line () OK
370fded4
ER
79;; TAG SYSTEM
80;; - create-tag (dir name branchp) NEEDED
81;; - retrieve-tag (dir name update) NEEDED
a07e665b
DN
82;; MISCELLANEOUS
83;; - make-version-backups-p (file) ??
62754d29 84;; - repository-hostname (dirname) ??
ec4149ff
DN
85;; - previous-revision (file rev) OK
86;; - next-revision (file rev) OK
a07e665b
DN
87;; - check-headers () ??
88;; - clear-headers () ??
89;; - delete-file (file) TEST IT
90;; - rename-file (old new) OK
91;; - find-file-hook () PROBABLY NOT NEEDED
92;; - find-file-not-found-hook () PROBABLY NOT NEEDED
61223448 93
ec4149ff 94;; 2) Implement Stefan Monnier's advice:
248c6645
DN
95;; vc-hg-registered and vc-hg-state
96;; Both of those functions should be super extra careful to fail gracefully in
a07e665b 97;; unexpected circumstances. The reason this is important is that any error
248c6645
DN
98;; there will prevent the user from even looking at the file :-(
99;; Ideally, just like in vc-arch and vc-cvs, checking that the file is under
100;; mercurial's control and extracting the current revision should be done
101;; without even using `hg' (this way even if you don't have `hg' installed,
102;; Emacs is able to tell you this file is under mercurial's control).
61223448 103
248c6645 104;;; History:
11a4edc2 105;;
61223448
DN
106
107;;; Code:
108
109(eval-when-compile
34b7fb85 110 (require 'cl)
10c7e431
DN
111 (require 'vc)
112 (require 'vc-dir))
61223448 113
61223448
DN
114;;; Customization options
115
116(defcustom vc-hg-global-switches nil
117 "*Global switches to pass to any Hg command."
118 :type '(choice (const :tag "None" nil)
119 (string :tag "Argument String")
120 (repeat :tag "Argument List"
121 :value ("")
122 string))
a07e665b 123 :version "22.2"
61223448
DN
124 :group 'vc)
125
8cdd17b4
ER
126\f
127;;; Properties of the backend
128
70e2f6c7
ER
129(defun vc-hg-revision-granularity () 'repository)
130(defun vc-hg-checkout-model (files) 'implicit)
8cdd17b4 131
61223448
DN
132;;; State querying functions
133
11a4edc2
SM
134;;;###autoload (defun vc-hg-registered (file)
135;;;###autoload "Return non-nil if FILE is registered with hg."
136;;;###autoload (if (vc-find-root file ".hg") ; short cut
137;;;###autoload (progn
138;;;###autoload (load "vc-hg")
139;;;###autoload (vc-hg-registered file))))
140
6772c8e1 141;; Modeled after the similar function in vc-bzr.el
61223448 142(defun vc-hg-registered (file)
248c6645 143 "Return non-nil if FILE is registered with hg."
a6ea7ffc 144 (when (vc-hg-root file) ; short cut
6c47d819 145 (let ((state (vc-hg-state file))) ; expensive
f1e22ada 146 (and state (not (memq state '(ignored unregistered)))))))
61223448
DN
147
148(defun vc-hg-state (file)
248c6645 149 "Hg-specific version of `vc-state'."
62754d29 150 (let*
b33ac3b7
DN
151 ((status nil)
152 (out
153 (with-output-to-string
154 (with-current-buffer
155 standard-output
156 (setq status
157 (condition-case nil
158 ;; Ignore all errors.
159 (call-process
160 "hg" nil t nil "--cwd" (file-name-directory file)
6c47d819 161 "status" "-A" (file-name-nondirectory file))
b33ac3b7
DN
162 ;; Some problem happened. E.g. We can't find an `hg'
163 ;; executable.
164 (error nil)))))))
165 (when (eq 0 status)
a6ea7ffc
DN
166 (when (null (string-match ".*: No such file or directory$" out))
167 (let ((state (aref out 0)))
168 (cond
b38f5e6f 169 ((eq state ?=) 'up-to-date)
6a3f9bb7 170 ((eq state ?A) 'added)
a6ea7ffc 171 ((eq state ?M) 'edited)
722f037f 172 ((eq state ?I) 'ignored)
5440448e 173 ((eq state ?R) 'removed)
42550348 174 ((eq state ?!) 'missing)
722f037f 175 ((eq state ??) 'unregistered)
b38f5e6f 176 ((eq state ?C) 'up-to-date) ;; Older mercurials use this
6c47d819 177 (t 'up-to-date)))))))
a6ea7ffc 178
ac3f4c6f
ER
179(defun vc-hg-working-revision (file)
180 "Hg-specific version of `vc-working-revision'."
62754d29 181 (let*
b33ac3b7
DN
182 ((status nil)
183 (out
184 (with-output-to-string
185 (with-current-buffer
186 standard-output
187 (setq status
188 (condition-case nil
189 ;; Ignore all errors.
190 (call-process
191 "hg" nil t nil "--cwd" (file-name-directory file)
192 "log" "-l1" (file-name-nondirectory file))
193 ;; Some problem happened. E.g. We can't find an `hg'
194 ;; executable.
195 (error nil)))))))
196 (when (eq 0 status)
197 (if (string-match "changeset: *\\([0-9]*\\)" out)
198 (match-string 1 out)
199 "0"))))
61223448 200
61223448
DN
201;;; History functions
202
be01714b 203(defun vc-hg-print-log (files &optional buffer)
8cdd17b4 204 "Get change log associated with FILES."
be01714b 205 ;; `log-view-mode' needs to have the file names in order to function
7c1912af
DN
206 ;; correctly. "hg log" does not print it, so we insert it here by
207 ;; hand.
208
209 ;; `vc-do-command' creates the buffer, but we need it before running
210 ;; the command.
211 (vc-setup-buffer buffer)
212 ;; If the buffer exists from a previous invocation it might be
213 ;; read-only.
214 (let ((inhibit-read-only t))
6653c6b7
DN
215 (with-current-buffer
216 buffer
217 (vc-hg-command buffer 0 files "log"))))
61223448 218
d797e643
DN
219(defvar log-view-message-re)
220(defvar log-view-file-re)
221(defvar log-view-font-lock-keywords)
6653c6b7 222(defvar log-view-per-file-logs)
d797e643 223
4211679b 224(define-derived-mode vc-hg-log-view-mode log-view-mode "Hg-Log-View"
f0230324 225 (require 'add-log) ;; we need the add-log faces
6653c6b7
DN
226 (set (make-local-variable 'log-view-file-re) "\\`a\\`")
227 (set (make-local-variable 'log-view-per-file-logs) nil)
d797e643
DN
228 (set (make-local-variable 'log-view-message-re)
229 "^changeset:[ \t]*\\([0-9]+\\):\\(.+\\)")
230 (set (make-local-variable 'log-view-font-lock-keywords)
11a4edc2 231 (append
e72e768b 232 log-view-font-lock-keywords
698c8717 233 '(
d797e643
DN
234 ;; Handle the case:
235 ;; user: FirstName LastName <foo@bar>
236 ("^user:[ \t]+\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]"
237 (1 'change-log-name)
238 (2 'change-log-email))
698c8717 239 ;; Handle the cases:
62754d29
TTN
240 ;; user: foo@bar
241 ;; and
698c8717
DN
242 ;; user: foo
243 ("^user:[ \t]+\\([A-Za-z0-9_.+-]+\\(?:@[A-Za-z0-9_.-]+\\)?\\)"
244 (1 'change-log-email))
d797e643 245 ("^date: \\(.+\\)" (1 'change-log-date))
e72e768b 246 ("^summary:[ \t]+\\(.+\\)" (1 'log-view-message))))))
d797e643 247
8cdd17b4 248(defun vc-hg-diff (files &optional oldvers newvers buffer)
5b5afd50 249 "Get a difference report using hg between two revisions of FILES."
6653c6b7
DN
250 (let* ((firstfile (car files))
251 (working (and firstfile (vc-working-revision firstfile))))
ec4149ff
DN
252 (when (and (equal oldvers working) (not newvers))
253 (setq oldvers nil))
254 (when (and (not oldvers) newvers)
255 (setq oldvers working))
d7927b9f
DN
256 (apply #'vc-hg-command (or buffer "*vc-diff*") nil
257 (mapcar (lambda (file) (file-name-nondirectory file)) files)
6653c6b7
DN
258 "--cwd" (or (when firstfile (file-name-directory firstfile))
259 (expand-file-name default-directory))
d7927b9f 260 "diff"
11a4edc2 261 (append
ec4149ff
DN
262 (when oldvers
263 (if newvers
264 (list "-r" oldvers "-r" newvers)
265 (list "-r" oldvers)))))))
cdaf01cc 266
87d1a48e
SM
267(defun vc-hg-revision-table (files)
268 (let ((default-directory (file-name-directory (car files))))
34b7fb85 269 (with-temp-buffer
004a00f4 270 (vc-hg-command t nil files "log" "--template" "{rev} ")
62754d29 271 (split-string
34b7fb85
DN
272 (buffer-substring-no-properties (point-min) (point-max))))))
273
6772c8e1 274;; Modeled after the similar function in vc-cvs.el
87d1a48e
SM
275(defun vc-hg-revision-completion-table (files)
276 (lexical-let ((files files)
eff23ff3
DN
277 table)
278 (setq table (lazy-completion-table
87d1a48e 279 table (lambda () (vc-hg-revision-table files))))
eff23ff3 280 table))
34b7fb85 281
5b5afd50 282(defun vc-hg-annotate-command (file buffer &optional revision)
cdaf01cc 283 "Execute \"hg annotate\" on FILE, inserting the contents in BUFFER.
5b5afd50 284Optional arg REVISION is a revision to annotate from."
fe4f8695 285 (vc-hg-command buffer 0 file "annotate" "-d" "-n"
ec4149ff 286 (when revision (concat "-r" revision)))
cdaf01cc
DN
287 (with-current-buffer buffer
288 (goto-char (point-min))
9f940545
DN
289 (re-search-forward "^[ \t]*[0-9]")
290 (delete-region (point-min) (match-beginning 0))))
cdaf01cc 291
f8bd9ac6 292(declare-function vc-annotate-convert-time "vc-annotate" (time))
cdaf01cc 293
11a4edc2
SM
294;; The format for one line output by "hg annotate -d -n" looks like this:
295;;215 Wed Jun 20 21:22:58 2007 -0700: CONTENTS
296;; i.e: VERSION_NUMBER DATE: CONTENTS
4064ff25
DN
297;; If the user has set the "--follow" option, the output looks like:
298;;215 Wed Jun 20 21:22:58 2007 -0700 foo.c: CONTENTS
299;; i.e. VERSION_NUMBER DATE FILENAME: CONTENTS
300(defconst vc-hg-annotate-re
301 "^[ \t]*\\([0-9]+\\) \\(.\\{30\\}\\)[^:\n]*\\(:[^ \n][^:\n]*\\)*: ")
cdaf01cc
DN
302
303(defun vc-hg-annotate-time ()
304 (when (looking-at vc-hg-annotate-re)
305 (goto-char (match-end 0))
11a4edc2 306 (vc-annotate-convert-time
cdaf01cc
DN
307 (date-to-time (match-string-no-properties 2)))))
308
309(defun vc-hg-annotate-extract-revision-at-line ()
310 (save-excursion
311 (beginning-of-line)
4064ff25 312 (when (looking-at vc-hg-annotate-re) (match-string-no-properties 1))))
cdaf01cc 313
5b5afd50 314(defun vc-hg-previous-revision (file rev)
cdaf01cc
DN
315 (let ((newrev (1- (string-to-number rev))))
316 (when (>= newrev 0)
317 (number-to-string newrev))))
61223448 318
5b5afd50 319(defun vc-hg-next-revision (file rev)
a07e665b 320 (let ((newrev (1+ (string-to-number rev)))
62754d29 321 (tip-revision
a07e665b 322 (with-temp-buffer
34b7fb85 323 (vc-hg-command t 0 nil "tip")
a07e665b
DN
324 (goto-char (point-min))
325 (re-search-forward "^changeset:[ \t]*\\([0-9]+\\):")
326 (string-to-number (match-string-no-properties 1)))))
5b5afd50
ER
327 ;; We don't want to exceed the maximum possible revision number, ie
328 ;; the tip revision.
329 (when (<= newrev tip-revision)
a07e665b
DN
330 (number-to-string newrev))))
331
6772c8e1 332;; Modeled after the similar function in vc-bzr.el
a07e665b
DN
333(defun vc-hg-delete-file (file)
334 "Delete FILE and delete it in the hg repository."
335 (condition-case ()
336 (delete-file file)
337 (file-error nil))
34b7fb85 338 (vc-hg-command nil 0 file "remove" "--after" "--force"))
a07e665b 339
6772c8e1 340;; Modeled after the similar function in vc-bzr.el
a07e665b
DN
341(defun vc-hg-rename-file (old new)
342 "Rename file from OLD to NEW using `hg mv'."
bfd57731 343 (vc-hg-command nil 0 new "mv" old))
a07e665b 344
8cdd17b4
ER
345(defun vc-hg-register (files &optional rev comment)
346 "Register FILES under hg.
248c6645
DN
347REV is ignored.
348COMMENT is ignored."
34b7fb85 349 (vc-hg-command nil 0 files "add"))
8cdd17b4
ER
350
351(defun vc-hg-create-repo ()
352 "Create a new Mercurial repository."
34b7fb85 353 (vc-hg-command nil 0 nil "init"))
248c6645 354
a07e665b
DN
355(defalias 'vc-hg-responsible-p 'vc-hg-root)
356
6772c8e1 357;; Modeled after the similar function in vc-bzr.el
a07e665b
DN
358(defun vc-hg-could-register (file)
359 "Return non-nil if FILE could be registered under hg."
360 (and (vc-hg-responsible-p file) ; shortcut
361 (condition-case ()
362 (with-temp-buffer
363 (vc-hg-command t nil file "add" "--dry-run"))
364 ;; The command succeeds with no output if file is
365 ;; registered.
366 (error))))
367
4f10da1c 368;; FIXME: This would remove the file. Is that correct?
a07e665b
DN
369;; (defun vc-hg-unregister (file)
370;; "Unregister FILE from hg."
371;; (vc-hg-command nil nil file "remove"))
372
8cdd17b4 373(defun vc-hg-checkin (files rev comment)
4211679b 374 "Hg-specific version of `vc-backend-checkin'.
cdaf01cc 375REV is ignored."
34b7fb85 376 (vc-hg-command nil 0 files "commit" "-m" comment))
cdaf01cc 377
ac3f4c6f 378(defun vc-hg-find-revision (file rev buffer)
248c6645
DN
379 (let ((coding-system-for-read 'binary)
380 (coding-system-for-write 'binary))
248c6645 381 (if rev
34b7fb85
DN
382 (vc-hg-command buffer 0 file "cat" "-r" rev)
383 (vc-hg-command buffer 0 file "cat"))))
a07e665b 384
6772c8e1 385;; Modeled after the similar function in vc-bzr.el
a6ea7ffc
DN
386(defun vc-hg-checkout (file &optional editable rev)
387 "Retrieve a revision of FILE.
388EDITABLE is ignored.
389REV is the revision to check out into WORKFILE."
390 (let ((coding-system-for-read 'binary)
391 (coding-system-for-write 'binary))
392 (with-current-buffer (or (get-file-buffer file) (current-buffer))
393 (if rev
34b7fb85
DN
394 (vc-hg-command t 0 file "cat" "-r" rev)
395 (vc-hg-command t 0 file "cat")))))
248c6645 396
6772c8e1 397;; Modeled after the similar function in vc-bzr.el
a272e668
DN
398(defun vc-hg-workfile-unchanged-p (file)
399 (eq 'up-to-date (vc-hg-state file)))
400
6772c8e1 401;; Modeled after the similar function in vc-bzr.el
b33ac3b7
DN
402(defun vc-hg-revert (file &optional contents-done)
403 (unless contents-done
34b7fb85 404 (with-temp-buffer (vc-hg-command t 0 file "revert"))))
b33ac3b7 405
f0230324
DN
406;;; Hg specific functionality.
407
f0230324
DN
408(defvar vc-hg-extra-menu-map
409 (let ((map (make-sparse-keymap)))
410 (define-key map [incoming] '(menu-item "Show incoming" vc-hg-incoming))
411 (define-key map [outgoing] '(menu-item "Show outgoing" vc-hg-outgoing))
412 map))
413
414(defun vc-hg-extra-menu () vc-hg-extra-menu-map)
415
25a4ea6d 416(defun vc-hg-extra-status-menu () vc-hg-extra-menu-map)
6656ecaa 417
f0230324
DN
418(define-derived-mode vc-hg-outgoing-mode vc-hg-log-view-mode "Hg-Outgoing")
419
420(define-derived-mode vc-hg-incoming-mode vc-hg-log-view-mode "Hg-Incoming")
421
7db924c0
DN
422(defstruct (vc-hg-extra-fileinfo
423 (:copier nil)
424 (:constructor vc-hg-create-extra-fileinfo (rename-state extra-name))
425 (:conc-name vc-hg-extra-fileinfo->))
426 rename-state ;; rename or copy state
fe4f8695 427 extra-name) ;; original name for copies and rename targets, new name for
7db924c0 428
f8bd9ac6
DN
429(declare-function vc-default-status-printer "vc-dir" (backend fileentry))
430
7db924c0
DN
431(defun vc-hg-status-printer (info)
432 "Pretty-printer for the vc-dir-fileinfo structure."
433 (let ((extra (vc-dir-fileinfo->extra info)))
434 (vc-default-status-printer 'Hg info)
435 (when extra
436 (insert (propertize
437 (format " (%s %s)"
438 (case (vc-hg-extra-fileinfo->rename-state extra)
439 ('copied "copied from")
440 ('renamed-from "renamed from")
441 ('renamed-to "renamed to"))
442 (vc-hg-extra-fileinfo->extra-name extra))
443 'face 'font-lock-comment-face)))))
444
c1b51374 445(defun vc-hg-after-dir-status (update-function)
5ab612e8
DN
446 (let ((status-char nil)
447 (file nil)
448 (translation '((?= . up-to-date)
449 (?C . up-to-date)
450 (?A . added)
451 (?R . removed)
452 (?M . edited)
453 (?I . ignored)
49546869 454 (?! . missing)
7db924c0 455 (? . copy-rename-line)
5ab612e8
DN
456 (?? . unregistered)))
457 (translated nil)
7db924c0
DN
458 (result nil)
459 (last-added nil)
460 (last-line-copy nil))
5ab612e8 461 (goto-char (point-min))
8fcaf22f 462 (while (not (eobp))
7db924c0 463 (setq translated (cdr (assoc (char-after) translation)))
62754d29
TTN
464 (setq file
465 (buffer-substring-no-properties (+ (point) 2)
5ab612e8 466 (line-end-position)))
7db924c0
DN
467 (cond ((not translated)
468 (setq last-line-copy nil))
469 ((eq translated 'up-to-date)
470 (setq last-line-copy nil))
471 ((eq translated 'copy-rename-line)
472 ;; For copied files the output looks like this:
473 ;; A COPIED_FILE_NAME
474 ;; ORIGINAL_FILE_NAME
fe4f8695 475 (setf (nth 2 last-added)
7db924c0
DN
476 (vc-hg-create-extra-fileinfo 'copied file))
477 (setq last-line-copy t))
478 ((and last-line-copy (eq translated 'removed))
479 ;; For renamed files the output looks like this:
480 ;; A NEW_FILE_NAME
481 ;; ORIGINAL_FILE_NAME
482 ;; R ORIGINAL_FILE_NAME
483 ;; We need to adjust the previous entry to not think it is a copy.
484 (setf (vc-hg-extra-fileinfo->rename-state (nth 2 last-added))
485 'renamed-from)
486 (push (list file translated
487 (vc-hg-create-extra-fileinfo
488 'renamed-to (nth 0 last-added))) result)
489 (setq last-line-copy nil))
490 (t
491 (setq last-added (list file translated nil))
492 (push last-added result)
493 (setq last-line-copy nil)))
8fcaf22f 494 (forward-line))
c1b51374 495 (funcall update-function result)))
5ab612e8 496
c1b51374 497(defun vc-hg-dir-status (dir update-function)
7db924c0 498 (vc-hg-command (current-buffer) 'async dir "status" "-C")
115c0061 499 (vc-exec-after
c1b51374 500 `(vc-hg-after-dir-status (quote ,update-function))))
8fcaf22f 501
fe4f8695
SS
502(defun vc-hg-status-extra-header (name &rest commands)
503 (concat (propertize name 'face 'font-lock-type-face)
504 (propertize
505 (with-temp-buffer
506 (apply 'vc-hg-command (current-buffer) 0 nil commands)
507 (buffer-substring-no-properties (point-min) (1- (point-max))))
508 'face 'font-lock-variable-name-face)))
509
510(defun vc-hg-status-extra-headers (dir)
511 "Generate extra status headers for a Mercurial tree."
512 (let ((default-directory dir))
513 (concat
514 (vc-hg-status-extra-header "Root : " "root") "\n"
515 (vc-hg-status-extra-header "Branch : " "id" "-b") "\n"
516 (vc-hg-status-extra-header "Tags : " "id" "-t") ; "\n"
517 ;; these change after each commit
518 ;; (vc-hg-status-extra-header "Local num : " "id" "-n") "\n"
519 ;; (vc-hg-status-extra-header "Global id : " "id" "-i")
520 )))
521
4f10da1c 522;; FIXME: this adds another top level menu, instead figure out how to
f0230324
DN
523;; replace the Log-View menu.
524(easy-menu-define log-view-mode-menu vc-hg-outgoing-mode-map
525 "Hg-outgoing Display Menu"
526 `("Hg-outgoing"
527 ["Push selected" vc-hg-push]))
528
529(easy-menu-define log-view-mode-menu vc-hg-incoming-mode-map
530 "Hg-incoming Display Menu"
531 `("Hg-incoming"
532 ["Pull selected" vc-hg-pull]))
533
534(defun vc-hg-outgoing ()
535 (interactive)
536 (let ((bname "*Hg outgoing*"))
537 (vc-hg-command bname 0 nil "outgoing" "-n")
538 (pop-to-buffer bname)
539 (vc-hg-outgoing-mode)))
540
541(defun vc-hg-incoming ()
542 (interactive)
543 (let ((bname "*Hg incoming*"))
544 (vc-hg-command bname 0 nil "incoming" "-n")
545 (pop-to-buffer bname)
546 (vc-hg-incoming-mode)))
547
004a00f4
DN
548(declare-function log-view-get-marked "log-view" ())
549
f0230324
DN
550;; XXX maybe also add key bindings for these functions.
551(defun vc-hg-push ()
552 (interactive)
553 (let ((marked-list (log-view-get-marked)))
554 (if marked-list
62754d29 555 (vc-hg-command
f0230324
DN
556 nil 0 nil
557 (cons "push"
558 (apply 'nconc
559 (mapcar (lambda (arg) (list "-r" arg)) marked-list))))
560 (error "No log entries selected for push"))))
561
562(defun vc-hg-pull ()
563 (interactive)
564 (let ((marked-list (log-view-get-marked)))
565 (if marked-list
62754d29 566 (vc-hg-command
f0230324
DN
567 nil 0 nil
568 (cons "pull"
569 (apply 'nconc
570 (mapcar (lambda (arg) (list "-r" arg)) marked-list))))
571 (error "No log entries selected for pull"))))
572
61223448
DN
573;;; Internal functions
574
8cdd17b4 575(defun vc-hg-command (buffer okstatus file-or-list &rest flags)
61223448
DN
576 "A wrapper around `vc-do-command' for use in vc-hg.el.
577The difference to vc-do-command is that this function always invokes `hg',
578and that it passes `vc-hg-global-switches' to it before FLAGS."
2888a97e 579 (apply 'vc-do-command (or buffer "*vc*") okstatus "hg" file-or-list
61223448
DN
580 (if (stringp vc-hg-global-switches)
581 (cons vc-hg-global-switches flags)
582 (append vc-hg-global-switches
583 flags))))
584
a07e665b
DN
585(defun vc-hg-root (file)
586 (vc-find-root file ".hg"))
587
61223448
DN
588(provide 'vc-hg)
589
eaaa2b09 590;; arch-tag: bd094dc5-715a-434f-a331-37b9fb7cd954
248c6645 591;;; vc-hg.el ends here