stgit.el: Make sure "M" retains the order of the patches
[stgit] / contrib / stgit.el
index ec3c1d0..b3be770 100644 (file)
@@ -677,13 +677,13 @@ at point."
       (smerge-mode 1))))
 
 (defun stgit-expand (&optional patches collapse)
-  "Show the contents selected patches, or the patch at point.
+  "Show the contents of marked patches, or the patch at point.
 
 See also `stgit-collapse'.
 
 Non-interactively, operate on PATCHES, and collapse instead of
 expand if COLLAPSE is not nil."
-  (interactive (list (stgit-patches-marked-or-at-point)))
+  (interactive (list (stgit-patches-marked-or-at-point t)))
   (stgit-assert-mode)
   (let ((patches-diff (funcall (if collapse #'intersection #'set-difference)
                                patches stgit-expanded-patches)))
@@ -697,10 +697,10 @@ expand if COLLAPSE is not nil."
   (move-to-column (stgit-goal-column)))
 
 (defun stgit-collapse (&optional patches)
-  "Hide the contents selected patches, or the patch at point.
+  "Hide the contents of marked patches, or the patch at point.
 
 See also `stgit-expand'."
-  (interactive (list (stgit-patches-marked-or-at-point)))
+  (interactive (list (stgit-patches-marked-or-at-point t)))
   (stgit-assert-mode)
   (stgit-expand patches t))
 
@@ -906,21 +906,22 @@ file for (applied) copies and renames."
         ["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)]
-        ["Delete patch" stgit-delete :active (stgit-patch-name-at-point nil t)]
+        ["Delete patches" stgit-delete
+         :active (stgit-patches-marked-or-at-point nil t)]
         "-"
         ["Move patches" stgit-move-patches
          :active stgit-marked-patches
-         :help "Move selected patch(es) to point"]
+         :help "Move marked patch(es) to point"]
         ["Squash patches" stgit-squash
          :active (> (length stgit-marked-patches) 1)
-         :help "Merge selected patches into one"]
+         :help "Merge marked patches into one"]
         "-"
         ["Refresh top patch" stgit-refresh
          :active (not (and (stgit-index-empty-p) (stgit-work-tree-empty-p)))
          :help "Refresh the top patch with changes in index or work tree"]
         ["Refresh this patch" (stgit-refresh t)
          :keys "\\[universal-argument] \\[stgit-refresh]"
-         :help "Refresh the patch at point with changes in index or work tree"
+         :help "Refresh marked patch with changes in index or work tree"
          :active (and (not (and (stgit-index-empty-p)
                                 (stgit-work-tree-empty-p)))
                       (stgit-patch-name-at-point nil t))]
@@ -1010,8 +1011,8 @@ Commands for patches:
 \\[stgit-refresh]      Refresh patch with changes in index or work tree
 \\[stgit-diff] Show the patch log and diff
 
-\\[stgit-expand]       Show changes in selected patches
-\\[stgit-collapse]     Hide changes in selected patches
+\\[stgit-expand]       Show changes in marked patches
+\\[stgit-collapse]     Hide changes in marked patches
 
 \\[stgit-new]  Create a new, empty patch
 \\[stgit-new-and-refresh]      Create a new patch from index or work tree
@@ -1132,14 +1133,16 @@ index or work tree."
 (defun stgit-patched-file-at-point ()
   (get-text-property (point) 'file-data))
 
-(defun stgit-patches-marked-or-at-point ()
-  "Return the symbols of the marked patches, or the patch on the current line."
+(defun stgit-patches-marked-or-at-point (&optional cause-error only-patches)
+  "Return the symbols of the marked patches, or the patch on the current line.
+If CAUSE-ERRROR is not nil, signal an error if none found.
+If ONLY-PATCHES is not nil, do not include index or work tree."
   (if stgit-marked-patches
       stgit-marked-patches
-    (let ((patch (stgit-patch-name-at-point)))
-      (if patch
-          (list patch)
-        '()))))
+    (let ((patch (stgit-patch-name-at-point nil only-patches)))
+      (cond (patch (list patch))
+            (cause-error (error "No patches marked or at this line"))
+            (t nil)))))
 
 (defun stgit-goto-patch (patchsym &optional file)
   "Move point to the line containing patch PATCHSYM.
@@ -1753,7 +1756,7 @@ Interactively, delete the marked patches, or the patch at point.
 
 With a prefix argument, or SPILL-P, spill the patch contents to
 the work tree and index."
-  (interactive (list (stgit-patches-marked-or-at-point)
+  (interactive (list (stgit-patches-marked-or-at-point t t)
                      current-prefix-arg))
   (stgit-assert-mode)
   (unless patchsyms
@@ -1781,13 +1784,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
@@ -1826,20 +1837,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)
@@ -1930,13 +1938,10 @@ With prefix argument, refresh the marked patch or the patch under point."
   (interactive "P")
   (stgit-assert-mode)
   (let ((patchargs (if arg
-                       (let ((patches (stgit-patches-marked-or-at-point)))
-                         (cond ((null patches)
-                                (error "No patch to update"))
-                               ((> (length patches) 1)
-                                (error "Too many patches selected"))
-                               (t
-                                (cons "-p" patches))))
+                       (let ((patches (stgit-patches-marked-or-at-point nil t)))
+                         (when (> (length patches) 1)
+                           (error "Too many patches marked"))
+                         (cons "-p" patches))
                      nil)))
     (unless (stgit-index-empty-p)
       (setq patchargs (cons "--index" patchargs)))