stgit.el: Add "B" for stgit-branch
[stgit] / contrib / stgit.el
index 9c88e60..7fd3786 100644 (file)
@@ -124,7 +124,7 @@ Argument DIR is the repository path."
     (erase-buffer)
     (insert "Branch: ")
     (stgit-run-silent "branch")
-    (stgit-run-silent "series" "--description")
+    (stgit-run-silent "series" "--description" "--empty")
     (stgit-rescan)
     (if curpatch
         (stgit-goto-patch curpatch)
@@ -350,57 +350,90 @@ find copied files."
         (insert "    <no files>\n"))
       (put-text-property start (point) 'stgit-file-patchsym patchsym))))
 
+(defun stgit-collapse-patch (patchsym)
+  "Collapse the patch with name PATCHSYM after the line at point."
+  (save-excursion
+    (forward-line)
+    (let ((start (point)))
+      (while (eq (get-text-property (point) 'stgit-file-patchsym) patchsym)
+        (forward-line))
+      (delete-region start (point)))))
+
 (defun stgit-rescan ()
   "Rescan the status buffer."
   (save-excursion
-    (let ((marked ()))
+    (let ((marked ())
+         found-any)
       (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))))
+              ((looking-at "\\([0 ]\\)\\([>+-]\\)\\( \\)\\([^ ]+\\) *[|#] \\(.*\\)")
+              (setq found-any t)
+               (let ((empty (match-string 1))
+                    (state (match-string 2))
+                     (patchsym (intern (match-string 4))))
                  (put-text-property
-                  (match-beginning 3) (match-end 3) 'face
+                  (match-beginning 4) (match-end 4) '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)
+                 (put-text-property (match-beginning 5) (match-end 5)
                                     'face 'stgit-description-face)
                  (when (memq patchsym stgit-marked-patches)
-                   (replace-match "*" nil nil nil 2)
+                   (save-excursion
+                    (replace-match "*" nil nil nil 3))
                    (setq marked (cons patchsym marked)))
                  (put-text-property (match-beginning 0) (match-end 0)
                                     'stgit-patchsym patchsym)
                  (when (memq patchsym stgit-expanded-patches)
                    (stgit-expand-patch patchsym))
+                (when (equal "0" empty)
+                  (save-excursion
+                    (goto-char (match-beginning 5))
+                    (insert "(empty) ")))
+                (delete-char 1)
                  ))
               ((or (looking-at "stg series: Branch \".*\" not initialised")
                    (looking-at "stg series: .*: branch not initialized"))
+              (setq found-any t)
                (forward-line 1)
                (insert "Run M-x stgit-init to initialise")))
         (forward-line 1))
-      (setq stgit-marked-patches (nreverse marked)))))
+      (setq stgit-marked-patches (nreverse marked))
+      (unless found-any
+       (insert "\n  "
+               (propertize "no patches in series"
+                           'face 'stgit-description-face))))))
+
+(defun stgit-select-file ()
+  (let ((patched-file (stgit-patched-file-at-point)))
+    (unless patched-file
+      (error "No patch or file on the current line"))
+    (let ((filename (expand-file-name (cdr patched-file))))
+      (unless (file-exists-p filename)
+        (error "File does not exist"))
+      (find-file filename))))
+
+(defun stgit-toggle-patch-file-list (curpath)
+  (let ((inhibit-read-only t))
+    (if (memq curpatch stgit-expanded-patches)
+        (save-excursion
+          (setq stgit-expanded-patches (delq curpatch stgit-expanded-patches))
+          (stgit-collapse-patch curpatch))
+      (progn
+        (setq stgit-expanded-patches (cons curpatch stgit-expanded-patches))
+        (stgit-expand-patch curpatch)))))
 
 (defun stgit-select ()
   "Expand or collapse the current entry"
   (interactive)
   (let ((curpatch (stgit-patch-at-point)))
-    (if (not curpatch)
-        (let ((patched-file (stgit-patched-file-at-point)))
-          (unless patched-file
-            (error "No patch or file on the current line"))
-          (let ((filename (expand-file-name (cdr patched-file))))
-            (unless (file-exists-p filename)
-              (error "File does not exist"))
-            (find-file filename)))
-      (setq stgit-expanded-patches
-            (if (memq curpatch stgit-expanded-patches)
-                (delq curpatch stgit-expanded-patches)
-              (cons curpatch stgit-expanded-patches)))
-      (stgit-reload))))
+    (if curpatch
+        (stgit-toggle-patch-file-list curpatch)
+      (stgit-select-file))))
+
 
 (defun stgit-find-file-other-window ()
   "Open file at point in other window"
@@ -508,7 +541,8 @@ find copied files."
           ("D" .        stgit-delete)
           ([(control ?/)] . stgit-undo)
           ("\C-_" .     stgit-undo)
-          ("q" . stgit-quit))))
+          ("B" .        stgit-branch)
+          ("q" .        stgit-quit))))
 
 (defun stgit-mode ()
   "Major mode for interacting with StGit.
@@ -644,16 +678,36 @@ If that patch cannot be found, return nil."
     (stgit-run "repair"))
   (stgit-reload))
 
