X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/blobdiff_plain/5038381d0f32d23c03b8535cccee5bbbed85570f..277b52af33a2b41db17f9ef02f1fb3f421342899:/contrib/stgit.el diff --git a/contrib/stgit.el b/contrib/stgit.el index ec3c1d0..829669e 100644 --- a/contrib/stgit.el +++ b/contrib/stgit.el @@ -16,6 +16,187 @@ (require 'cl) (require 'ewoc) (require 'easymenu) +(require 'format-spec) + +(defun stgit-set-default (symbol value) + "Set default value of SYMBOL to VALUE using `set-default' and +reload all StGit buffers." + (set-default symbol value) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (eq major-mode 'stgit-mode) + (stgit-reload))))) + +(defgroup stgit nil + "A user interface for the StGit patch maintenance tool." + :group 'tools + :link '(function-link stgit) + :link '(url-link "http://www.procode.org/stgit/")) + +(defcustom stgit-abbreviate-copies-and-renames t + "If non-nil, abbreviate copies and renames as \"dir/{old -> new}/file\" +instead of \"dir/old/file -> dir/new/file\"." + :type 'boolean + :group 'stgit + :set 'stgit-set-default) + +(defcustom stgit-default-show-worktree t + "Set to non-nil to by default show the working tree in a new stgit buffer. + +Use \\\\[stgit-toggle-worktree] to toggle the this setting in an already-started StGit buffer." + :type 'boolean + :group 'stgit + :link '(variable-link stgit-show-worktree)) + +(defcustom stgit-find-copies-harder nil + "Try harder to find copied files when listing patches. + +When not nil, runs git diff-tree with the --find-copies-harder +flag, which reduces performance." + :type 'boolean + :group 'stgit + :set 'stgit-set-default) + +(defcustom stgit-show-worktree-mode 'center + "This variable controls where the \"Index\" and \"Work tree\" +will be shown on in the buffer. + +It can be set to 'top (above all patches), 'center (show between +applied and unapplied patches), and 'bottom (below all patches)." + :type '(radio (const :tag "above all patches (top)" top) + (const :tag "between applied and unapplied patches (center)" + center) + (const :tag "below all patches (bottom)" bottom)) + :group 'stgit + :link '(variable-link stgit-show-worktree) + :set 'stgit-set-default) + +(defcustom stgit-patch-line-format "%s%m%-30n %e%d" + "The format string used to format patch lines. +The format string is passed to `format-spec' and the following +format characters are recognized: + + %s - A '+', '-', '>' or space, depending on whether the patch is + applied, unapplied, top, or something else. + + %m - An asterisk if the patch is marked, and a space otherwise. + + %n - The patch name. + + %e - The string \"(empty) \" if the patch is empty. + + %d - The short patch description. + + %D - The short patch description, or the patch name. + +When `stgit-show-patch-names' is non-nil, the `stgit-noname-patch-line-format' +variable is used instead." + :type 'string + :group 'stgit + :set 'stgit-set-default) + +(defcustom stgit-noname-patch-line-format "%s%m%e%D" + "The alternate format string used to format patch lines. +It has the same semantics as `stgit-patch-line-format', and the +display can be toggled between the two formats using +\\>\\[stgit-toggle-patch-names]. + +The alternate form is used when the patch name is hidden." + :type 'string + :group 'stgit + :set 'stgit-set-default) + +(defcustom stgit-default-show-patch-names t + "If non-nil, default to showing patch names in a new stgit buffer. + +Use \\\\[stgit-toggle-patch-names] to toggle the +this setting in an already-started StGit buffer." + :type 'boolean + :group 'stgit + :link '(variable-link stgit-show-patch-names)) + +(defcustom stgit-file-line-format " %-11s %-2m %n %c" + "The format string used to format file lines. +The format string is passed to `format-spec' and the following +format characters are recognized: + + %s - A string describing the status of the file. + + %m - Mode change information + + %n - The file name. + + %c - A description of file changes." + :type 'string + :group 'stgit + :set 'stgit-set-default) + +(defface stgit-branch-name-face + '((t :inherit bold)) + "The face used for the StGit branch name" + :group 'stgit) + +(defface stgit-top-patch-face + '((((background dark)) (:weight bold :foreground "yellow")) + (((background light)) (:weight bold :foreground "purple")) + (t (:weight bold))) + "The face used for the top patch names" + :group 'stgit) + +(defface stgit-applied-patch-face + '((((background dark)) (:foreground "light yellow")) + (((background light)) (:foreground "purple")) + (t ())) + "The face used for applied patch names" + :group 'stgit) + +(defface stgit-unapplied-patch-face + '((((background dark)) (:foreground "gray80")) + (((background light)) (:foreground "orchid")) + (t ())) + "The face used for unapplied patch names" + :group 'stgit) + +(defface stgit-description-face + '((((background dark)) (:foreground "tan")) + (((background light)) (:foreground "dark red"))) + "The face used for StGit descriptions" + :group 'stgit) + +(defface stgit-index-work-tree-title-face + '((((supports :slant italic)) :slant italic) + (t :inherit bold)) + "StGit mode face used for the \"Index\" and \"Work tree\" titles" + :group 'stgit) + +(defface stgit-unmerged-file-face + '((((class color) (background light)) (:foreground "red" :bold t)) + (((class color) (background dark)) (:foreground "red" :bold t))) + "StGit mode face used for unmerged file status" + :group 'stgit) + +(defface stgit-unknown-file-face + '((((class color) (background light)) (:foreground "goldenrod" :bold t)) + (((class color) (background dark)) (:foreground "goldenrod" :bold t))) + "StGit mode face used for unknown file status" + :group 'stgit) + +(defface stgit-ignored-file-face + '((((class color) (background light)) (:foreground "grey60")) + (((class color) (background dark)) (:foreground "grey40"))) + "StGit mode face used for ignored files") + +(defface stgit-file-permission-face + '((((class color) (background light)) (:foreground "green" :bold t)) + (((class color) (background dark)) (:foreground "green" :bold t))) + "StGit mode face used for permission changes." + :group 'stgit) + +(defface stgit-modified-file-face + '((((class color) (background light)) (:foreground "purple")) + (((class color) (background dark)) (:foreground "salmon"))) + "StGit mode face used for modified file status" + :group 'stgit) (defun stgit (dir) "Manage StGit patches for the tree in DIR. @@ -73,30 +254,40 @@ directory DIR or `default-directory'" (defstruct (stgit-patch) status name desc empty files-ewoc) +(defun stgit-patch-display-name (patch) + (let ((name (stgit-patch-name patch))) + (case name + (:index "Index") + (:work "Work Tree") + (t (symbol-name name))))) + (defun stgit-patch-pp (patch) (let* ((status (stgit-patch-status patch)) (start (point)) (name (stgit-patch-name patch)) - (face (cdr (assq status stgit-patch-status-face-alist)))) - (insert (case status - ('applied "+") - ('top ">") - ('unapplied "-") - (t " ")) - (if (memq name stgit-marked-patches) - "*" " ")) - (if (memq status '(index work)) - (insert (propertize (if (eq status 'index) "Index" "Work tree") - 'face face)) - (insert (format "%-30s" - (propertize (symbol-name name) - 'face face - 'syntax-table (string-to-syntax "w"))) - " " - (if (stgit-patch-empty patch) "(empty) " "") - (propertize (or (stgit-patch-desc patch) "") - 'face 'stgit-description-face))) - (insert "\n") + (face (cdr (assq status stgit-patch-status-face-alist))) + (fmt (if stgit-show-patch-names + stgit-patch-line-format + stgit-noname-patch-line-format)) + (spec (format-spec-make + ?s (case status + ('applied "+") + ('top ">") + ('unapplied "-") + (t " ")) + ?m (if (memq name stgit-marked-patches) + "*" " ") + ?n (propertize (stgit-patch-display-name patch) + 'face face + 'syntax-table (string-to-syntax "w")) + ?e (if (stgit-patch-empty patch) "(empty) " "") + ?d (propertize (or (stgit-patch-desc patch) "") + 'face 'stgit-description-face) + ?D (propertize (or (stgit-patch-desc patch) + (stgit-patch-display-name patch)) + 'face face)))) + + (insert (format-spec fmt spec) "\n") (put-text-property start (point) 'entry-type 'patch) (when (memq name stgit-expanded-patches) (stgit-insert-patch-files patch)) @@ -125,6 +316,7 @@ Returns nil if there was no output." (stgit-dir default-directory) (inhibit-read-only t)) (with-current-buffer output-buf + (buffer-disable-undo) (erase-buffer) (setq default-directory stgit-dir) (setq buffer-read-only t)) @@ -284,126 +476,6 @@ Returns nil if there was no output." (goto-line curline))) (stgit-refresh-git-status)) -(defun stgit-set-default (symbol value) - "Set default value of SYMBOL to VALUE using `set-default' and -reload all StGit buffers." - (set-default symbol value) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (eq major-mode 'stgit-mode) - (stgit-reload))))) - -(defgroup stgit nil - "A user interface for the StGit patch maintenance tool." - :group 'tools - :link '(function-link stgit) - :link '(url-link "http://www.procode.org/stgit/")) - -(defcustom stgit-abbreviate-copies-and-renames t - "If non-nil, abbreviate copies and renames as \"dir/{old -> new}/file\" -instead of \"dir/old/file -> dir/new/file\"." - :type 'boolean - :group 'stgit - :set 'stgit-set-default) - -(defcustom stgit-default-show-worktree t - "Set to non-nil to by default show the working tree in a new stgit buffer. - -Use \\\\[stgit-toggle-worktree] to toggle the this setting in an already-started StGit buffer." - :type 'boolean - :group 'stgit - :link '(variable-link stgit-show-worktree)) - -(defcustom stgit-find-copies-harder nil - "Try harder to find copied files when listing patches. - -When not nil, runs git diff-tree with the --find-copies-harder -flag, which reduces performance." - :type 'boolean - :group 'stgit - :set 'stgit-set-default) - -(defcustom stgit-show-worktree-mode 'center - "This variable controls where the \"Index\" and \"Work tree\" -will be shown on in the buffer. - -It can be set to 'top (above all patches), 'center (show between -applied and unapplied patches), and 'bottom (below all patches)." - :type '(radio (const :tag "above all patches (top)" top) - (const :tag "between applied and unapplied patches (center)" - center) - (const :tag "below all patches (bottom)" bottom)) - :group 'stgit - :link '(variable-link stgit-show-worktree) - :set 'stgit-set-default) - -(defface stgit-branch-name-face - '((t :inherit bold)) - "The face used for the StGit branch name" - :group 'stgit) - -(defface stgit-top-patch-face - '((((background dark)) (:weight bold :foreground "yellow")) - (((background light)) (:weight bold :foreground "purple")) - (t (:weight bold))) - "The face used for the top patch names" - :group 'stgit) - -(defface stgit-applied-patch-face - '((((background dark)) (:foreground "light yellow")) - (((background light)) (:foreground "purple")) - (t ())) - "The face used for applied patch names" - :group 'stgit) - -(defface stgit-unapplied-patch-face - '((((background dark)) (:foreground "gray80")) - (((background light)) (:foreground "orchid")) - (t ())) - "The face used for unapplied patch names" - :group 'stgit) - -(defface stgit-description-face - '((((background dark)) (:foreground "tan")) - (((background light)) (:foreground "dark red"))) - "The face used for StGit descriptions" - :group 'stgit) - -(defface stgit-index-work-tree-title-face - '((((supports :slant italic)) :slant italic) - (t :inherit bold)) - "StGit mode face used for the \"Index\" and \"Work tree\" titles" - :group 'stgit) - -(defface stgit-unmerged-file-face - '((((class color) (background light)) (:foreground "red" :bold t)) - (((class color) (background dark)) (:foreground "red" :bold t))) - "StGit mode face used for unmerged file status" - :group 'stgit) - -(defface stgit-unknown-file-face - '((((class color) (background light)) (:foreground "goldenrod" :bold t)) - (((class color) (background dark)) (:foreground "goldenrod" :bold t))) - "StGit mode face used for unknown file status" - :group 'stgit) - -(defface stgit-ignored-file-face - '((((class color) (background light)) (:foreground "grey60")) - (((class color) (background dark)) (:foreground "grey40"))) - "StGit mode face used for ignored files") - -(defface stgit-file-permission-face - '((((class color) (background light)) (:foreground "green" :bold t)) - (((class color) (background dark)) (:foreground "green" :bold t))) - "StGit mode face used for permission changes." - :group 'stgit) - -(defface stgit-modified-file-face - '((((class color) (background light)) (:foreground "purple")) - (((class color) (background dark)) (:foreground "salmon"))) - "StGit mode face used for modified file status" - :group 'stgit) - (defconst stgit-file-status-code-strings (mapcar (lambda (arg) (cons (car arg) @@ -433,12 +505,11 @@ applied and unapplied patches), and 'bottom (below all patches)." stgit-file-status-code-strings)) (score (stgit-file-cr-score file))) (when code - (format "%-11s " - (if (and score (/= score 100)) - (format "%s %s" (cdr code) - (propertize (format "%d%%" score) - 'face 'stgit-description-face)) - (cdr code)))))) + (if (and score (/= score 100)) + (format "%s %s" (cdr code) + (propertize (format "%d%%" score) + 'face 'stgit-description-face)) + (cdr code))))) (defun stgit-file-status-code (str &optional score) "Return stgit status code from git status string" @@ -481,8 +552,8 @@ Cf. `stgit-file-type-string'." ((zerop old-type) (if (= new-type #o100) "" - (format " (%s)" (stgit-file-type-string new-type)))) - (t (format " (%s -> %s)" + (format "(%s)" (stgit-file-type-string new-type)))) + (t (format "(%s -> %s)" (stgit-file-type-string old-type) (stgit-file-type-string new-type)))))) @@ -555,23 +626,20 @@ Cf. `stgit-file-type-change-string'." (concat (stgit-file-cr-from file) arrow (stgit-file-cr-to file))))) (defun stgit-file-pp (file) - (let ((status (stgit-file-status file)) - (name (if (stgit-file-copy-or-rename file) - (stgit-describe-copy-or-rename file) - (stgit-file-file file))) - (mode-change (stgit-file-mode-change-string - (stgit-file-old-perm file) - (stgit-file-new-perm file))) - (start (point))) - (insert (format " %-12s%s%s%s%s\n" - (stgit-file-status-code-as-string file) - mode-change - (if (zerop (length mode-change)) "" " ") - name - (propertize (stgit-file-type-change-string - (stgit-file-old-perm file) - (stgit-file-new-perm file)) - 'face 'stgit-description-face))) + (let ((start (point)) + (spec (format-spec-make + ?s (stgit-file-status-code-as-string file) + ?m (stgit-file-mode-change-string + (stgit-file-old-perm file) + (stgit-file-new-perm file)) + ?n (if (stgit-file-copy-or-rename file) + (stgit-describe-copy-or-rename file) + (stgit-file-file file)) + ?c (propertize (stgit-file-type-change-string + (stgit-file-old-perm file) + (stgit-file-new-perm file)) + 'face 'stgit-description-face)))) + (insert (format-spec stgit-file-line-format spec) "\n") (add-text-properties start (point) (list 'entry-type 'file 'file-data file)))) @@ -677,13 +745,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 +765,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)) @@ -807,7 +875,8 @@ file for (applied) copies and renames." ("t" . stgit-diff-theirs))) (suppress-keymap toggle-map) (mapc (lambda (arg) (define-key toggle-map (car arg) (cdr arg))) - '(("t" . stgit-toggle-worktree) + '(("n" . stgit-toggle-patch-names) + ("t" . stgit-toggle-worktree) ("i" . stgit-toggle-ignored) ("u" . stgit-toggle-unknown))) (setq stgit-mode-map (make-keymap)) @@ -904,23 +973,25 @@ file for (applied) copies and renames." :active (stgit-patch-name-at-point nil t)] ["Rename patch" stgit-rename :active (stgit-patch-name-at-point nil t)] ["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)] + :label (if (subsetp (stgit-patches-marked-or-at-point nil t) + (stgit-applied-patchsyms t)) + "Pop patches" "Push patches")] + ["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))] @@ -966,6 +1037,8 @@ file for (applied) copies and renames." :selected stgit-show-unknown :active stgit-show-worktree] ["Show ignored files" stgit-toggle-ignored :style toggle :selected stgit-show-ignored :active stgit-show-worktree] + ["Show patch names" stgit-toggle-patch-names :style toggle + :selected stgit-show-patch-names] "-" ["Switch branches" stgit-branch t :help "Switch to another branch"] @@ -1010,11 +1083,12 @@ 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 +\\[stgit-new] Create a new, empty patch + \\[stgit-rename] Rename patch \\[stgit-edit] Edit patch description \\[stgit-delete] Delete patch(es) @@ -1024,11 +1098,11 @@ Commands for patches: \\[stgit-push-next] Push next patch onto stack \\[stgit-pop-next] Pop current patch from stack -\\[stgit-push-or-pop] Push or pop patch at point -\\[stgit-goto] Make current patch current by popping or pushing +\\[stgit-push-or-pop] Push or pop marked patches +\\[stgit-goto] Make patch at point current by popping or pushing \\[stgit-squash] Squash (meld together) patches -\\[stgit-move-patches] Move patch(es) to point +\\[stgit-move-patches] Move marked patches to point \\[stgit-commit] Commit patch(es) \\[stgit-uncommit] Uncommit patch(es) @@ -1042,6 +1116,7 @@ Commands for files: \\[stgit-revert] Revert changes to file Display commands: +\\[stgit-toggle-patch-names] Toggle showing patch names \\[stgit-toggle-worktree] Toggle showing index and work tree \\[stgit-toggle-unknown] Toggle showing unknown files \\[stgit-toggle-ignored] Toggle showing ignored files @@ -1067,6 +1142,7 @@ Commands for branches: Customization variables: `stgit-abbreviate-copies-and-renames' +`stgit-default-show-patch-names' `stgit-default-show-worktree' `stgit-find-copies-harder' `stgit-show-worktree-mode' @@ -1081,6 +1157,8 @@ See also \\[customize-group] for the \"stgit\" group." (set (make-local-variable 'list-buffers-directory) default-directory) (set (make-local-variable 'stgit-marked-patches) nil) (set (make-local-variable 'stgit-expanded-patches) (list :work :index)) + (set (make-local-variable 'stgit-show-patch-names) + stgit-default-show-patch-names) (set (make-local-variable 'stgit-show-worktree) stgit-default-show-worktree) (set (make-local-variable 'stgit-index-node) nil) (set (make-local-variable 'stgit-worktree-node) nil) @@ -1132,14 +1210,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. @@ -1460,23 +1540,43 @@ With numeric prefix argument, pop that many patches." (stgit-reload) (stgit-refresh-git-status)) -(defun stgit-applied-at-point-p () - "Return non-nil if the patch at point is applied." - (let ((patch (stgit-patch-at-point t))) - (not (eq (stgit-patch-status patch) 'unapplied)))) +(defun stgit-applied-patches (&optional only-patches) + "Return a list of the applied patches. + +If ONLY-PATCHES is not nil, exclude index and work tree." + (let ((states (if only-patches + '(applied top) + '(applied top index work))) + result) + (ewoc-map (lambda (patch) (when (memq (stgit-patch-status patch) states) + (setq result (cons patch result)))) + stgit-ewoc) + result)) + +(defun stgit-applied-patchsyms (&optional only-patches) + "Return a list of the symbols of the applied patches. + +If ONLY-PATCHES is not nil, exclude index and work tree." + (mapcar #'stgit-patch-name (stgit-applied-patches only-patches))) (defun stgit-push-or-pop () - "Push or pop the patch on the current line." + "Push or pop the marked patches." (interactive) (stgit-assert-mode) - (let ((patchsym (stgit-patch-name-at-point t t)) - (applied (stgit-applied-at-point-p))) + (let* ((patchsyms (stgit-patches-marked-or-at-point t t)) + (applied-syms (stgit-applied-patchsyms t)) + (unapplied (set-difference patchsyms applied-syms))) (stgit-capture-output nil - (stgit-run (if applied "pop" "push") patchsym)) - (stgit-reload))) + (apply 'stgit-run + (if unapplied "push" "pop") + "--" + (stgit-sort-patches (if unapplied unapplied patchsyms))))) + (stgit-reload)) (defun stgit-goto () - "Go to the patch on the current line." + "Go to the patch on the current line. + +Pops or pushes patches to make this patch topmost." (interactive) (stgit-assert-mode) (let ((patchsym (stgit-patch-name-at-point t))) @@ -1678,7 +1778,8 @@ file ended up. You can then jump to the file with \ (set (make-local-variable 'stgit-edit-patchsym) patchsym) (setq default-directory dir) (let ((standard-output edit-buf)) - (stgit-run-silent "edit" "--save-template=-" patchsym)))) + (save-excursion + (stgit-run-silent "edit" "--save-template=-" patchsym))))) (defun stgit-confirm-edit () (interactive) @@ -1753,7 +1854,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 +1882,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 +1935,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) @@ -1861,8 +1967,9 @@ deepest patch had before the squash." (set (make-local-variable 'stgit-patchsyms) sorted-patchsyms) (setq default-directory dir) (let ((result (let ((standard-output edit-buf)) - (apply 'stgit-run-silent "squash" - "--save-template=-" sorted-patchsyms)))) + (save-excursion + (apply 'stgit-run-silent "squash" + "--save-template=-" sorted-patchsyms))))) ;; stg squash may have reordered the patches or caused conflicts (with-current-buffer stgit-buffer @@ -1930,13 +2037,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))) @@ -1956,6 +2060,9 @@ See also `stgit-show-worktree-mode'.") (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.") + (defun stgit-toggle-worktree (&optional arg) "Toggle the visibility of the work tree. With ARG, show the work tree if ARG is positive. @@ -1998,4 +2105,17 @@ Use \\[stgit-toggle-worktree] to show the work tree." (not stgit-show-unknown))) (stgit-reload)) +(defun stgit-toggle-patch-names (&optional arg) + "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'." + (interactive) + (stgit-assert-mode) + (setq stgit-show-patch-names + (if (numberp arg) + (> arg 0) + (not stgit-show-patch-names))) + (stgit-reload)) + (provide 'stgit)