+(defun stgit-execute-process-sentinel (process sentinel)
+ (let (old-sentinel stgit-buf)
+ (with-current-buffer (process-buffer process)
+ (setq old-sentinel old-process-sentinel
+ stgit-buf stgit-buffer))
+ (and (memq (process-status process) '(exit signal))
+ (buffer-live-p stgit-buf)
+ (with-current-buffer stgit-buf
+ (stgit-reload)))
+ (funcall old-sentinel process sentinel)))
+
+(defun stgit-execute-process-filter (process output)
+ (with-current-buffer (process-buffer process)
+ (let* ((old-point (point))
+ (pmark (process-mark process))
+ (insert-at (marker-position pmark))
+ (at-pmark (= insert-at old-point)))
+ (goto-char insert-at)
+ (insert-before-markers output)
+ (comint-carriage-motion insert-at (point))
+ (set-marker pmark (point))
+ (unless at-pmark
+ (goto-char old-point)))))
+
+(defun stgit-execute (&optional git-mode)
+ "Prompt for an stg command to execute in a shell.
+
+The names of any marked patches or the patch at point are
+inserted in the command to be executed.
+
+With a prefix argument, or if GIT-MODE is non-nil, insert SHA1
+sums of the marked patches instead, and prompt for a git command.
+
+If the command ends in an ampersand, run it asynchronously.
+
+When the command has finished, reload the stgit buffer."
+ (interactive "P")
+ (stgit-assert-mode)
+ (let* ((patches (stgit-sort-patches
+ (stgit-patches-marked-or-at-point nil 'allow-committed)))
+ (patch-names (mapcar 'symbol-name patches))
+ (hyphens (find-if (lambda (s) (string-match "^-" s)) patch-names))
+ (defaultcmd (if patches
+ (concat (if git-mode "git" "stg") " "
+ (and hyphens "-- ")
+ (mapconcat (if git-mode 'stgit-id 'identity)
+ patch-names " "))
+ "stg "))
+ (cmd (read-from-minibuffer "Shell command: " (cons defaultcmd 5)
+ nil nil 'shell-command-history))
+ (async (string-match "&[ \t]*\\'" cmd))
+ (buffer (get-buffer-create
+ (if async
+ "*Async Shell Command*"
+ "*Shell Command Output*"))))
+ ;; cannot use minibuffer as stgit-reload would overwrite it; if we
+ ;; show the buffer, shell-command will not use the minibuffer
+ (display-buffer buffer)
+ (shell-command cmd)
+ (if async
+ (let ((old-buffer (current-buffer)))
+ (with-current-buffer buffer
+ (let ((process (get-buffer-process buffer)))
+ (set (make-local-variable 'old-process-sentinel)
+ (process-sentinel process))
+ (set (make-local-variable 'stgit-buffer)
+ old-buffer)
+ (set-process-filter process 'stgit-execute-process-filter)
+ (set-process-sentinel process 'stgit-execute-process-sentinel))))
+ (with-current-buffer buffer
+ (comint-carriage-motion (point-min) (point-max)))
+ (shrink-window-if-larger-than-buffer (get-buffer-window buffer))
+ (stgit-reload))))
+
+(defun stgit-undo-or-redo (redo hard)
+ "Run stg undo or, if REDO is non-nil, stg redo.
+
+If HARD is non-nil, use the --hard flag."
+ (stgit-assert-mode)
+ (let ((cmd (if redo "redo" "undo")))
+ (stgit-capture-output nil
+ (if arg
+ (when (or (and (stgit-index-empty-p)
+ (stgit-work-tree-empty-p))
+ (y-or-n-p (format "Hard %s may overwrite index/work tree changes. Continue? "
+ cmd)))
+ (stgit-run cmd "--hard"))
+ (stgit-run cmd))))
+ (stgit-reload))
+
+(defun stgit-undo (&optional arg)
+ "Run stg undo.
+With prefix argument, run it with the --hard flag.
+
+See also `stgit-redo'."
+ (interactive "P")
+ (stgit-undo-or-redo nil arg))
+
+(defun stgit-redo (&optional arg)
+ "Run stg redo.
+With prefix argument, run it with the --hard flag.
+
+See also `stgit-undo'."
+ (interactive "P")
+ (stgit-undo-or-redo t arg))
+
+(defun stgit-refresh (&optional arg)
+ "Run stg refresh.
+If the index contains any changes, only refresh from index.
+
+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 t t)))
+ (when (> (length patches) 1)
+ (error "Too many patches marked"))
+ (cons "-p" patches))
+ nil)))
+ (unless (stgit-index-empty-p)
+ (setq patchargs (cons "--index" patchargs)))
+ (stgit-capture-output nil
+ (apply 'stgit-run "refresh" patchargs))
+ (stgit-refresh-git-status))
+ (stgit-reload))
+
+(defvar stgit-show-worktree nil
+ "If nil, inhibit showing work tree and index in the stgit buffer.
+
+See also `stgit-show-worktree-mode'.")
+
+(defvar stgit-show-ignored nil
+ "If nil, inhibit showing files ignored by git.")
+
+(defvar stgit-show-unknown nil
+ "If nil, inhibit showing files not registered with git.")
+
+(defvar stgit-show-patch-names t
+ "If nil, inhibit showing patch names.")
+
+(defvar stgit-show-committed nil
+ "If nil, inhibit showing recent commits.")
+
+(defvar stgit-show-svn nil
+ "If nil, inhibit showing git svn information.")
+
+(defvar stgit-committed-count nil
+ "The number of recent commits to show.")
+
+(defmacro stgit-define-toggle-view (sym desc help)
+ (declare (indent 1))
+ (let* ((name (symbol-name sym))
+ (fun (intern (concat "stgit-toggle-" name)))
+ (flag (intern (concat "stgit-show-" name))))
+ ;; make help-follow find the correct function
+ `(put (quote ,fun) 'definition-name 'stgit-define-toggle-view)
+ `(defun ,fun (&optional arg)
+ ,help
+ (interactive "P")
+ (stgit-assert-mode)
+ (setq ,flag (if arg
+ (> (prefix-numeric-value arg) 0)
+ (not ,flag)))
+ (stgit-reload (format "%s %s" (if ,flag "Showing" "Hiding") ,desc)))))
+
+(stgit-define-toggle-view worktree
+ "work tree and index"
+ "Toggle the visibility of the work tree.
+With ARG, show the work tree if ARG is positive.
+
+Its initial setting is controlled by `stgit-default-show-worktree'.
+
+`stgit-show-worktree-mode' controls where on screen the index and
+work tree will show up.")
+
+(stgit-define-toggle-view ignored
+ "ignored files"
+ "Toggle the visibility of files ignored by git in the work
+tree. With ARG, show these files if ARG is positive.
+
+Its initial setting is controlled by `stgit-default-show-ignored'.
+
+Use \\[stgit-toggle-worktree] to show the work tree.")
+
+(stgit-define-toggle-view unknown
+ "unknown files"
+ "Toggle the visibility of files not registered with git in the
+work tree. With ARG, show these files if ARG is positive.
+
+Its initial setting is controlled by `stgit-default-show-unknown'.
+
+Use \\[stgit-toggle-worktree] to show the work tree.")
+
+(stgit-define-toggle-view patch-names
+ "patch names"
+ "Toggle the visibility of patch names. With ARG, show patch names
+if ARG is positive.
+
+The initial setting is controlled by `stgit-default-show-patch-names'.")
+
+(stgit-define-toggle-view svn
+ "subversion revisions"
+ "Toggle showing subversion information from git svn. With ARG,
+show svn information if ARG is positive.
+
+The initial setting is controlled by `stgit-default-show-svn'.")
+
+(defun stgit-toggle-committed (&optional arg)
+ "Toggle the visibility of historical git commits.
+With ARG, set the number of commits to show to ARG, and disable
+them if ARG is zero.
+
+The initial setting is controlled by `stgit-default-show-committed'."
+ (interactive "P")
+ (stgit-assert-mode)
+ (if (null arg)
+ (setq stgit-show-committed (not stgit-show-committed))
+ (let ((n (prefix-numeric-value arg)))
+ (setq stgit-show-committed (> n 0))
+ (setq stgit-committed-count n)))
+ (stgit-reload (format "%s historical commits"
+ (if (and stgit-show-committed
+ (> stgit-committed-count 0))
+ "Showing"
+ "Hiding"))))
+