-(defun stgit-commit ()
-  "Run stg commit."
-  (interactive)
-  (stgit-capture-output nil (stgit-run "commit"))
+(defun stgit-available-branches ()
+  "Returns a list of the available stg branches"
+  (let ((output (with-output-to-string
+                  (stgit-run "branch" "--list")))
+        (start 0)
+        result)
+    (while (string-match "^>?\\s-+s\\s-+\\(\\S-+\\)" output start)
+      (setq result (cons (match-string 1 output) result))
+      (setq start (match-end 0)))
+    result))
+
+(defun stgit-branch (branch)
+  "Switch to branch BRANCH."
+  (interactive (list (completing-read "Switch to branch: "
+                                      (stgit-available-branches))))
+  (stgit-capture-output nil (stgit-run "branch" "--" branch))
+  (stgit-reload))
+
+(defun stgit-commit (count)
+  "Run stg commit on COUNT commits.
+Interactively, the prefix argument is used as COUNT."
+  (interactive "p")
+  (stgit-capture-output nil (stgit-run "commit" "-n" count))
   (stgit-reload))
 
-(defun stgit-uncommit (arg)
-  "Run stg uncommit. Numeric arg determines number of patches to uncommit."
+(defun stgit-uncommit (count)
+  "Run stg uncommit on COUNT commits.
+Interactively, the prefix argument is used as COUNT."
   (interactive "p")
-  (stgit-capture-output nil (stgit-run "uncommit" "-n" arg))
+  (stgit-capture-output nil (stgit-run "uncommit" "-n" count))
   (stgit-reload))
 
 (defun stgit-push-next (npatches)
@@ -713,20 +767,17 @@ With numeric prefix argument, pop that many patches."
             (unless patched-file
               (error "No patch or file at point"))
             (let ((id (stgit-id (car patched-file))))
-              (with-output-to-temp-buffer "*StGit diff*"
-                (if (consp (cdr patched-file))
-                    ;; two files (copy or rename)
-                    (stgit-run-git "diff" "-C" "-C" (concat id "^") id "--"
-                                   (cadr patched-file) (cddr patched-file))
-                  ;; just one file
-                  (stgit-run-git "diff" (concat id "^") id "--"
-                                 (cdr patched-file)))
-                (with-current-buffer standard-output
-                  (diff-mode)))))
-        (stgit-run "show" patchsym)
-        (with-current-buffer standard-output
-          (goto-char (point-min))
-          (diff-mode))))))
+             (if (consp (cdr patched-file))
+                 ;; two files (copy or rename)
+                 (stgit-run-git "diff" "-C" "-C" (concat id "^") id "--"
+                                (cadr patched-file) (cddr patched-file))
+               ;; just one file
+               (stgit-run-git "diff" (concat id "^") id "--"
+                              (cdr patched-file)))))
+        (stgit-run "show" "-O" "--patch-with-stat" patchsym))
+      (with-current-buffer standard-output
+       (goto-char (point-min))
+       (diff-mode)))))
 
 (defun stgit-edit ()
   "Edit the patch on the current line."
@@ -791,18 +842,28 @@ end of the patch."
            (substring patch 0 20))
           (t patch))))
 
-(defun stgit-delete (patchsyms)
+(defun stgit-delete (patchsyms &optional spill-p)
   "Delete the patches in PATCHSYMS.
-Interactively, delete the marked patches, or the patch at point."
-  (interactive (list (stgit-patches-marked-or-at-point)))
+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)
+                     current-prefix-arg))
+  (unless patchsyms
+    (error "No patches to delete"))
   (let ((npatches (length patchsyms)))
-    (if (zerop npatches)
-        (error "No patches to delete")
-      (when (yes-or-no-p (format "Really delete %d patch%s? "
-                                 npatches
-                                 (if (= 1 npatches) "" "es")))
+    (when (yes-or-no-p (format "Really delete %d patch%s%s? "
+                              npatches
+                              (if (= 1 npatches) "" "es")
+                               (if spill-p
+                                   " (spilling contents to index)"
+                                 "")))
+      (let ((args (if spill-p 
+                      (cons "--spill" patchsyms)
+                    patchsyms)))
         (stgit-capture-output nil
-          (apply 'stgit-run "delete" patchsyms))
+          (apply 'stgit-run "delete" args))
         (stgit-reload)))))
 
 (defun stgit-coalesce (patchsyms)