Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FR] stage selected region #170

Open
bricewge opened this issue Mar 15, 2020 · 6 comments
Open

[FR] stage selected region #170

bricewge opened this issue Mar 15, 2020 · 6 comments
Labels
enhancement new feature requested

Comments

@bricewge
Copy link

bricewge commented Mar 15, 2020

I wish it would be possible to stage selected region of a buffer, like magit does. ATM git-gutter:stage-hunk can only stage a whole hunk.

@syohex
Copy link
Contributor

syohex commented Mar 15, 2020

Sorry this package is no longer maintained. And it is difficult such feature correctly.

@syohex syohex closed this as completed Mar 15, 2020
@bricewge
Copy link
Author

Maybe misunderstood but I thought the members of @emacsorphanage were now maintaining emacs-git-gutter, especially @gonewest818. That's why I have opened this feature request. Can you keep it open, to track the possible enhancement of this package and let the new active maintainers choose if this FR is relevant?
Thank you greatly for all your work @syohex and for handing over the reins to the community!

@syohex syohex reopened this Mar 15, 2020
@gonewest818
Copy link
Collaborator

Yes, let’s keep the issues open so that new maintainers can continue working on them.

@gonewest818 gonewest818 added the enhancement new feature requested label Mar 24, 2020
@syohex
Copy link
Contributor

syohex commented Apr 4, 2020

Patch for staging region.

diff --git a/git-gutter.el b/git-gutter.el
index 01db6b2..1676b79 100644
--- a/git-gutter.el
+++ b/git-gutter.el
@@ -749,16 +749,17 @@ Can be a directory-local variable in your project.")
 
 (defun git-gutter:query-action (action action-fn update-fn)
   (git-gutter:awhen (git-gutter:search-here-diffinfo git-gutter:diffinfos)
-    (save-window-excursion
-      (when git-gutter:ask-p
-        (git-gutter:popup-hunk it))
-      (when (or (not git-gutter:ask-p)
-                (yes-or-no-p (format "%s current hunk ? " action)))
-        (funcall action-fn it)
-        (funcall update-fn))
-      (if git-gutter:ask-p
-          (delete-window (git-gutter:popup-buffer-window))
-        (message "%s current hunk." action)))))
+    (let ((diff-info (git-gutter:adjust-diff-info it)))
+      (save-window-excursion
+        (when git-gutter:ask-p
+          (git-gutter:popup-hunk diff-info))
+        (when (or (not git-gutter:ask-p)
+                  (yes-or-no-p (format "%s current hunk ? " action)))
+          (funcall action-fn diff-info)
+          (funcall update-fn))
+        (if git-gutter:ask-p
+            (delete-window (git-gutter:popup-buffer-window))
+          (message "%s current hunk." action))))))
 
 (defun git-gutter:revert-hunk ()
   "Revert current hunk."
@@ -809,6 +810,67 @@ Can be a directory-local variable in your project.")
   (let ((root (locate-dominating-file default-directory ".git")))
     (file-name-directory (file-relative-name (git-gutter:base-file) root))))
 
+(defun git-gutter:adjust-added-hunk (diff-info start-line end-line)
+  (unless (= (git-gutter-hunk-start-line diff-info) start-line)
+    (error "Invalid region. Staging region for added hunk must start from first line of this hunk"))
+  (let ((region-changes (1+ (- end-line start-line))))
+    (with-temp-buffer
+      (insert (git-gutter-hunk-content diff-info))
+      (goto-char (point-min))
+      ;; re-write header
+      (re-search-forward "\\+\\([0-9]+\\),\\([0-9]+\\)" nil t)
+      (let ((base-line (string-to-number (match-string-no-properties 1))))
+        (replace-match (number-to-string region-changes) t t nil 2)
+        (let ((end-offset (1+ (- end-line base-line))))
+          (forward-line (1+ end-offset))
+          (delete-region (point) (point-max))
+          (buffer-string))))))
+
+(defun git-gutter:adjust-diff-by-region (pre-keep-lines keep-lines post-keep-lines)
+  (let ((delete-fn (lambda (lines)
+                     (dotimes (_i lines)
+                       (let ((pos (point)))
+                         (forward-line 1)
+                         (delete-region pos (point)))))))
+    (funcall delete-fn pre-keep-lines)
+    (forward-line keep-lines)
+    (funcall delete-fn post-keep-lines)))
+
+(defun git-gutter:adjust-modified-hunk (diff-info start-line end-line)
+  (with-temp-buffer
+    (insert (git-gutter-hunk-content diff-info))
+    (goto-char (point-min))
+    (re-search-forward ",[0-9]+ \\+\\([0-9]+\\),[0-9]+" nil t)
+    (let* ((base-line (string-to-number (match-string-no-properties 1)))
+           (pre-keep-lines (- start-line base-line))
+           (keep-lines (1+ (- end-line start-line)))
+           (post-keep-lines (- (git-gutter-hunk-end-line diff-info) end-line))
+           (new-header (format ",%d +%d,%d" keep-lines base-line keep-lines)))
+      (replace-match new-header)
+      (forward-line 1)
+      ;; adjust '-' part
+      (git-gutter:adjust-diff-by-region pre-keep-lines keep-lines post-keep-lines)
+      (re-search-forward "^\\+" nil t)
+      (goto-char (match-beginning 0))
+      ;; adjust '+' part
+      (git-gutter:adjust-diff-by-region pre-keep-lines keep-lines post-keep-lines)
+      (buffer-string))))
+
+(defun git-gutter:adjust-diff-info (diff-info)
+  (let ((hunk-type (git-gutter-hunk-type diff-info)))
+    (if (or (not (use-region-p)) (not (memq hunk-type '(added modified))))
+        diff-info
+      (let ((start-line (max (line-number-at-pos (region-beginning))
+                             (git-gutter-hunk-start-line diff-info)))
+            (end-line (min (line-number-at-pos (region-end))
+                           (git-gutter-hunk-end-line diff-info))))
+        (let ((new-hunk (cl-case hunk-type
+                          (added (git-gutter:adjust-added-hunk diff-info start-line end-line))
+                          (modified (git-gutter:adjust-modified-hunk diff-info start-line end-line))))
+              (adjusted-hunk (copy-git-gutter-hunk diff-info)))
+          (setf (git-gutter-hunk-content adjusted-hunk) new-hunk)
+          adjusted-hunk)))))
+
 (defun git-gutter:do-stage-hunk (diff-info)
   (let ((content (git-gutter-hunk-content diff-info))
         (type (git-gutter-hunk-type diff-info))

@NicholasBHubbard
Copy link

Would a PR for this patch be merged?

@syohex
Copy link
Contributor

syohex commented Mar 10, 2022

I'm not sure that the above patch works well. I think I doesn't work well in some situations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement new feature requested
Development

No branches or pull requests

4 participants