(defcustom stgit-default-show-worktree t
"Set to non-nil to by default show the working tree in a new stgit buffer.
-Use \\<stgit-mode-map>\\[stgit-toggle-worktree] to toggle the this setting in an already-started StGit buffer."
+Use \\<stgit-mode-map>\\[stgit-toggle-worktree] to toggle the
+this setting in an already-started StGit buffer."
:type 'boolean
:group 'stgit
:link '(variable-link stgit-show-worktree))
(setq buffer-read-only t))
buf))
+(def-edebug-spec stgit-capture-output
+ (form body))
(defmacro stgit-capture-output (name &rest body)
"Capture StGit output and, if there was any output, show it in a window
at the end.
(defvar stgit-index-node)
(defvar stgit-worktree-node)
+(defvar stgit-did-advise nil
+ "Set to non-nil if appropriate (non-stgit) git functions have
+been advised to update the stgit status when necessary.")
+
(defconst stgit-allowed-branch-name-re
;; Disallow control characters, space, del, and "/:@^{}~" in
;; "/"-separated parts; parts may not start with a period (.)
(let ((standard-output (current-buffer)))
(apply 'stgit-run-git
(cond ((eq patchsym :work)
+ (let (standard-output)
+ (stgit-run-git "update-index" "--refresh"))
`("diff-files" "-0" ,@args))
((eq patchsym :index)
`("diff-index" ,@args "--cached" "HEAD"))
("c" . stgit-diff-combined)
("m" . stgit-find-file-merge)
("o" . stgit-diff-ours)
+ ("r" . stgit-diff-range)
("t" . stgit-diff-theirs)))
(suppress-keymap toggle-map)
(mapc (lambda (arg) (define-key toggle-map (car arg) (cdr arg)))
"-"
["Show diff" stgit-diff
:active (get-text-property (point) 'entry-type)]
+ ["Show diff for range of applied patches" stgit-diff-range
+ :active (= (length stgit-marked-patches) 1)]
("Merge"
:active (stgit-git-index-unmerged-p)
["Combined diff" stgit-diff-combined
Commands for diffs:
\\[stgit-diff] Show diff of patch or file
+\\[stgit-diff-range] Show diff for range of patches
\\[stgit-diff-base] Show diff against the merge base
\\[stgit-diff-ours] Show diff against our branch
\\[stgit-diff-theirs] Show diff against their branch
(set (make-local-variable 'stgit-worktree-node) nil)
(set (make-local-variable 'parse-sexp-lookup-properties) t)
(set-variable 'truncate-lines 't)
- (add-hook 'after-save-hook 'stgit-update-saved-file)
+ (add-hook 'after-save-hook 'stgit-update-stgit-for-buffer)
+ (unless stgit-did-advise
+ (stgit-advise)
+ (setq stgit-did-advise t))
(run-hooks 'stgit-mode-hook))
-(defun stgit-update-saved-file ()
- (let* ((file (expand-file-name buffer-file-name))
- (dir (file-name-directory file))
- (gitdir (condition-case nil (git-get-top-dir dir)
- (error nil)))
+(defun stgit-advise-funlist (funlist)
+ "Add advice to the functions in FUNLIST so we can refresh the
+stgit buffers as the git status of files change."
+ (mapc (lambda (sym)
+ (when (fboundp sym)
+ (eval `(defadvice ,sym (after stgit-update-stgit-for-buffer)
+ (stgit-update-stgit-for-buffer t)))
+ (ad-activate sym)))
+ funlist))
+
+(defun stgit-advise ()
+ "Add advice to appropriate (non-stgit) git functions so we can
+refresh the stgit buffers as the git status of files change."
+ (mapc (lambda (arg)
+ (let ((feature (car arg))
+ (funlist (cdr arg)))
+ (if (featurep feature)
+ (stgit-advise-funlist funlist)
+ (add-to-list 'after-load-alist
+ `(,feature (stgit-advise-funlist
+ (quote ,funlist)))))))
+ '((vc-git vc-git-rename-file vc-git-revert vc-git-register)
+ (git git-add-file git-checkout git-revert-file git-remove-file))))
+
+(defun stgit-update-stgit-for-buffer (&optional refresh-index)
+ "Refresh worktree status in any `stgit-mode' buffer that shows
+the status of the current buffer.
+
+If REFRESH-INDEX is not-nil, also update the index."
+ (let* ((dir (cond ((eq major-mode 'git-status-mode)
+ default-directory)
+ (buffer-file-name
+ (file-name-directory
+ (expand-file-name buffer-file-name)))))
+ (gitdir (and dir (condition-case nil (git-get-top-dir dir)
+ (error nil))))
(buffer (and gitdir (stgit-find-buffer gitdir))))
(when buffer
(with-current-buffer buffer
- (stgit-refresh-worktree)))))
+ (stgit-refresh-worktree)
+ (when refresh-index (stgit-refresh-index))))))
(defun stgit-add-mark (patchsym)
"Mark the patch PATCHSYM."
(when (and node file)
(let* ((file-ewoc (stgit-patch->files-ewoc (ewoc-data node)))
(file-node (ewoc-nth file-ewoc 0)))
- (while (and file-node (not (equal (stgit-file->file (ewoc-data file-node)) file)))
+ (while (and file-node
+ (not (equal (stgit-file->file (ewoc-data file-node))
+ file)))
(setq file-node (ewoc-next file-ewoc file-node)))
(when file-node
(ewoc-goto-node file-ewoc file-node)
'(applied top)
'(applied top index work)))
result)
- (ewoc-map (lambda (patch) (when (memq (stgit-patch->status patch) states)
- (setq result (cons patch result))))
+ (ewoc-map (lambda (patch)
+ (when (memq (stgit-patch->status patch) states)
+ (setq result (cons patch result)))
+ nil)
stgit-ewoc)
result))
"--cc"
"show a combined diff")
+(defun stgit-diff-range (&optional ignore-whitespace)
+ "Show diff for the range of patches between point and the marked patch.
+
+With a prefix argument, ignore whitespace. With a prefix argument
+greater than four (e.g., \\[universal-argument] \
+\\[universal-argument] \\[stgit-diff-range]), ignore all whitespace."
+ (interactive "p")
+ (stgit-assert-mode)
+ (unless (= (length stgit-marked-patches) 1)
+ (error "Need exactly one patch marked"))
+ (let* ((patches (stgit-sort-patches (cons (stgit-patch-name-at-point t t)
+ stgit-marked-patches)
+ t))
+ (first-patch (car patches))
+ (second-patch (if (cdr patches) (cadr patches) first-patch))
+ (whitespace-arg (stgit-whitespace-diff-arg ignore-whitespace))
+ (applied (stgit-applied-patchsyms t)))
+ (unless (and (memq first-patch applied) (memq second-patch applied))
+ (error "Can only show diff range for applied patches"))
+ (stgit-capture-output (format "*StGit diff %s..%s*"
+ first-patch second-patch)
+ (apply 'stgit-run-git (append '("diff" "--patch-with-stat")
+ (and whitespace-arg (list whitespace-arg))
+ (list (format "%s^" (stgit-id first-patch))
+ (stgit-id second-patch))))
+ (with-current-buffer standard-output
+ (goto-char (point-min))
+ (diff-mode)))))
+
(defun stgit-move-change-to-index (file &optional force)
"Copies the work tree state of FILE to index, using git add or git rm.