comparison contrib/mercurial.el @ 995:1e4b009b379e

Emacs support: add hg-revert-buffer.
author Bryan O'Sullivan <bos@serpentine.com>
date Sun, 21 Aug 2005 21:51:01 -0800
parents d845a1f174bb
children 5ed566574486
comparison
equal deleted inserted replaced
988:a66e249d77ae 995:1e4b009b379e
96 :group 'mercurial) 96 :group 'mercurial)
97 97
98 (defcustom hg-log-limit 50 98 (defcustom hg-log-limit 50
99 "The maximum number of revisions that hg-log will display." 99 "The maximum number of revisions that hg-log will display."
100 :type 'integer 100 :type 'integer
101 :group 'mercurial)
102
103 (defcustom hg-update-modeline t
104 "Whether to update the modeline with the status of a file after every save.
105 Set this to nil on platforms with poor process management, such as Windows."
106 :type 'boolean
101 :group 'mercurial) 107 :group 'mercurial)
102 108
103 109
104 ;;; Other variables. 110 ;;; Other variables.
105 111
135 (define-key hg-prefix-map "c" 'hg-undo) 141 (define-key hg-prefix-map "c" 'hg-undo)
136 (define-key hg-prefix-map "g" 'hg-annotate) 142 (define-key hg-prefix-map "g" 'hg-annotate)
137 (define-key hg-prefix-map "l" 'hg-log) 143 (define-key hg-prefix-map "l" 'hg-log)
138 (define-key hg-prefix-map "n" 'hg-commit-file) 144 (define-key hg-prefix-map "n" 'hg-commit-file)
139 ;; (define-key hg-prefix-map "r" 'hg-update) 145 ;; (define-key hg-prefix-map "r" 'hg-update)
140 (define-key hg-prefix-map "u" 'hg-revert-file) 146 (define-key hg-prefix-map "u" 'hg-revert-buffer)
141 (define-key hg-prefix-map "~" 'hg-version-other-window) 147 (define-key hg-prefix-map "~" 'hg-version-other-window)
142 148
143 (defvar hg-mode-map (make-sparse-keymap)) 149 (defvar hg-mode-map (make-sparse-keymap))
144 (define-key hg-mode-map "\C-xv" 'hg-prefix-map) 150 (define-key hg-mode-map "\C-xv" 'hg-prefix-map)
145 151
187 'hg-buffer-mouse-clicked) 193 'hg-buffer-mouse-clicked)
188 194
189 195
190 ;;; Convenience functions. 196 ;;; Convenience functions.
191 197
192 (defun hg-binary () 198 (defsubst hg-binary ()
193 (if hg-binary 199 (if hg-binary
194 hg-binary 200 hg-binary
195 (error "No `hg' executable found!"))) 201 (error "No `hg' executable found!")))
196 202
197 (defun hg-replace-in-string (str regexp newtext &optional literal) 203 (defsubst hg-replace-in-string (str regexp newtext &optional literal)
198 "Replace all matches in STR for REGEXP with NEWTEXT string. 204 "Replace all matches in STR for REGEXP with NEWTEXT string.
199 Return the new string. Optional LITERAL non-nil means do a literal 205 Return the new string. Optional LITERAL non-nil means do a literal
200 replacement. 206 replacement.
201 207
202 This function bridges yet another pointless impedance gap between 208 This function bridges yet another pointless impedance gap between
203 XEmacs and GNU Emacs." 209 XEmacs and GNU Emacs."
204 (if (fboundp 'replace-in-string) 210 (if (fboundp 'replace-in-string)
205 (replace-in-string str regexp newtext literal) 211 (replace-in-string str regexp newtext literal)
206 (replace-regexp-in-string regexp newtext str nil literal))) 212 (replace-regexp-in-string regexp newtext str nil literal)))
207 213
208 (defun hg-chomp (str) 214 (defsubst hg-chomp (str)
209 "Strip trailing newlines from a string." 215 "Strip trailing newlines from a string."
210 (hg-replace-in-string str "[\r\n]+$" "")) 216 (hg-replace-in-string str "[\r\n]+$" ""))
211 217
212 (defun hg-run-command (command &rest args) 218 (defun hg-run-command (command &rest args)
213 "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT). 219 "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT).
266 272
267 (unless (fboundp 'view-minor-mode) 273 (unless (fboundp 'view-minor-mode)
268 (defun view-minor-mode (prev-buffer exit-func) 274 (defun view-minor-mode (prev-buffer exit-func)
269 (view-mode))) 275 (view-mode)))
270 276
271 (defun hg-abbrev-file-name (file) 277 (defsubst hg-abbrev-file-name (file)
278 "Portable wrapper around abbreviate-file-name."
272 (if hg-running-xemacs 279 (if hg-running-xemacs
273 (abbreviate-file-name file t) 280 (abbreviate-file-name file t)
274 (abbreviate-file-name file))) 281 (abbreviate-file-name file)))
275 282
276 (defun hg-read-file-name (&optional prompt default) 283 (defun hg-read-file-name (&optional prompt default)
339 (output (cdr s))) 346 (output (cdr s)))
340 (if (= exit 0) 347 (if (= exit 0)
341 (let ((state (assoc (substring output 0 (min (length output) 2)) 348 (let ((state (assoc (substring output 0 (min (length output) 2))
342 '(("M " . modified) 349 '(("M " . modified)
343 ("A " . added) 350 ("A " . added)
344 ("R " . removed))))) 351 ("R " . removed)
352 ("? " . nil)))))
345 (if state 353 (if state
346 (cdr state) 354 (cdr state)
347 'normal))))) 355 'normal)))))
348 356
349 (defun hg-tip () 357 (defun hg-tip ()
379 (pop-to-buffer view-buf-name) 387 (pop-to-buffer view-buf-name)
380 (hg-view-mode ,prev-buf ,@v-m-rest)))))) 388 (hg-view-mode ,prev-buf ,@v-m-rest))))))
381 389
382 (put 'hg-view-output 'lisp-indent-function 1) 390 (put 'hg-view-output 'lisp-indent-function 1)
383 391
392 ;;; Context save and restore across revert.
393
394 (defun hg-position-context (pos)
395 "Return information to help find the given position again."
396 (let* ((end (min (point-max) (+ pos 98))))
397 (list pos
398 (buffer-substring (max (point-min) (- pos 2)) end)
399 (- end pos))))
400
401 (defun hg-buffer-context ()
402 "Return information to help restore a user's editing context.
403 This is useful across reverts and merges, where a context is likely
404 to have moved a little, but not really changed."
405 (let ((point-context (hg-position-context (point)))
406 (mark-context (let ((mark (mark-marker)))
407 (and mark (hg-position-context mark)))))
408 (list point-context mark-context)))
409
410 (defun hg-find-context (ctx)
411 "Attempt to find a context in the given buffer.
412 Always returns a valid, hopefully sane, position."
413 (let ((pos (nth 0 ctx))
414 (str (nth 1 ctx))
415 (fixup (nth 2 ctx)))
416 (save-excursion
417 (goto-char (max (point-min) (- pos 15000)))
418 (if (and (not (equal str ""))
419 (search-forward str nil t))
420 (- (point) fixup)
421 (max pos (point-min))))))
422
423 (defun hg-restore-context (ctx)
424 "Attempt to restore the user's editing context."
425 (let ((point-context (nth 0 ctx))
426 (mark-context (nth 1 ctx)))
427 (goto-char (hg-find-context point-context))
428 (when mark-context
429 (set-mark (hg-find-context mark-context)))))
430
431
384 ;;; Hooks. 432 ;;; Hooks.
385 433
386 (defun hg-mode-line () 434 (defun hg-mode-line (&optional force)
387 (when (hg-root) 435 "Update the modeline with the current status of a file.
436 An update occurs if optional argument FORCE is non-nil,
437 hg-update-modeline is non-nil, or we have not yet checked the state of
438 the file."
439 (when (and (hg-root) (or force hg-update-modeline (not hg-mode)))
388 (let ((status (hg-file-status buffer-file-name))) 440 (let ((status (hg-file-status buffer-file-name)))
389 (setq hg-status status 441 (setq hg-status status
390 hg-mode (and status (concat " Hg:" 442 hg-mode (and status (concat " Hg:"
391 (car (hg-tip)) 443 (car (hg-tip))
392 (cdr (assq status 444 (cdr (assq status
436 -------- --- ----------- ------------ 488 -------- --- ----------- ------------
437 Help overview (what you are reading) G C-c h h hg-help-overview 489 Help overview (what you are reading) G C-c h h hg-help-overview
438 490
439 Tell Mercurial to manage a file G C-c h a hg-add 491 Tell Mercurial to manage a file G C-c h a hg-add
440 Commit changes to current file only L C-x v n hg-commit 492 Commit changes to current file only L C-x v n hg-commit
441 Undo changes to file since commit L C-x v u hg-revert-file 493 Undo changes to file since commit L C-x v u hg-revert-buffer
442 494
443 Diff file vs last checkin L C-x v = hg-diff 495 Diff file vs last checkin L C-x v = hg-diff
444 496
445 View file change history L C-x v l hg-log 497 View file change history L C-x v l hg-log
446 View annotated file L C-x v a hg-annotate 498 View annotated file L C-x v a hg-annotate
486 (defun hg-diff (path &optional rev1 rev2) 538 (defun hg-diff (path &optional rev1 rev2)
487 (interactive (list (hg-read-file-name " to diff") 539 (interactive (list (hg-read-file-name " to diff")
488 (hg-read-rev " to start with") 540 (hg-read-rev " to start with")
489 (let ((rev2 (hg-read-rev " to end with" 'working-dir))) 541 (let ((rev2 (hg-read-rev " to end with" 'working-dir)))
490 (and (not (eq rev2 'working-dir)) rev2)))) 542 (and (not (eq rev2 'working-dir)) rev2))))
491 (let ((a-path (hg-abbrev-file-name path))) 543 (unless rev1
544 (setq rev1 "-1"))
545 (let ((a-path (hg-abbrev-file-name path))
546 diff)
492 (hg-view-output ((if (equal rev1 rev2) 547 (hg-view-output ((if (equal rev1 rev2)
493 (format "Mercurial: Rev %s of %s" rev1 a-path) 548 (format "Mercurial: Rev %s of %s" rev1 a-path)
494 (format "Mercurial: Rev %s to %s of %s" 549 (format "Mercurial: Rev %s to %s of %s"
495 rev1 (or rev2 "Current") a-path))) 550 rev1 (or rev2 "Current") a-path)))
496 (if rev2 551 (if rev2
497 (call-process (hg-binary) nil t nil "diff" "-r" rev1 "-r" rev2 path) 552 (call-process (hg-binary) nil t nil "diff" "-r" rev1 "-r" rev2 path)
498 (call-process (hg-binary) nil t nil "diff" "-r" rev1 path)) 553 (call-process (hg-binary) nil t nil "diff" "-r" rev1 path))
499 (diff-mode) 554 (diff-mode)
500 (font-lock-fontify-buffer)))) 555 (setq diff (not (= (point-min) (point-max))))
556 (font-lock-fontify-buffer))
557 diff))
501 558
502 (defun hg-forget (path) 559 (defun hg-forget (path)
503 (interactive (list (hg-read-file-name " to forget"))) 560 (interactive (list (hg-read-file-name " to forget")))
504 (let ((buf (current-buffer)) 561 (let ((buf (current-buffer))
505 (update (equal buffer-file-name path))) 562 (update (equal buffer-file-name path)))
519 576
520 (defun hg-log (path &optional rev1 rev2) 577 (defun hg-log (path &optional rev1 rev2)
521 (interactive (list (hg-read-file-name " to log") 578 (interactive (list (hg-read-file-name " to log")
522 (hg-read-rev " to start with" "-1") 579 (hg-read-rev " to start with" "-1")
523 (hg-read-rev " to end with" (format "-%d" hg-log-limit)))) 580 (hg-read-rev " to end with" (format "-%d" hg-log-limit))))
524 (message "log %s %s" rev1 rev2)
525 (sit-for 1)
526 (let ((a-path (hg-abbrev-file-name path))) 581 (let ((a-path (hg-abbrev-file-name path)))
527 (hg-view-output ((if (equal rev1 rev2) 582 (hg-view-output ((if (equal rev1 rev2)
528 (format "Mercurial: Rev %s of %s" rev1 a-path) 583 (format "Mercurial: Rev %s of %s" rev1 a-path)
529 (format "Mercurial: Rev %s to %s of %s" 584 (format "Mercurial: Rev %s to %s of %s"
530 rev1 (or rev2 "Current") a-path))) 585 rev1 (or rev2 "Current") a-path)))
542 597
543 (defun hg-push () 598 (defun hg-push ()
544 (interactive) 599 (interactive)
545 (error "not implemented")) 600 (error "not implemented"))
546 601
547 (defun hg-revert () 602 (defun hg-revert-buffer-internal ()
548 (interactive) 603 (let ((ctx (hg-buffer-context)))
549 (error "not implemented")) 604 (message "Reverting %s..." buffer-file-name)
550 605 (hg-run0 "revert" buffer-file-name)
551 (defun hg-revert-file () 606 (revert-buffer t t t)
552 (interactive) 607 (hg-restore-context ctx)
553 (error "not implemented")) 608 (hg-mode-line)
609 (message "Reverting %s...done" buffer-file-name)))
610
611 (defun hg-revert-buffer ()
612 (interactive)
613 (let ((vc-suppress-confirm nil)
614 (obuf (current-buffer))
615 diff)
616 (vc-buffer-sync)
617 (unwind-protect
618 (setq diff (hg-diff buffer-file-name))
619 (when diff
620 (unless (yes-or-no-p "Discard changes? ")
621 (error "Revert cancelled")))
622 (when diff
623 (let ((buf (current-buffer)))
624 (delete-window (selected-window))
625 (kill-buffer buf))))
626 (set-buffer obuf)
627 (when diff
628 (hg-revert-buffer-internal))))
554 629
555 (defun hg-root (&optional path) 630 (defun hg-root (&optional path)
556 (interactive (list (hg-read-file-name))) 631 (interactive (list (hg-read-file-name)))
557 (let ((root (do ((prev nil dir) 632 (let ((root (do ((prev nil dir)
558 (dir (file-name-directory (or path (buffer-file-name))) 633 (dir (file-name-directory (or path (buffer-file-name)))
585 660
586 (provide 'mercurial) 661 (provide 'mercurial)
587 662
588 663
589 ;;; Local Variables: 664 ;;; Local Variables:
590 ;;; mode: emacs-lisp
591 ;;; prompt-to-byte-compile: nil 665 ;;; prompt-to-byte-compile: nil
592 ;;; end: 666 ;;; end: