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