emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/diff-hl b68fc2f8e6 1/5: New commands: diff-hl-stage-som


From: ELPA Syncer
Subject: [elpa] externals/diff-hl b68fc2f8e6 1/5: New commands: diff-hl-stage-some and diff-hl-stage-dwim
Date: Sun, 21 Jan 2024 00:57:43 -0500 (EST)

branch: externals/diff-hl
commit b68fc2f8e68132187d1799d0295aecadddd350bf
Author: Dmitry Gutov <dmitry@gutov.dev>
Commit: Dmitry Gutov <dmitry@gutov.dev>

    New commands: diff-hl-stage-some and diff-hl-stage-dwim
    
    #195
---
 diff-hl.el | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 86 insertions(+), 12 deletions(-)

diff --git a/diff-hl.el b/diff-hl.el
index e302523a42..56255232c1 100644
--- a/diff-hl.el
+++ b/diff-hl.el
@@ -708,6 +708,21 @@ its end position."
     (unless (eq backend 'Git)
       (user-error "Only Git supports staging; this file is controlled by %s" 
backend))))
 
+(defun diff-hl-stage-diff (orig-buffer)
+  (let ((patchfile (make-temp-file "diff-hl-stage-patch"))
+        success)
+    (write-region (point-min) (point-max) patchfile
+                  nil 'silent)
+    (unwind-protect
+        (with-current-buffer orig-buffer
+          (with-output-to-string
+            (vc-git-command standard-output 0
+                            patchfile
+                            "apply" "--cached" )
+            (setq success t)))
+      (delete-file patchfile))
+    success))
+
 (defun diff-hl-stage-current-hunk ()
   "Stage the hunk at or near point.
 
@@ -741,17 +756,7 @@ Only supported with Git."
         (insert (format "diff a/%s b/%s\n" file-base file-base))
         (insert (format "--- a/%s\n" file-base))
         (insert (format "+++ b/%s\n" file-base)))
-      (let ((patchfile (make-temp-file "diff-hl-stage-patch")))
-        (write-region (point-min) (point-max) patchfile
-                      nil 'silent)
-        (unwind-protect
-            (with-current-buffer orig-buffer
-              (with-output-to-string
-                (vc-git-command standard-output 0
-                                patchfile
-                                "apply" "--cached" ))
-              (setq success t))
-          (delete-file patchfile))))
+      (setq success (diff-hl-stage-diff orig-buffer)))
     (when success
       (if diff-hl-show-staged-changes
           (message (concat "Hunk staged; customize 
`diff-hl-show-staged-changes'"
@@ -773,6 +778,75 @@ Only supported with Git."
   (unless diff-hl-show-staged-changes
     (diff-hl-update)))
 
+(defun diff-hl-stage-dwim (&optional with-edit)
+  "Stage the current hunk or choose the hunks to stage.
+When called with the prefix argument, invokes `diff-hl-stage-some'."
+  (interactive "p")
+  (if with-edit
+      (call-interactively #'diff-hl-stage-some)
+    (call-interactively #'diff-hl-stage-current-hunk)))
+
+(defvar diff-hl-stage--orig nil)
+
+(define-derived-mode diff-hl-stage-diff-mode diff-mode "Stage Diff"
+  "Major mode for editing a diff buffer before staging.
+
+\\[diff-hl-stage-commit]"
+  (setq revert-buffer-function #'ignore))
+
+(define-key diff-hl-stage-diff-mode-map (kbd "C-c C-c") #'diff-hl-stage-finish)
+
+(defun diff-hl-stage-some ()
+  "Stage some or all of the current changes, interactively.
+Pops up a diff buffer that can be edited to choose the changes to stage."
+  (interactive)
+  (diff-hl--ensure-staging-supported)
+  (diff-hl-find-current-hunk)
+  (let* ((line (line-number-at-pos))
+         (file buffer-file-name)
+         (dest-buffer (get-buffer-create "*diff-hl-stage-some*"))
+         (orig-buffer (current-buffer))
+         ;; FIXME: If the file name has double quotes, these need to be quoted.
+         (file-base (file-name-nondirectory file)))
+    (with-current-buffer dest-buffer
+      (let ((inhibit-read-only t))
+        (erase-buffer)))
+    (diff-hl-diff-buffer-with-reference file dest-buffer nil 3)
+    (with-current-buffer dest-buffer
+      (with-no-warnings
+        (let (diff-auto-refine-mode)
+          (diff-hl-diff-skip-to line)))
+      (let ((inhibit-read-only t))
+        (goto-char (point-min))
+        (forward-line 3)
+        (delete-region (point-min) (point))
+        ;; diff-no-select creates a very ugly header; Git rejects it
+        (insert (format "diff a/%s b/%s\n" file-base file-base))
+        (insert (format "--- a/%s\n" file-base))
+        (insert (format "+++ b/%s\n" file-base)))
+      (let ((diff-default-read-only t))
+        (diff-hl-stage-diff-mode))
+      (setq-local diff-hl-stage--orig orig-buffer))
+    (pop-to-buffer dest-buffer)
+    (message "Press %s and %s to navigate, %s to split, %s to kill hunk, %s to 
undo, and %s to stage the diff after editing"
+             (substitute-command-keys "\\`n'")
+             (substitute-command-keys "\\`p'")
+             (substitute-command-keys "\\[diff-split-hunk]")
+             (substitute-command-keys "\\[diff-hunk-kill]")
+             (substitute-command-keys "\\[diff-undo]")
+             (substitute-command-keys "\\[diff-hl-stage-finish]"))))
+
+(defun diff-hl-stage-finish ()
+  (interactive)
+  (let ((count 0))
+    (when (diff-hl-stage-diff diff-hl-stage--orig)
+      (save-excursion
+        (goto-char (point-min))
+        (while (re-search-forward diff-hunk-header-re-unified nil t)
+          (cl-incf count)))
+      (message "Staged %d hunks" count)
+      (bury-buffer))))
+
 (defvar diff-hl-command-map
   (let ((map (make-sparse-keymap)))
     (define-key map "n" 'diff-hl-revert-hunk)
@@ -781,7 +855,7 @@ Only supported with Git."
     (define-key map "*" 'diff-hl-show-hunk)
     (define-key map "{" 'diff-hl-show-hunk-previous)
     (define-key map "}" 'diff-hl-show-hunk-next)
-    (define-key map "S" 'diff-hl-stage-current-hunk)
+    (define-key map "S" 'diff-hl-stage-dwim)
     map))
 (fset 'diff-hl-command-map diff-hl-command-map)
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]