stgit.el: Allow "P" to operate on all marked files
[stgit] / contrib / stgit.el
index b7c4b7f..4b3f5f8 100644 (file)
@@ -904,8 +904,9 @@ file for (applied) copies and renames."
          :active (stgit-patch-name-at-point nil t)]
         ["Rename patch" stgit-rename :active (stgit-patch-name-at-point nil t)]
         ["Push/pop patch" stgit-push-or-pop
-         :label (if (stgit-applied-at-point-p) "Pop patch" "Push patch")
-         :active (stgit-patch-name-at-point nil t)]
+         :label (if (subsetp (stgit-patches-marked-or-at-point nil t)
+                             (stgit-applied-patchsyms t))
+                    "Pop patches" "Push patches")]
         ["Delete patches" stgit-delete
          :active (stgit-patches-marked-or-at-point nil t)]
         "-"
@@ -1463,20 +1464,38 @@ With numeric prefix argument, pop that many patches."
   (stgit-reload)
   (stgit-refresh-git-status))
 
-(defun stgit-applied-at-point-p ()
-  "Return non-nil if the patch at point is applied."
-  (let ((patch (stgit-patch-at-point t)))
-    (not (eq (stgit-patch-status patch) 'unapplied))))
+(defun stgit-applied-patches (&optional only-patches)
+  "Return a list of the applied patches.
+
+If ONLY-PATCHES is not nil, exclude index and work tree."
+  (let ((states (if only-patches
+                    '(applied top)
+                  '(applied top index work)))
+        result)
+    (ewoc-map (lambda (patch) (when (memq (stgit-patch-status patch) states)
+                                (setq result (cons patch result))))
+              stgit-ewoc)
+    result))
+
+(defun stgit-applied-patchsyms (&optional only-patches)
+  "Return a list of the symbols of the applied patches.
+
+If ONLY-PATCHES is not nil, exclude index and work tree."
+  (mapcar #'stgit-patch-name (stgit-applied-patches only-patches)))
 
 (defun stgit-push-or-pop ()
-  "Push or pop the patch on the current line."
+  "Push or pop the marked patches."
   (interactive)
   (stgit-assert-mode)
-  (let ((patchsym (stgit-patch-name-at-point t t))
-        (applied (stgit-applied-at-point-p)))
+  (let* ((patchsyms (stgit-patches-marked-or-at-point t t))
+         (applied-syms (stgit-applied-patchsyms t))
+         (unapplied (set-difference patchsyms applied-syms)))
     (stgit-capture-output nil
-      (stgit-run (if applied "pop" "push") patchsym))
-    (stgit-reload)))
+      (apply 'stgit-run
+             (if unapplied "push" "pop")
+             "--"
+             (stgit-sort-patches (if unapplied unapplied patchsyms)))))
+  (stgit-reload))
 
 (defun stgit-goto ()
   "Go to the patch on the current line."
@@ -1784,13 +1803,21 @@ the work tree and index."
   "Return the patchsym indicating a target patch for
 `stgit-move-patches'.
 
-This is either the patch at point, or one of :top and :bottom, if
-the point is after or before the applied patches."
-
-  (let ((patchsym (stgit-patch-name-at-point nil t)))
-    (cond (patchsym patchsym)
-         ((save-excursion (re-search-backward "^>" nil t)) :top)
-         (t :bottom))))
+This is either the first unmarked patch at or after point, or one
+of :top and :bottom if the point is after or before the applied
+patches."
+
+  (save-excursion
+    (let (result)
+      (while (not result)
+        (let ((patchsym (stgit-patch-name-at-point)))
+          (cond ((memq patchsym '(:work :index)) (setq result :top))
+                (patchsym (if (memq patchsym stgit-marked-patches)
+                              (stgit-next-patch)
+                            (setq result patchsym)))
+                ((re-search-backward "^>" nil t) (setq result :top))
+                (t (setq result :bottom)))))
+      result)))
 
 (defun stgit-sort-patches (patchsyms)
   "Returns the list of patches in PATCHSYMS sorted according to
@@ -1829,20 +1856,17 @@ Interactively, move the marked patches to where the point is."
   (unless target-patch
     (error "Point not at a patch"))
 
-  (if (eq target-patch :top)
-      (stgit-capture-output nil
-        (apply 'stgit-run "float" patchsyms))
-
-    ;; need to have patchsyms sorted by position in the stack
-    (let ((sorted-patchsyms (stgit-sort-patches patchsyms)))
-      (while sorted-patchsyms
-        (setq sorted-patchsyms
-              (and (stgit-capture-output nil
-                     (if (eq target-patch :bottom)
-                         (stgit-run "sink" "--" (car sorted-patchsyms))
-                       (stgit-run "sink" "--to" target-patch "--"
-                                  (car sorted-patchsyms))))
-                   (cdr sorted-patchsyms))))))
+  ;; need to have patchsyms sorted by position in the stack
+  (let ((sorted-patchsyms (stgit-sort-patches patchsyms)))
+    (stgit-capture-output nil
+      (if (eq target-patch :top)
+          (apply 'stgit-run "float" sorted-patchsyms)
+        (apply 'stgit-run
+               "sink"
+               (append (unless (eq target-patch :bottom)
+                         (list "--to" target-patch))
+                       '("--")
+                       sorted-patchsyms)))))
   (stgit-reload))
 
 (defun stgit-squash (patchsyms)