Mercurial > hg > pyhgsh
comparison contrib/mercurial.el @ 1029:b5f0ccad8917
Emacs: implement hg-incoming, hg-outgoing and hg-push.
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Tue, 23 Aug 2005 21:53:13 -0700 |
parents | cb31576ed3e4 |
children | 7e909ceeb36a |
comparison
equal
deleted
inserted
replaced
1028:25e7ea0f2cff | 1029:b5f0ccad8917 |
---|---|
90 "Hook run before a commit is performed. | 90 "Hook run before a commit is performed. |
91 If you want to prevent the commit from proceeding, raise an error." | 91 If you want to prevent the commit from proceeding, raise an error." |
92 :type 'sexp | 92 :type 'sexp |
93 :group 'mercurial) | 93 :group 'mercurial) |
94 | 94 |
95 (defcustom hg-log-mode-hook nil | |
96 "Hook run after a buffer is filled with log information." | |
97 :type 'sexp | |
98 :group 'mercurial) | |
99 | |
95 (defcustom hg-global-prefix "\C-ch" | 100 (defcustom hg-global-prefix "\C-ch" |
96 "The global prefix for Mercurial keymap bindings." | 101 "The global prefix for Mercurial keymap bindings." |
97 :type 'sexp | 102 :type 'sexp |
98 :group 'mercurial) | 103 :group 'mercurial) |
99 | 104 |
123 "Whether to update the modeline with the status of a file after every save. | 128 "Whether to update the modeline with the status of a file after every save. |
124 Set this to nil on platforms with poor process management, such as Windows." | 129 Set this to nil on platforms with poor process management, such as Windows." |
125 :type 'boolean | 130 :type 'boolean |
126 :group 'mercurial) | 131 :group 'mercurial) |
127 | 132 |
133 (defcustom hg-incoming-repository "default" | |
134 "The repository from which changes are pulled from by default. | |
135 This should be a symbolic repository name, since it is used for all | |
136 repository-related commands." | |
137 :type 'string | |
138 :group 'mercurial) | |
139 | |
140 (defcustom hg-outgoing-repository "default-push" | |
141 "The repository to which changes are pushed to by default. | |
142 This should be a symbolic repository name, since it is used for all | |
143 repository-related commands." | |
144 :type 'string | |
145 :group 'mercurial) | |
146 | |
128 | 147 |
129 ;;; Other variables. | 148 ;;; Other variables. |
130 | 149 |
131 (defconst hg-running-xemacs (string-match "XEmacs" emacs-version) | 150 (defconst hg-running-xemacs (string-match "XEmacs" emacs-version) |
132 "Is mercurial.el running under XEmacs?") | 151 "Is mercurial.el running under XEmacs?") |
150 | 169 |
151 (defvar hg-output-buffer-name "*Hg*" | 170 (defvar hg-output-buffer-name "*Hg*" |
152 "The name to use for Mercurial output buffers.") | 171 "The name to use for Mercurial output buffers.") |
153 | 172 |
154 (defvar hg-file-history nil) | 173 (defvar hg-file-history nil) |
174 (defvar hg-repo-history nil) | |
155 (defvar hg-rev-history nil) | 175 (defvar hg-rev-history nil) |
156 | 176 |
157 | 177 |
158 ;;; Random constants. | 178 ;;; Random constants. |
159 | 179 |
232 ;;; Commit mode keymaps. | 252 ;;; Commit mode keymaps. |
233 | 253 |
234 (defvar hg-commit-mode-map (make-sparse-keymap)) | 254 (defvar hg-commit-mode-map (make-sparse-keymap)) |
235 (define-key hg-commit-mode-map "\C-c\C-c" 'hg-commit-finish) | 255 (define-key hg-commit-mode-map "\C-c\C-c" 'hg-commit-finish) |
236 (define-key hg-commit-mode-map "\C-c\C-k" 'hg-commit-kill) | 256 (define-key hg-commit-mode-map "\C-c\C-k" 'hg-commit-kill) |
257 (define-key hg-commit-mode-map "\C-xv=" 'hg-diff-repo) | |
237 | 258 |
238 (defvar hg-commit-mode-file-map (make-sparse-keymap)) | 259 (defvar hg-commit-mode-file-map (make-sparse-keymap)) |
239 (define-key hg-commit-mode-file-map | 260 (define-key hg-commit-mode-file-map |
240 (if hg-running-xemacs [button2] [mouse-2]) | 261 (if hg-running-xemacs [button2] [mouse-2]) |
241 'hg-commit-mouse-clicked) | 262 'hg-commit-mouse-clicked) |
368 nil nil | 389 nil nil |
369 (and path (file-name-nondirectory path)) | 390 (and path (file-name-nondirectory path)) |
370 'hg-file-history)) | 391 'hg-file-history)) |
371 path)))) | 392 path)))) |
372 | 393 |
394 (defun hg-read-config () | |
395 "Return an alist of (key . value) pairs of Mercurial config data. | |
396 Each key is of the form (section . name)." | |
397 (let (items) | |
398 (dolist (line (split-string (hg-chomp (hg-run0 "debugconfig")) "\n") items) | |
399 (string-match "^\\([^=]*\\)=\\(.*\\)" line) | |
400 (let* ((left (substring line (match-beginning 1) (match-end 1))) | |
401 (right (substring line (match-beginning 2) (match-end 2))) | |
402 (key (split-string left "\\.")) | |
403 (value (hg-replace-in-string right "\\\\n" "\n" t))) | |
404 (setq items (cons (cons (cons (car key) (cadr key)) value) items)))))) | |
405 | |
406 (defun hg-config-section (section config) | |
407 "Return an alist of (name . value) pairs for SECTION of CONFIG." | |
408 (let (items) | |
409 (dolist (item config items) | |
410 (when (equal (caar item) section) | |
411 (setq items (cons (cons (cdar item) (cdr item)) items)))))) | |
412 | |
413 (defun hg-string-starts-with (sub str) | |
414 "Indicate whether string STR starts with the substring or character SUB." | |
415 (if (not (stringp sub)) | |
416 (and (> (length str) 0) (equal (elt str 0) sub)) | |
417 (let ((sub-len (length sub))) | |
418 (and (<= sub-len (length str)) | |
419 (string= sub (substring str 0 sub-len)))))) | |
420 | |
421 (defun hg-complete-repo (string predicate all) | |
422 "Attempt to complete a repository name. | |
423 We complete on either symbolic names from Mercurial's config or real | |
424 directory names from the file system. We do not penalise URLs." | |
425 (or (if all | |
426 (all-completions string hg-repo-completion-table predicate) | |
427 (try-completion string hg-repo-completion-table predicate)) | |
428 (let* ((str (expand-file-name string)) | |
429 (dir (file-name-directory str)) | |
430 (file (file-name-nondirectory str))) | |
431 (if all | |
432 (let (completions) | |
433 (dolist (name (delete "./" (file-name-all-completions file dir)) | |
434 completions) | |
435 (let ((path (concat dir name))) | |
436 (when (file-directory-p path) | |
437 (setq completions (cons name completions)))))) | |
438 (let ((comp (file-name-completion file dir))) | |
439 (if comp | |
440 (hg-abbrev-file-name (concat dir comp)))))))) | |
441 | |
442 (defun hg-read-repo-name (&optional prompt initial-contents default) | |
443 "Read the location of a repository." | |
444 (save-excursion | |
445 (while hg-prev-buffer | |
446 (set-buffer hg-prev-buffer)) | |
447 (let (hg-repo-completion-table) | |
448 (if current-prefix-arg | |
449 (progn | |
450 (dolist (path (hg-config-section "paths" (hg-read-config))) | |
451 (setq hg-repo-completion-table | |
452 (cons (cons (car path) t) hg-repo-completion-table)) | |
453 (unless (hg-string-starts-with directory-sep-char (cdr path)) | |
454 (setq hg-repo-completion-table | |
455 (cons (cons (cdr path) t) hg-repo-completion-table)))) | |
456 (completing-read (format "Repository%s: " (or prompt "")) | |
457 'hg-complete-repo | |
458 nil | |
459 nil | |
460 initial-contents | |
461 'hg-repo-history | |
462 default)) | |
463 default)))) | |
464 | |
373 (defun hg-read-rev (&optional prompt default) | 465 (defun hg-read-rev (&optional prompt default) |
374 "Read a revision or tag, offering completions." | 466 "Read a revision or tag, offering completions." |
375 (save-excursion | 467 (save-excursion |
376 (while hg-prev-buffer | 468 (while hg-prev-buffer |
377 (set-buffer hg-prev-buffer)) | 469 (set-buffer hg-prev-buffer)) |
378 (let ((rev (or default "tip"))) | 470 (let ((rev (or default "tip"))) |
379 (if (or (not rev) current-prefix-arg) | 471 (if current-prefix-arg |
380 (let ((revs (split-string (hg-chomp | 472 (let ((revs (split-string (hg-chomp |
381 (hg-run0 "-q" "log" "-r" | 473 (hg-run0 "-q" "log" "-r" |
382 (format "-%d" | 474 (format "-%d" |
383 hg-rev-completion-limit) | 475 hg-rev-completion-limit) |
384 "-r" "tip")) | 476 "-r" "tip")) |
835 (apply 'call-process (hg-binary) nil t nil (list "forget" path))) | 927 (apply 'call-process (hg-binary) nil t nil (list "forget" path))) |
836 (when update | 928 (when update |
837 (with-current-buffer buf | 929 (with-current-buffer buf |
838 (hg-mode-line))))) | 930 (hg-mode-line))))) |
839 | 931 |
840 (defun hg-incoming () | 932 (defun hg-incoming (&optional repo) |
933 "Display changesets present in REPO that are not present locally." | |
934 (interactive (list (hg-read-repo-name " where changes would come from"))) | |
935 (hg-view-output ((format "Mercurial: Incoming from %s to %s" | |
936 (hg-abbrev-file-name (hg-root)) | |
937 (hg-abbrev-file-name | |
938 (or repo hg-incoming-repository)))) | |
939 (call-process (hg-binary) nil t nil "incoming" | |
940 (or repo hg-incoming-repository)) | |
941 (hg-log-mode))) | |
942 | |
943 (defun hg-init () | |
841 (interactive) | 944 (interactive) |
842 (error "not implemented")) | 945 (error "not implemented")) |
843 | 946 |
844 (defun hg-init () | 947 (defun hg-log-mode () |
845 (interactive) | 948 "Mode for viewing a Mercurial change log." |
846 (error "not implemented")) | 949 (goto-char (point-min)) |
950 (when (looking-at "^searching for changes") | |
951 (kill-entire-line)) | |
952 (run-hooks 'hg-log-mode-hook)) | |
847 | 953 |
848 (defun hg-log (path &optional rev1 rev2) | 954 (defun hg-log (path &optional rev1 rev2) |
849 "Display the revision history of PATH, between REV1 and REV2. | 955 "Display the revision history of PATH, between REV1 and REV2. |
850 REV1 defaults to hg-log-limit changes from the tip revision, while | 956 REV1 defaults to hg-log-limit changes from the tip revision, while |
851 REV2 defaults to the tip. | 957 REV2 defaults to the tip. |
861 (format "Mercurial: Log from rev %s to %s of %s" | 967 (format "Mercurial: Log from rev %s to %s of %s" |
862 r1 r2 a-path))) | 968 r1 r2 a-path))) |
863 (if (> (length path) (length (hg-root path))) | 969 (if (> (length path) (length (hg-root path))) |
864 (call-process (hg-binary) nil t nil "log" "-r" r1 "-r" r2 path) | 970 (call-process (hg-binary) nil t nil "log" "-r" r1 "-r" r2 path) |
865 (call-process (hg-binary) nil t nil "log" "-r" r1 "-r" r2)) | 971 (call-process (hg-binary) nil t nil "log" "-r" r1 "-r" r2)) |
866 (font-lock-fontify-buffer)))) | 972 (hg-log-mode)))) |
867 | 973 |
868 (defun hg-log-repo (path &optional rev1 rev2) | 974 (defun hg-log-repo (path &optional rev1 rev2) |
869 "Display the revision history of the repository containing PATH. | 975 "Display the revision history of the repository containing PATH. |
870 History is displayed between REV1, which defaults to the tip, and | 976 History is displayed between REV1, which defaults to the tip, and |
871 REV2, which defaults to the initial revision. | 977 REV2, which defaults to the initial revision. |
873 (interactive (list (hg-read-file-name " to log") | 979 (interactive (list (hg-read-file-name " to log") |
874 (hg-read-rev " to start with" "tip") | 980 (hg-read-rev " to start with" "tip") |
875 (hg-read-rev " to end with" (format "-%d" hg-log-limit)))) | 981 (hg-read-rev " to end with" (format "-%d" hg-log-limit)))) |
876 (hg-log (hg-root path) rev1 rev2)) | 982 (hg-log (hg-root path) rev1 rev2)) |
877 | 983 |
878 (defun hg-outgoing () | 984 (defun hg-outgoing (&optional repo) |
985 "Display changesets present locally that are not present in REPO." | |
986 (interactive (list (hg-read-repo-name " where changes would go to" nil | |
987 hg-outgoing-repository))) | |
988 (hg-view-output ((format "Mercurial: Outgoing from %s to %s" | |
989 (hg-abbrev-file-name (hg-root)) | |
990 (hg-abbrev-file-name | |
991 (or repo hg-outgoing-repository)))) | |
992 (call-process (hg-binary) nil t nil "outgoing" | |
993 (or repo hg-outgoing-repository)) | |
994 (hg-log-mode))) | |
995 | |
996 (defun hg-pull () | |
879 (interactive) | 997 (interactive) |
880 (error "not implemented")) | 998 (error "not implemented")) |
881 | 999 |
882 (defun hg-pull () | 1000 (defun hg-push (&optional repo) |
883 (interactive) | 1001 "Push changes to repository REPO." |
884 (error "not implemented")) | 1002 (interactive (list (hg-read-repo-name " to push to"))) |
885 | 1003 (hg-view-output ((format "Mercurial: Push from %s to %s" |
886 (defun hg-push () | 1004 (hg-abbrev-file-name (hg-root)) |
887 (interactive) | 1005 (hg-abbrev-file-name |
888 (error "not implemented")) | 1006 (or repo hg-outgoing-repository)))) |
1007 (call-process (hg-binary) nil t nil "push" | |
1008 (or repo hg-outgoing-repository)))) | |
889 | 1009 |
890 (defun hg-revert-buffer-internal () | 1010 (defun hg-revert-buffer-internal () |
891 (let ((ctx (hg-buffer-context))) | 1011 (let ((ctx (hg-buffer-context))) |
892 (message "Reverting %s..." buffer-file-name) | 1012 (message "Reverting %s..." buffer-file-name) |
893 (hg-run0 "revert" buffer-file-name) | 1013 (hg-run0 "revert" buffer-file-name) |
933 (return dir))))) | 1053 (return dir))))) |
934 (when (interactive-p) | 1054 (when (interactive-p) |
935 (if root | 1055 (if root |
936 (message "The root of this repository is `%s'." root) | 1056 (message "The root of this repository is `%s'." root) |
937 (message "The path `%s' is not in a Mercurial repository." | 1057 (message "The path `%s' is not in a Mercurial repository." |
938 (abbreviate-file-name path t)))) | 1058 (hg-abbrev-file-name path)))) |
939 root) | 1059 root) |
940 hg-root)) | 1060 hg-root)) |
941 | 1061 |
942 (defun hg-status (path) | 1062 (defun hg-status (path) |
943 "Print revision control status of a file or directory. | 1063 "Print revision control status of a file or directory. |