Add a boundary to parse_patches in pick.py
[stgit] / contrib / stgit.el
index 1cb4dd2..ba6df6a 100644 (file)
@@ -70,7 +70,7 @@ Argument DIR is the repository path."
     (insert "Branch: ")
     (stgit-run "branch")
     (stgit-run "series" "--description")
-    (stgit-rehighlight (point-min) (point-max))
+    (stgit-rescan)
     (if curpatch
         (stgit-goto-patch curpatch)
       (goto-line curline))))
@@ -98,23 +98,30 @@ Argument DIR is the repository path."
     (t ()))
   "The face used for unapplied patch names")
 
-(defun stgit-rehighlight (start end)
-  "Refresh fontification of region between START and END."
+(defun stgit-rescan ()
+  "Rescan the status buffer."
   (save-excursion
-    (goto-char start)
-    (while (< (point) end)
-      (cond ((looking-at "Branch: \\(.*\\)")
-             (put-text-property (match-beginning 1) (match-end 1) 'face 'bold))
-            ((looking-at "\\([>+-]\\) \\([^ ]+\\) *| \\(.*\\)")
-             (let ((state (match-string 1)))
-               (put-text-property
-                (match-beginning 2) (match-end 2)
-                'face (cond ((string= state ">") 'stgit-top-patch-face)
-                            ((string= state "+") 'stgit-applied-patch-face)
-                            ((string= state "-") 'stgit-unapplied-patch-face)))
-               (put-text-property (match-beginning 3) (match-end 3)
-                                  'face 'stgit-description-face))))
-      (forward-line 1))))
+    (let ((marked ()))
+      (goto-char (point-min))
+      (while (not (eobp))
+        (cond ((looking-at "Branch: \\(.*\\)")
+               (put-text-property (match-beginning 1) (match-end 1)
+                                  'face 'bold))
+              ((looking-at "\\([>+-]\\)\\( \\)\\([^ ]+\\) *| \\(.*\\)")
+               (let ((state (match-string 1))
+                     (patchsym (intern (match-string 3))))
+                 (put-text-property
+                  (match-beginning 3) (match-end 3) 'face
+                  (cond ((string= state ">") 'stgit-top-patch-face)
+                        ((string= state "+") 'stgit-applied-patch-face)
+                        ((string= state "-") 'stgit-unapplied-patch-face)))
+                 (put-text-property (match-beginning 4) (match-end 4)
+                                    'face 'stgit-description-face)
+                 (when (memq patchsym stgit-marked-patches)
+                   (replace-match "*" nil nil nil 2)
+                   (setq marked (cons patchsym marked))))))
+        (forward-line 1))
+      (setq stgit-marked-patches (nreverse marked)))))
 
 (defvar stgit-mode-hook nil
   "Run after `stgit-mode' is setup.")
@@ -125,6 +132,8 @@ Argument DIR is the repository path."
 (unless stgit-mode-map
   (setq stgit-mode-map (make-keymap))
   (suppress-keymap stgit-mode-map)
+  (define-key stgit-mode-map " "   'stgit-mark)
+  (define-key stgit-mode-map "\d" 'stgit-unmark)
   (define-key stgit-mode-map "?"   'stgit-help)
   (define-key stgit-mode-map "h"   'stgit-help)
   (define-key stgit-mode-map "p"   'previous-line)
@@ -132,8 +141,9 @@ Argument DIR is the repository path."
   (define-key stgit-mode-map "g"   'stgit-refresh)
   (define-key stgit-mode-map "r"   'stgit-rename)
   (define-key stgit-mode-map "e"   'stgit-edit)
+  (define-key stgit-mode-map "c"   'stgit-coalesce)
   (define-key stgit-mode-map "N"   'stgit-new)
-  (define-key stgit-mode-map "\C-r"   'stgit-repair)
+  (define-key stgit-mode-map "R"   'stgit-repair)
   (define-key stgit-mode-map "C"   'stgit-commit)
   (define-key stgit-mode-map "U"   'stgit-uncommit)
   (define-key stgit-mode-map ">"   'stgit-push-next)
@@ -153,14 +163,27 @@ Commands:
         goal-column 2)
   (use-local-map stgit-mode-map)
   (set (make-local-variable 'list-buffers-directory) default-directory)
+  (set (make-local-variable 'stgit-marked-patches) nil)
   (set-variable 'truncate-lines 't)
   (run-hooks 'stgit-mode-hook))
 
+(defun stgit-add-mark (patch)
+  (let ((patchsym (intern patch)))
+    (setq stgit-marked-patches (cons patchsym stgit-marked-patches))))
+
+(defun stgit-remove-mark (patch)
+  (let ((patchsym (intern patch)))
+    (setq stgit-marked-patches (delq patchsym stgit-marked-patches))))
+
+(defun stgit-marked-patches ()
+  "Return the names of the marked patches."
+  (mapcar 'symbol-name stgit-marked-patches))
+
 (defun stgit-patch-at-point ()
   "Return the patch name on the current line"
   (save-excursion
     (beginning-of-line)
-    (if (looking-at "[>+-] \\([^ ]*\\)")
+    (if (looking-at "[>+-][ *]\\([^ ]*\\)")
         (match-string-no-properties 1)
       nil)))
 
@@ -168,12 +191,28 @@ Commands:
   "Move point to the line containing PATCH"
   (let ((p (point)))
     (goto-char (point-min))
-    (if (re-search-forward (concat "[>+-] " (regexp-quote patch) " ") nil t)
+    (if (re-search-forward (concat "^[>+-][ *]" (regexp-quote patch) " ") nil t)
         (progn (move-to-column goal-column)
                t)
       (goto-char p)
       nil)))
 
+(defun stgit-mark ()
+  "Mark the patch under point"
+  (interactive)
+  (let ((patch (stgit-patch-at-point)))
+    (stgit-add-mark patch)
+    (stgit-refresh))
+  (next-line))
+
+(defun stgit-unmark ()
+  "Mark the patch on the previous line"
+  (interactive)
+  (forward-line -1)
+  (let ((patch (stgit-patch-at-point)))
+    (stgit-remove-mark patch)
+    (stgit-refresh)))
+
 (defun stgit-rename (name)
   "Rename the patch under point"
   (interactive (list (read-string "Patch name: " (stgit-patch-at-point))))
@@ -251,10 +290,8 @@ Commands:
 (defun stgit-edit ()
   "Edit the patch on the current line"
   (interactive)
-  (let ((patch (if (stgit-applied-at-point)
-                   (stgit-patch-at-point)
-                 (error "This patch is not applied")))
-        (edit-buf (get-buffer-create "*stgit edit*"))
+  (let ((patch (stgit-patch-at-point))
+        (edit-buf (get-buffer-create "*StGit edit*"))
         (dir default-directory))
     (log-edit 'stgit-confirm-edit t nil edit-buf)
     (set (make-local-variable 'stgit-edit-patch) patch)
@@ -274,7 +311,7 @@ Commands:
 (defun stgit-new ()
   "Create a new patch"
   (interactive)
-  (let ((edit-buf (get-buffer-create "*stgit edit*")))
+  (let ((edit-buf (get-buffer-create "*StGit edit*")))
     (log-edit 'stgit-confirm-new t nil edit-buf)))
 
 (defun stgit-confirm-new ()
@@ -310,6 +347,26 @@ Commands:
            (substring patch 0 20))
           (t patch))))
 
+(defun stgit-coalesce (patch-names)
+  "Run stg coalesce on the named patches"
+  (interactive (list (stgit-marked-patches)))
+  (let ((edit-buf (get-buffer-create "*StGit edit*"))
+        (dir default-directory))
+    (log-edit 'stgit-confirm-coalesce t nil edit-buf)
+    (set (make-local-variable 'stgit-patches) patch-names)
+    (setq default-directory dir)
+    (let ((standard-output edit-buf))
+      (apply 'stgit-run "coalesce" "--save-template=-" patch-names))))
+
+(defun stgit-confirm-coalesce ()
+  (interactive)
+  (let ((file (make-temp-file "stgit-edit-")))
+    (write-region (point-min) (point-max) file)
+    (stgit-capture-output nil
+      (apply 'stgit-run "coalesce" "-f" file stgit-patches))
+    (with-current-buffer log-edit-parent-buffer
+      (stgit-refresh))))
+
 (defun stgit-help ()
   "Display help for the StGit mode."
   (interactive)