X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/blobdiff_plain/d11e0621dad259315ef587ac50aa3f1bd54032e2..2547179e7fe72ce7ac9a7641fd61ab00aaa205a8:/contrib/stgit.el?ds=sidebyside diff --git a/contrib/stgit.el b/contrib/stgit.el index 81222f6..b3be770 100644 --- a/contrib/stgit.el +++ b/contrib/stgit.el @@ -15,6 +15,7 @@ (require 'git nil t) (require 'cl) (require 'ewoc) +(require 'easymenu) (defun stgit (dir) "Manage StGit patches for the tree in DIR. @@ -676,13 +677,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))) @@ -696,10 +697,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)) @@ -795,8 +796,8 @@ file for (applied) copies and renames." "Keymap for StGit major mode.") (unless stgit-mode-map - (let ((diff-map (make-keymap)) - (toggle-map (make-keymap))) + (let ((diff-map (make-sparse-keymap)) + (toggle-map (make-sparse-keymap))) (suppress-keymap diff-map) (mapc (lambda (arg) (define-key diff-map (car arg) (cdr arg))) '(("b" . stgit-diff-base) @@ -858,7 +859,123 @@ file for (applied) copies and renames." ("\C-c\C-b" . stgit-rebase) ("t" . ,toggle-map) ("d" . ,diff-map) - ("q" . stgit-quit))))) + ("q" . stgit-quit)))) + + (let ((at-unmerged-file '(let ((file (stgit-patched-file-at-point))) + (and file (eq (stgit-file-status file) + 'unmerged)))) + (patch-collapsed-p '(lambda (p) (not (memq p stgit-expanded-patches))))) + (easy-menu-define stgit-menu stgit-mode-map + "StGit Menu" + `("StGit" + ["Reload" stgit-reload-or-repair + :help "Reload StGit status from disk"] + ["Repair" stgit-repair + :keys "\\[universal-argument] \\[stgit-reload-or-repair]" + :help "Repair StGit metadata"] + "-" + ["Undo" stgit-undo t] + ["Redo" stgit-redo t] + "-" + ["Git status" stgit-git-status :active (fboundp 'git-status)] + "-" + ["New patch" stgit-new-and-refresh + :help "Create a new patch from changes in index or work tree" + :active (not (and (stgit-index-empty-p) (stgit-work-tree-empty-p)))] + ["New empty patch" stgit-new + :help "Create a new, empty patch"] + ["(Un)mark patch" stgit-toggle-mark + :label (if (memq (stgit-patch-name-at-point nil t) + stgit-marked-patches) + "Unmark patch" "Mark patch") + :active (stgit-patch-name-at-point nil t)] + ["Expand/collapse patch" + (let ((patches (stgit-patches-marked-or-at-point))) + (if (member-if ,patch-collapsed-p patches) + (stgit-expand patches) + (stgit-collapse patches))) + :label (if (member-if ,patch-collapsed-p + (stgit-patches-marked-or-at-point)) + "Expand patches" + "Collapse patches") + :active (stgit-patches-marked-or-at-point)] + ["Edit patch" stgit-edit + :help "Edit patch comment" + :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 patches" stgit-delete + :active (stgit-patches-marked-or-at-point nil t)] + "-" + ["Move patches" stgit-move-patches + :active stgit-marked-patches + :help "Move marked patch(es) to point"] + ["Squash patches" stgit-squash + :active (> (length stgit-marked-patches) 1) + :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 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))] + "-" + ["Find file" stgit-select + :active (eq (get-text-property (point) 'entry-type) 'file)] + ["Open file" stgit-find-file-other-window + :active (eq (get-text-property (point) 'entry-type) 'file)] + ["Toggle file index" stgit-toggle-index + :active (and (eq (get-text-property (point) 'entry-type) 'file) + (memq (stgit-patch-name-at-point) '(:work :index))) + :label (if (eq (stgit-patch-name-at-point) :work) + "Move change to index" + "Move change to work tree")] + "-" + ["Show diff" stgit-diff + :active (get-text-property (point) 'entry-type)] + ("Merge" + :active (stgit-git-index-unmerged-p) + ["Combined diff" stgit-diff-combined + :active (memq (stgit-patch-name-at-point nil nil) '(:work :index))] + ["Diff against base" stgit-diff-base + :help "Show diff against the common base" + :active (memq (stgit-patch-name-at-point nil nil) '(:work :index))] + ["Diff against ours" stgit-diff-ours + :help "Show diff against our branch" + :active (memq (stgit-patch-name-at-point nil nil) '(:work :index))] + ["Diff against theirs" stgit-diff-theirs + :help "Show diff against their branch" + :active (memq (stgit-patch-name-at-point nil nil) '(:work :index))] + "-" + ["Interactive merge" stgit-find-file-merge + :help "Interactively merge the file" + :active ,at-unmerged-file] + ["Resolve file" stgit-resolve-file + :help "Mark file conflict as resolved" + :active ,at-unmerged-file] + ) + "-" + ["Show index & work tree" stgit-toggle-worktree :style toggle + :selected stgit-show-worktree] + ["Show unknown files" stgit-toggle-unknown :style toggle + :selected stgit-show-unknown :active stgit-show-worktree] + ["Show ignored files" stgit-toggle-ignored :style toggle + :selected stgit-show-ignored :active stgit-show-worktree] + "-" + ["Switch branches" stgit-branch t + :help "Switch to another branch"] + ["Rebase branch" stgit-rebase t + :help "Rebase the current branch"] + )))) + +;; disable tool bar editing buttons +(put 'stgit-mode 'mode-class 'special) (defun stgit-mode () "Major mode for interacting with StGit. @@ -894,8 +1011,8 @@ 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 @@ -1016,14 +1133,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. @@ -1637,7 +1756,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 @@ -1665,13 +1784,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 @@ -1710,20 +1837,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) @@ -1814,13 +1938,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)))