(mail-interactive): Change default.
[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)
61223448
DN
111 (require 'vc))
112
61223448
DN
113;;; Customization options
114
115(defcustom vc-hg-global-switches nil
116 "*Global switches to pass to any Hg command."
117 :type '(choice (const :tag "None" nil)
118 (string :tag "Argument String")
119 (repeat :tag "Argument List"
120 :value ("")
121 string))
a07e665b 122 :version "22.2"
61223448
DN
123 :group 'vc)
124
8cdd17b4
ER
125\f
126;;; Properties of the backend
127
70e2f6c7
ER
128(defun vc-hg-revision-granularity () 'repository)
129(defun vc-hg-checkout-model (files) 'implicit)
8cdd17b4 130
61223448
DN
131;;; State querying functions
132
11a4edc2
SM
133;;;###autoload (defun vc-hg-registered (file)
134;;;###autoload "Return non-nil if FILE is registered with hg."
135;;;###autoload (if (vc-find-root file ".hg") ; short cut
136;;;###autoload (progn
137;;;###autoload (load "vc-hg")
138;;;###autoload (vc-hg-registered file))))
139
140;; Modelled after the similar function in vc-bzr.el
61223448 141(defun vc-hg-registered (file)
248c6645 142 "Return non-nil if FILE is registered with hg."
a6ea7ffc 143 (when (vc-hg-root file) ; short cut
6c47d819
DN
144 (let ((state (vc-hg-state file))) ; expensive
145 (vc-file-setprop file 'vc-state state)
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))
62754d29 215 ;; We need to loop and call "hg log" on each file separately.
a6ea7ffc 216 ;; "hg log" with multiple file arguments mashes all the logs
be01714b
ER
217 ;; together. Ironically enough, this puts us back near CVS
218 ;; which can't generate proper fileset logs either.
a6ea7ffc
DN
219 (dolist (file files)
220 (with-current-buffer
221 buffer
be01714b 222 (insert "Working file: " file "\n")) ;; Like RCS/CVS.
34b7fb85 223 (vc-hg-command buffer 0 file "log"))))
61223448 224
d797e643
DN
225(defvar log-view-message-re)
226(defvar log-view-file-re)
227(defvar log-view-font-lock-keywords)
d797e643 228
4211679b 229(define-derived-mode vc-hg-log-view-mode log-view-mode "Hg-Log-View"
f0230324 230 (require 'add-log) ;; we need the add-log faces
92de528e 231 (set (make-local-variable 'log-view-file-re) "^Working file:[ \t]+\\(.+\\)")
d797e643
DN
232 (set (make-local-variable 'log-view-message-re)
233 "^changeset:[ \t]*\\([0-9]+\\):\\(.+\\)")
234 (set (make-local-variable 'log-view-font-lock-keywords)
11a4edc2 235 (append
e72e768b 236 log-view-font-lock-keywords
698c8717 237 '(
d797e643
DN
238 ;; Handle the case:
239 ;; user: FirstName LastName <foo@bar>
240 ("^user:[ \t]+\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]"
241 (1 'change-log-name)
242 (2 'change-log-email))
698c8717 243 ;; Handle the cases:
62754d29
TTN
244 ;; user: foo@bar
245 ;; and
698c8717
DN
246 ;; user: foo
247 ("^user:[ \t]+\\([A-Za-z0-9_.+-]+\\(?:@[A-Za-z0-9_.-]+\\)?\\)"
248 (1 'change-log-email))
d797e643 249 ("^date: \\(.+\\)" (1 'change-log-date))
e72e768b 250 ("^summary:[ \t]+\\(.+\\)" (1 'log-view-message))))))
d797e643 251
8cdd17b4 252(defun vc-hg-diff (files &optional oldvers newvers buffer)
5b5afd50 253 "Get a difference report using hg between two revisions of FILES."
ac3f4c6f 254 (let ((working (vc-working-revision (car files))))
ec4149ff
DN
255 (when (and (equal oldvers working) (not newvers))
256 (setq oldvers nil))
257 (when (and (not oldvers) newvers)
258 (setq oldvers working))
d7927b9f
DN
259 (apply #'vc-hg-command (or buffer "*vc-diff*") nil
260 (mapcar (lambda (file) (file-name-nondirectory file)) files)
261 "--cwd" (file-name-directory (car files))
262 "diff"
11a4edc2 263 (append
ec4149ff
DN
264 (when oldvers
265 (if newvers
266 (list "-r" oldvers "-r" newvers)
267 (list "-r" oldvers)))))))
cdaf01cc 268
87d1a48e
SM
269(defun vc-hg-revision-table (files)
270 (let ((default-directory (file-name-directory (car files))))
34b7fb85 271 (with-temp-buffer
004a00f4 272 (vc-hg-command t nil files "log" "--template" "{rev} ")
62754d29 273 (split-string
34b7fb85
DN
274 (buffer-substring-no-properties (point-min) (point-max))))))
275
276;; Modelled after the similar function in vc-cvs.el
87d1a48e
SM
277(defun vc-hg-revision-completion-table (files)
278 (lexical-let ((files files)
eff23ff3
DN
279 table)
280 (setq table (lazy-completion-table
87d1a48e 281 table (lambda () (vc-hg-revision-table files))))
eff23ff3 282 table))
34b7fb85 283
5b5afd50 284(defun vc-hg-annotate-command (file buffer &optional revision)
cdaf01cc 285 "Execute \"hg annotate\" on FILE, inserting the contents in BUFFER.
5b5afd50 286Optional arg REVISION is a revision to annotate from."
fe4f8695 287 (vc-hg-command buffer 0 file "annotate" "-d" "-n"
ec4149ff 288 (when revision (concat "-r" revision)))
cdaf01cc
DN
289 (with-current-buffer buffer
290 (goto-char (point-min))
9f940545
DN
291 (re-search-forward "^[ \t]*[0-9]")
292 (delete-region (point-min) (match-beginning 0))))
cdaf01cc
DN
293
294
11a4edc2
SM
295;; The format for one line output by "hg annotate -d -n" looks like this:
296;;215 Wed Jun 20 21:22:58 2007 -0700: CONTENTS
297;; i.e: VERSION_NUMBER DATE: CONTENTS
4064ff25
DN
298;; If the user has set the "--follow" option, the output looks like:
299;;215 Wed Jun 20 21:22:58 2007 -0700 foo.c: CONTENTS
300;; i.e. VERSION_NUMBER DATE FILENAME: CONTENTS
301(defconst vc-hg-annotate-re
302 "^[ \t]*\\([0-9]+\\) \\(.\\{30\\}\\)[^:\n]*\\(:[^ \n][^:\n]*\\)*: ")
cdaf01cc
DN
303
304(defun vc-hg-annotate-time ()
305 (when (looking-at vc-hg-annotate-re)
306 (goto-char (match-end 0))
11a4edc2 307 (vc-annotate-convert-time
cdaf01cc
DN
308 (date-to-time (match-string-no-properties 2)))))
309
310(defun vc-hg-annotate-extract-revision-at-line ()
311 (save-excursion
312 (beginning-of-line)
4064ff25 313 (when (looking-at vc-hg-annotate-re) (match-string-no-properties 1))))
cdaf01cc 314
5b5afd50 315(defun vc-hg-previous-revision (file rev)
cdaf01cc
DN
316 (let ((newrev (1- (string-to-number rev))))
317 (when (>= newrev 0)
318 (number-to-string newrev))))
61223448 319
5b5afd50 320(defun vc-hg-next-revision (file rev)
a07e665b 321 (let ((newrev (1+ (string-to-number rev)))
62754d29 322 (tip-revision
a07e665b 323 (with-temp-buffer
34b7fb85 324 (vc-hg-command t 0 nil "tip")
a07e665b
DN
325 (goto-char (point-min))
326 (re-search-forward "^changeset:[ \t]*\\([0-9]+\\):")
327 (string-to-number (match-string-no-properties 1)))))
5b5afd50
ER
328 ;; We don't want to exceed the maximum possible revision number, ie
329 ;; the tip revision.
330 (when (<= newrev tip-revision)
a07e665b
DN
331 (number-to-string newrev))))
332
333;; Modelled after the similar function in vc-bzr.el
334(defun vc-hg-delete-file (file)
335 "Delete FILE and delete it in the hg repository."
336 (condition-case ()
337 (delete-file file)
338 (file-error nil))
34b7fb85 339 (vc-hg-command nil 0 file "remove" "--after" "--force"))
a07e665b
DN
340
341;; Modelled after the similar function in vc-bzr.el
342(defun vc-hg-rename-file (old new)
343 "Rename file from OLD to NEW using `hg mv'."
bfd57731 344 (vc-hg-command nil 0 new "mv" old))
a07e665b 345
8cdd17b4
ER
346(defun vc-hg-register (files &optional rev comment)
347 "Register FILES under hg.
248c6645
DN
348REV is ignored.
349COMMENT is ignored."
34b7fb85 350 (vc-hg-command nil 0 files "add"))
8cdd17b4
ER
351
352(defun vc-hg-create-repo ()
353 "Create a new Mercurial repository."
34b7fb85 354 (vc-hg-command nil 0 nil "init"))
248c6645 355
a07e665b
DN
356(defalias 'vc-hg-responsible-p 'vc-hg-root)
357
358;; Modelled after the similar function in vc-bzr.el
359(defun vc-hg-could-register (file)
360 "Return non-nil if FILE could be registered under hg."
361 (and (vc-hg-responsible-p file) ; shortcut
362 (condition-case ()
363 (with-temp-buffer
364 (vc-hg-command t nil file "add" "--dry-run"))
365 ;; The command succeeds with no output if file is
366 ;; registered.
367 (error))))
368
369;; XXX This would remove the file. Is that correct?
370;; (defun vc-hg-unregister (file)
371;; "Unregister FILE from hg."
372;; (vc-hg-command nil nil file "remove"))
373
8cdd17b4 374(defun vc-hg-checkin (files rev comment)
4211679b 375 "Hg-specific version of `vc-backend-checkin'.
cdaf01cc 376REV is ignored."
34b7fb85 377 (vc-hg-command nil 0 files "commit" "-m" comment))
cdaf01cc 378
ac3f4c6f 379(defun vc-hg-find-revision (file rev buffer)
248c6645
DN
380 (let ((coding-system-for-read 'binary)
381 (coding-system-for-write 'binary))
248c6645 382 (if rev
34b7fb85
DN
383 (vc-hg-command buffer 0 file "cat" "-r" rev)
384 (vc-hg-command buffer 0 file "cat"))))
a07e665b
DN
385
386;; Modelled after the similar function in vc-bzr.el
a6ea7ffc
DN
387(defun vc-hg-checkout (file &optional editable rev)
388 "Retrieve a revision of FILE.
389EDITABLE is ignored.
390REV is the revision to check out into WORKFILE."
391 (let ((coding-system-for-read 'binary)
392 (coding-system-for-write 'binary))
393 (with-current-buffer (or (get-file-buffer file) (current-buffer))
394 (if rev
34b7fb85
DN
395 (vc-hg-command t 0 file "cat" "-r" rev)
396 (vc-hg-command t 0 file "cat")))))
248c6645 397
a272e668
DN
398;; Modelled after the similar function in vc-bzr.el
399(defun vc-hg-workfile-unchanged-p (file)
400 (eq 'up-to-date (vc-hg-state file)))
401
b33ac3b7
DN
402;; Modelled after the similar function in vc-bzr.el
403(defun vc-hg-revert (file &optional contents-done)
404 (unless contents-done
34b7fb85 405 (with-temp-buffer (vc-hg-command t 0 file "revert"))))
b33ac3b7 406
f0230324
DN
407;;; Hg specific functionality.
408
f0230324
DN
409(defvar vc-hg-extra-menu-map
410 (let ((map (make-sparse-keymap)))
411 (define-key map [incoming] '(menu-item "Show incoming" vc-hg-incoming))
412 (define-key map [outgoing] '(menu-item "Show outgoing" vc-hg-outgoing))
413 map))
414
415(defun vc-hg-extra-menu () vc-hg-extra-menu-map)
416
25a4ea6d 417(defun vc-hg-extra-status-menu () vc-hg-extra-menu-map)
6656ecaa 418
f0230324
DN
419(define-derived-mode vc-hg-outgoing-mode vc-hg-log-view-mode "Hg-Outgoing")
420
421(define-derived-mode vc-hg-incoming-mode vc-hg-log-view-mode "Hg-Incoming")
422
7db924c0
DN
423(defstruct (vc-hg-extra-fileinfo
424 (:copier nil)
425 (:constructor vc-hg-create-extra-fileinfo (rename-state extra-name))
426 (:conc-name vc-hg-extra-fileinfo->))
427 rename-state ;; rename or copy state
fe4f8695 428 extra-name) ;; original name for copies and rename targets, new name for
7db924c0
DN
429
430(defun vc-hg-status-printer (info)
431 "Pretty-printer for the vc-dir-fileinfo structure."
432 (let ((extra (vc-dir-fileinfo->extra info)))
433 (vc-default-status-printer 'Hg info)
434 (when extra
435 (insert (propertize
436 (format " (%s %s)"
437 (case (vc-hg-extra-fileinfo->rename-state extra)
438 ('copied "copied from")
439 ('renamed-from "renamed from")
440 ('renamed-to "renamed to"))
441 (vc-hg-extra-fileinfo->extra-name extra))
442 'face 'font-lock-comment-face)))))
443
c1b51374 444(defun vc-hg-after-dir-status (update-function)
5ab612e8
DN
445 (let ((status-char nil)
446 (file nil)
447 (translation '((?= . up-to-date)
448 (?C . up-to-date)
449 (?A . added)
450 (?R . removed)
451 (?M . edited)
452 (?I . ignored)
49546869 453 (?! . missing)
7db924c0 454 (? . copy-rename-line)
5ab612e8
DN
455 (?? . unregistered)))
456 (translated nil)
7db924c0
DN
457 (result nil)
458 (last-added nil)
459 (last-line-copy nil))
5ab612e8 460 (goto-char (point-min))
8fcaf22f 461 (while (not (eobp))
7db924c0 462 (setq translated (cdr (assoc (char-after) translation)))
62754d29
TTN
463 (setq file
464 (buffer-substring-no-properties (+ (point) 2)
5ab612e8 465 (line-end-position)))
7db924c0
DN
466 (cond ((not translated)
467 (setq last-line-copy nil))
468 ((eq translated 'up-to-date)
469 (setq last-line-copy nil))
470 ((eq translated 'copy-rename-line)
471 ;; For copied files the output looks like this:
472 ;; A COPIED_FILE_NAME
473 ;; ORIGINAL_FILE_NAME
fe4f8695 474 (setf (nth 2 last-added)
7db924c0
DN
475 (vc-hg-create-extra-fileinfo 'copied file))
476 (setq last-line-copy t))
477 ((and last-line-copy (eq translated 'removed))
478 ;; For renamed files the output looks like this:
479 ;; A NEW_FILE_NAME
480 ;; ORIGINAL_FILE_NAME
481 ;; R ORIGINAL_FILE_NAME
482 ;; We need to adjust the previous entry to not think it is a copy.
483 (setf (vc-hg-extra-fileinfo->rename-state (nth 2 last-added))
484 'renamed-from)
485 (push (list file translated
486 (vc-hg-create-extra-fileinfo
487 'renamed-to (nth 0 last-added))) result)
488 (setq last-line-copy nil))
489 (t
490 (setq last-added (list file translated nil))
491 (push last-added result)
492 (setq last-line-copy nil)))
8fcaf22f 493 (forward-line))
c1b51374 494 (funcall update-function result)))
5ab612e8 495
c1b51374 496(defun vc-hg-dir-status (dir update-function)
7db924c0 497 (vc-hg-command (current-buffer) 'async dir "status" "-C")
115c0061 498 (vc-exec-after
c1b51374 499 `(vc-hg-after-dir-status (quote ,update-function))))
8fcaf22f 500
fe4f8695
SS
501(defun vc-hg-status-extra-header (name &rest commands)
502 (concat (propertize name 'face 'font-lock-type-face)
503 (propertize
504 (with-temp-buffer
505 (apply 'vc-hg-command (current-buffer) 0 nil commands)
506 (buffer-substring-no-properties (point-min) (1- (point-max))))
507 'face 'font-lock-variable-name-face)))
508
509(defun vc-hg-status-extra-headers (dir)
510 "Generate extra status headers for a Mercurial tree."
511 (let ((default-directory dir))
512 (concat
513 (vc-hg-status-extra-header "Root : " "root") "\n"
514 (vc-hg-status-extra-header "Branch : " "id" "-b") "\n"
515 (vc-hg-status-extra-header "Tags : " "id" "-t") ; "\n"
516 ;; these change after each commit
517 ;; (vc-hg-status-extra-header "Local num : " "id" "-n") "\n"
518 ;; (vc-hg-status-extra-header "Global id : " "id" "-i")
519 )))
520
f0230324
DN
521;; XXX this adds another top level menu, instead figure out how to
522;; replace the Log-View menu.
523(easy-menu-define log-view-mode-menu vc-hg-outgoing-mode-map
524 "Hg-outgoing Display Menu"
525 `("Hg-outgoing"
526 ["Push selected" vc-hg-push]))
527
528(easy-menu-define log-view-mode-menu vc-hg-incoming-mode-map
529 "Hg-incoming Display Menu"
530 `("Hg-incoming"
531 ["Pull selected" vc-hg-pull]))
532
533(defun vc-hg-outgoing ()
534 (interactive)
535 (let ((bname "*Hg outgoing*"))
536 (vc-hg-command bname 0 nil "outgoing" "-n")
537 (pop-to-buffer bname)
538 (vc-hg-outgoing-mode)))
539
540(defun vc-hg-incoming ()
541 (interactive)
542 (let ((bname "*Hg incoming*"))
543 (vc-hg-command bname 0 nil "incoming" "-n")
544 (pop-to-buffer bname)
545 (vc-hg-incoming-mode)))
546
004a00f4
DN
547(declare-function log-view-get-marked "log-view" ())
548
f0230324
DN
549;; XXX maybe also add key bindings for these functions.
550(defun vc-hg-push ()
551 (interactive)
552 (let ((marked-list (log-view-get-marked)))
553 (if marked-list
62754d29 554 (vc-hg-command
f0230324
DN
555 nil 0 nil
556 (cons "push"
557 (apply 'nconc
558 (mapcar (lambda (arg) (list "-r" arg)) marked-list))))
559 (error "No log entries selected for push"))))
560
561(defun vc-hg-pull ()
562 (interactive)
563 (let ((marked-list (log-view-get-marked)))
564 (if marked-list
62754d29 565 (vc-hg-command
f0230324
DN
566 nil 0 nil
567 (cons "pull"
568 (apply 'nconc
569 (mapcar (lambda (arg) (list "-r" arg)) marked-list))))
570 (error "No log entries selected for pull"))))
571
61223448
DN
572;;; Internal functions
573
8cdd17b4 574(defun vc-hg-command (buffer okstatus file-or-list &rest flags)
61223448
DN
575 "A wrapper around `vc-do-command' for use in vc-hg.el.
576The difference to vc-do-command is that this function always invokes `hg',
577and that it passes `vc-hg-global-switches' to it before FLAGS."
2888a97e 578 (apply 'vc-do-command (or buffer "*vc*") okstatus "hg" file-or-list
61223448
DN
579 (if (stringp vc-hg-global-switches)
580 (cons vc-hg-global-switches flags)
581 (append vc-hg-global-switches
582 flags))))
583
a07e665b
DN
584(defun vc-hg-root (file)
585 (vc-find-root file ".hg"))
586
61223448
DN
587(provide 'vc-hg)
588
eaaa2b09 589;; arch-tag: bd094dc5-715a-434f-a331-37b9fb7cd954
248c6645 590;;; vc-hg.el ends here