+(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))
+ (program (if git-mode stgit-git-program stgit-stg-program))
+ (defaultcmd (if patches
+ (concat program
+ " "
+ (and hyphens "-- ")
+ (mapconcat (if git-mode 'stgit-id 'identity)
+ patch-names " "))
+ (concat stgit-stg-program " ")))
+ (cmd (read-from-minibuffer "Shell command: "
+ (cons defaultcmd (+ (length program) 2))
+ 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))))
+