stgit.el: Fix showing diff in file that has been both copied and modified
[stgit] / contrib / stgit.el
index c4b78e2..564714b 100644 (file)
@@ -410,27 +410,37 @@ Returns nil if there was no output."
                    (error "Bad element in stgit-make-run-args args: %S" x))))
           args))
 
                    (error "Bad element in stgit-make-run-args args: %S" x))))
           args))
 
-(defun stgit-run-silent (&rest args)
-  (setq args (stgit-make-run-args args))
-  (apply 'call-process "stg" nil standard-output nil args))
+(defvar stgit-inhibit-messages nil
+  "Set to non-nil to inhibit messages when running `stg' commands.
+See also `stgit-message'.")
+(defun stgit-message (format-spec &rest args)
+  "Call `message' on the arguments unless `stgit-inhibit-messages' is non-nil."
+  (unless stgit-inhibit-messages
+    (apply 'message format-spec args)))
 
 (defun stgit-run (&rest args)
   (setq args (stgit-make-run-args args))
   (let ((msgcmd (mapconcat #'identity args " ")))
 
 (defun stgit-run (&rest args)
   (setq args (stgit-make-run-args args))
   (let ((msgcmd (mapconcat #'identity args " ")))
-    (message "Running stg %s..." msgcmd)
-    (apply 'call-process "stg" nil standard-output nil args)
-    (message "Running stg %s...done" msgcmd)))
+    (stgit-message "Running stg %s..." msgcmd)
+    (prog1
+        (apply 'call-process "stg" nil standard-output nil args)
+      (stgit-message "Running stg %s...done" msgcmd))))
+
+(defun stgit-run-silent (&rest args)
+  (let ((stgit-inhibit-messages t))
+    (apply 'stgit-run args)))
 
 (defun stgit-run-git (&rest args)
   (setq args (stgit-make-run-args args))
   (let ((msgcmd (mapconcat #'identity args " ")))
 
 (defun stgit-run-git (&rest args)
   (setq args (stgit-make-run-args args))
   (let ((msgcmd (mapconcat #'identity args " ")))
-    (message "Running git %s..." msgcmd)
-    (apply 'call-process "git" nil standard-output nil args)
-    (message "Running git %s...done" msgcmd)))
+    (stgit-message "Running git %s..." msgcmd)
+    (prog1
+        (apply 'call-process "git" nil standard-output nil args)
+      (stgit-message "Running git %s...done" msgcmd))))
 
 (defun stgit-run-git-silent (&rest args)
 
 (defun stgit-run-git-silent (&rest args)
-  (setq args (stgit-make-run-args args))
-  (apply 'call-process "git" nil standard-output nil args))
+  (let ((stgit-inhibit-messages t))
+    (apply 'stgit-run-git args)))
 
 (defun stgit-index-empty-p ()
   "Returns non-nil if the index contains no changes from HEAD."
 
 (defun stgit-index-empty-p ()
   "Returns non-nil if the index contains no changes from HEAD."
@@ -593,14 +603,20 @@ using (make-hash-table :test 'equal)."
                (stgit-run-silent "branch"))
              0 -1))
 
                (stgit-run-silent "branch"))
              0 -1))
 
-(defun stgit-reload ()
-  "Update the contents of the StGit buffer."
+(defun stgit-reload (&optional description)
+  "Update the contents of the StGit buffer.
+
+If DESCRIPTION is non-nil, it is displayed as a status message
+during the operation."
   (interactive)
   (stgit-assert-mode)
   (interactive)
   (stgit-assert-mode)
+  (when description
+    (message "%s..." description))
   (let ((inhibit-read-only t)
         (curline (line-number-at-pos))
         (curpatch (stgit-patch-name-at-point))
   (let ((inhibit-read-only t)
         (curline (line-number-at-pos))
         (curpatch (stgit-patch-name-at-point))
-        (curfile (stgit-patched-file-at-point)))
+        (curfile (stgit-patched-file-at-point))
+        (stgit-inhibit-messages description))
     (ewoc-filter stgit-ewoc #'(lambda (x) nil))
     (ewoc-set-hf stgit-ewoc
                  (concat "Branch: "
     (ewoc-filter stgit-ewoc #'(lambda (x) nil))
     (ewoc-set-hf stgit-ewoc
                  (concat "Branch: "
@@ -619,8 +635,10 @@ using (make-hash-table :test 'equal)."
                                    (and curfile (stgit-file->file curfile))))
       (goto-char (point-min))
       (forward-line (1- curline))
                                    (and curfile (stgit-file->file curfile))))
       (goto-char (point-min))
       (forward-line (1- curline))
-      (move-to-column (stgit-goal-column))))
-  (stgit-refresh-git-status))
+      (move-to-column (stgit-goal-column)))
+    (stgit-refresh-git-status))
+  (when description
+    (message "%s...done" description)))
 
 (defconst stgit-file-status-code-strings
   (mapcar (lambda (arg)
 
 (defconst stgit-file-status-code-strings
   (mapcar (lambda (arg)
@@ -1998,6 +2016,8 @@ which stage to diff against in the case of unmerged files."
                                      (list unmerged-stage))
                                     (t
                                      (list (concat patch-id "^") patch-id)))
                                      (list unmerged-stage))
                                     (t
                                      (list (concat patch-id "^") patch-id)))
+                              (and (eq (stgit-file->status patched-file) 'copy)
+                                   '("--diff-filter=C"))
                               '("--")
                               (if (stgit-file->copy-or-rename patched-file)
                                   (list (stgit-file->cr-from patched-file)
                               '("--")
                               (if (stgit-file->copy-or-rename patched-file)
                                   (list (stgit-file->cr-from patched-file)
@@ -2433,24 +2453,29 @@ deepest patch had before the squash."
       (unless at-pmark
         (goto-char old-point)))))
 
       (unless at-pmark
         (goto-char old-point)))))
 
-(defun stgit-execute ()
+(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.
 
   "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."
 If the command ends in an ampersand, run it asynchronously.
 
 When the command has finished, reload the stgit buffer."
-  (interactive)
+  (interactive "P")
   (stgit-assert-mode)
   (stgit-assert-mode)
-  (let* ((patches (stgit-patches-marked-or-at-point nil 'allow-committed))
+  (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
          (patch-names (mapcar 'symbol-name patches))
          (hyphens (find-if (lambda (s) (string-match "^-" s)) patch-names))
          (defaultcmd (if patches
-                         (concat "stg  "
+                         (concat (if git-mode "git" "stg") "  "
                                  (and hyphens "-- ")
                                  (and hyphens "-- ")
-                                 (mapconcat 'identity patch-names " "))
+                                 (mapconcat (if git-mode 'stgit-id 'identity)
+                                            patch-names " "))
                        "stg "))
          (cmd (read-from-minibuffer "Shell command: " (cons defaultcmd 5)
                                     nil nil 'shell-command-history))
                        "stg "))
          (cmd (read-from-minibuffer "Shell command: " (cons defaultcmd 5)
                                     nil nil 'shell-command-history))
@@ -2553,7 +2578,7 @@ See also `stgit-show-worktree-mode'.")
 (defvar stgit-committed-count nil
   "The number of recent commits to show.")
 
 (defvar stgit-committed-count nil
   "The number of recent commits to show.")
 
-(defmacro stgit-define-toggle-view (sym help)
+(defmacro stgit-define-toggle-view (sym desc help)
   (declare (indent 1))
   (let* ((name (symbol-name sym))
          (fun  (intern (concat "stgit-toggle-" name)))
   (declare (indent 1))
   (let* ((name (symbol-name sym))
          (fun  (intern (concat "stgit-toggle-" name)))
@@ -2567,9 +2592,10 @@ See also `stgit-show-worktree-mode'.")
        (setq ,flag (if arg
                        (> (prefix-numeric-value arg) 0)
                      (not ,flag)))
        (setq ,flag (if arg
                        (> (prefix-numeric-value arg) 0)
                      (not ,flag)))
-       (stgit-reload))))
+       (stgit-reload (format "%s %s" (if ,flag "Showing" "Hiding") ,desc)))))
 
 (stgit-define-toggle-view worktree
 
 (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.
 
   "Toggle the visibility of the work tree.
 With ARG, show the work tree if ARG is positive.
 
@@ -2579,6 +2605,7 @@ Its initial setting is controlled by `stgit-default-show-worktree'.
 work tree will show up.")
 
 (stgit-define-toggle-view ignored
 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.
 
   "Toggle the visibility of files ignored by git in the work
 tree. With ARG, show these files if ARG is positive.
 
@@ -2587,6 +2614,7 @@ Its initial setting is controlled by `stgit-default-show-ignored'.
 Use \\[stgit-toggle-worktree] to show the work tree.")
 
 (stgit-define-toggle-view unknown
 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.
 
   "Toggle the visibility of files not registered with git in the
 work tree. With ARG, show these files if ARG is positive.
 
@@ -2595,12 +2623,14 @@ 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
 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
   "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.
 
   "Toggle showing subversion information from git svn. With ARG,
 show svn information if ARG is positive.
 
@@ -2619,6 +2649,10 @@ The initial setting is controlled by `stgit-default-show-committed'."
     (let ((n (prefix-numeric-value arg)))
       (setq stgit-show-committed (> n 0))
       (setq stgit-committed-count n)))
     (let ((n (prefix-numeric-value arg)))
       (setq stgit-show-committed (> n 0))
       (setq stgit-committed-count n)))
-  (stgit-reload))
+  (stgit-reload (format "%s historical commits"
+                        (if (and stgit-show-committed
+                                 (> stgit-committed-count 0))
+                            "Showing"
+                          "Hiding"))))
 
 (provide 'stgit)
 
 (provide 'stgit)