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

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

[elpa] scratch/add-vdiff ad6035d 015/258: Implement folding of unchanged


From: Justin Burkett
Subject: [elpa] scratch/add-vdiff ad6035d 015/258: Implement folding of unchanged lines
Date: Wed, 17 May 2017 08:13:13 -0400 (EDT)

branch: scratch/add-vdiff
commit ad6035d52a95697d2889feb2dfac3fdaafd6f244
Author: justbur <address@hidden>
Commit: justbur <address@hidden>

    Implement folding of unchanged lines
---
 README.org |  15 ++--
 vdiff.el   | 248 ++++++++++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 180 insertions(+), 83 deletions(-)

diff --git a/README.org b/README.org
index aa75e46..b13f09e 100644
--- a/README.org
+++ b/README.org
@@ -18,12 +18,11 @@ vimdiff. vdiff does not assume you use evil-mode, but is 
compatible with it.
 vdiff is a work in progress, so use it at your own risk. Contributions are very
 welcome. A rough TODO list is
 
-1. Implement folding
-2. Improve scrolling/syncing position between buffers
-3. Three way diffs
-4. Other missing features from vimdiff
-5. Add tests
-6. Improve faces
+1. Improve scrolling/syncing position between buffers
+2. Three way diffs
+3. Other missing features from vimdiff
+4. Add tests
+5. Improve faces
 
 ** Installation and Usage
 
@@ -49,6 +48,10 @@ declaration the key bindings in vdiff buffers are
 | =C-c s= | =vdiff-send-changes=            | Send this hunk (or all in 
region) to other buffer  |
 | =C-c r= | =vdiff-receive-changes=         | Receive the corresponding hunk 
from other buffer   |
 | =C-c w= | =vdiff-save-buffers=            | Save both buffers                
                  |
+| =C-c o= | =vdiff-open-fold=               | Open fold at point or in region  
                  |
+| =C-c O= | =vdiff-open-all-folds=          | Open all folds in buffer         
                  |
+| =C-c c= | =vdiff-close-fold=              | Close fold at point or in region 
                  |
+| =C-c C= | =vdiff-close-all-folds=         | Close all folds in buffer        
                  |
 | =C-l=   | =vdiff-sync-and-center=         | Recenter both buffers at current 
line              |
 
 To start vdiff, use either =vdiff-files= to select two files or =vdiff-buffers=
diff --git a/vdiff.el b/vdiff.el
index 32a4577..916c9fc 100644
--- a/vdiff.el
+++ b/vdiff.el
@@ -39,12 +39,7 @@
 ;; vimdiff. vdiff does not assume you use evil-mode, but is compatible with it.
 
 ;; vdiff is a work in progress, so use it at your own risk. Contributions are 
very
-;; welcome. A rough TODO list is
-
-;; 1. Implement folding
-;; 2. Improve scrolling/syncing position between buffers
-;; 3. Three way diffs
-;; 4. Other missing features from vimdiff
+;; welcome.
 
 ;; ** Installation and Usage
 
@@ -131,6 +126,18 @@ the buffer here, because those are handled differently."
   :group 'vdiff
   :type '(repeat symbol))
 
+(defcustom vdiff-fold-padding 2
+  "Unchanged lines to leave unfolded around a fold"
+  :group 'vdiff
+  :type 'integer)
+
+(defcustom vdiff-fold-format-string "+ %s --- %s lines "
+  "Format string for text on closed folds. First element is the
+code on the first line being covered. The second is the number of
+lines hidden."
+  :group 'vdiff
+  :type 'string)
+
 (defvar vdiff--buffers nil)
 (defvar vdiff--temp-files nil)
 (defvar vdiff--process-buffer " *vdiff*")
@@ -284,7 +291,7 @@ the buffer here, because those are handled differently."
 (defun vdiff--make-subtraction-string (length)
   (let (string)
     (dotimes (_ length)
-      (push (make-string (vdiff--min-window-width) ?-) string))
+      (push (make-string (1- (vdiff--min-window-width)) ?-) string))
     (propertize
      (concat (mapconcat #'identity string "\n") "\n")
      'face '(:background "#440000"))))
@@ -321,77 +328,133 @@ the buffer here, because those are handled differently."
           (overlay-put ovr 'after-string
                        (vdiff--make-subtraction-string 
subtraction-padding)))))))
 
+(defun vdiff--make-fold (buffer range)
+  (with-current-buffer buffer
+    (let* ((beg-line (+ vdiff-fold-padding (car range)))
+           (end-line (1+ (- (cdr range) vdiff-fold-padding)))
+           (fold-start (vdiff--pos-at-line-beginning beg-line))
+           (summ-text (buffer-substring-no-properties
+                       fold-start
+                       (min (save-excursion
+                              (goto-char fold-start)
+                              (line-end-position))
+                            (+ fold-start
+                               (- (vdiff--min-window-width) 20)))))
+           (fold-end
+            (vdiff--pos-at-line-beginning end-line))
+           (ovr (make-overlay fold-start fold-end))
+           (text (format vdiff-fold-format-string
+                         summ-text
+                         (1+ (- end-line beg-line))))
+           (text
+            (propertize
+             (concat text
+                     (make-string (- (vdiff--min-window-width)
+                                     (length text) 1) ?-)
+                     "\n")
+             'face 'region)))
+      (overlay-put ovr 'face '(:background "#111"))
+      (overlay-put ovr 'vdiff-fold-text text)
+      (overlay-put ovr 'vdiff-type 'fold)
+      ovr)))
+
+(defun vdiff--add-folds (a-buffer b-buffer a-range b-range)
+  (when (and (> (1+ (- (cdr a-range) (car a-range)))
+                (* 2 vdiff-fold-padding))
+             (> (- (cdr a-range) (car a-range)) 2))
+    (let ((a-fold (vdiff--make-fold a-buffer a-range))
+          (b-fold (vdiff--make-fold b-buffer b-range)))
+      (overlay-put a-fold 'display (overlay-get a-fold 'vdiff-fold-text))
+      (overlay-put a-fold 'vdiff-fold-open nil)
+      (overlay-put a-fold 'vdiff-other-fold b-fold)
+      (overlay-put b-fold 'display (overlay-get b-fold 'vdiff-fold-text))
+      (overlay-put b-fold 'vdiff-fold-open nil)
+      (overlay-put b-fold 'vdiff-other-fold a-fold))))
+
 (defun vdiff--refresh-overlays ()
   (vdiff--remove-all-overlays)
   (vdiff--refresh-line-maps)
   (save-excursion
-    (dolist (header vdiff--diff-data)
-      (let* ((code (nth 0 header))
-             (a-buffer (car vdiff--buffers))
-             (b-buffer (cadr vdiff--buffers))
-             (a-range (nth 1 header))
-             (a-beg (car a-range))
-             (a-end (if (cdr-safe a-range)
-                        (cdr a-range)
-                      (car a-range)))
-             (a-norm-range (cons a-beg a-end))
-             (a-length (1+ (- a-end a-beg)))
-             (b-range (nth 2 header))
-             (b-beg (car b-range))
-             (b-end (if (cdr-safe b-range)
-                        (cdr b-range)
-                      (car b-range)))
-             (b-norm-range (cons b-beg b-end))
-             (b-length (1+ (- b-end b-beg))))
-        (cond ((string= code "d")
-               (vdiff--add-subtraction-overlays
-                b-buffer b-beg a-norm-range a-length)
-               (vdiff--add-change-overlays
-                a-buffer a-beg a-length b-norm-range t))
-
-              ((string= code "a")
-               (vdiff--add-subtraction-overlays
-                a-buffer a-beg b-norm-range b-length)
-               (vdiff--add-change-overlays
-                b-buffer b-beg b-length a-norm-range t))
-
-              ((and (string= code "c") (> a-length b-length))
-               (vdiff--add-change-overlays
-                a-buffer a-beg a-length b-norm-range)
-               (vdiff--add-change-overlays
-                b-buffer b-beg b-length a-norm-range
-                nil (- a-length b-length)))
-
-              ((and (string= code "c") (< a-length b-length))
-               (vdiff--add-change-overlays
-                a-buffer a-beg a-length b-norm-range
-                nil (- b-length a-length))
-               (vdiff--add-change-overlays
-                b-buffer b-beg b-length a-norm-range))
-
-              ((string= code "c")
-               (vdiff--add-change-overlays
-                a-buffer a-beg a-length b-norm-range)
-               (vdiff--add-change-overlays
-                b-buffer b-beg b-length a-norm-range)))))))
+    (let ((a-last-post-end 1)
+          (b-last-post-end 1))
+      (dolist (header vdiff--diff-data)
+        (let* ((a-buffer (car vdiff--buffers))
+               (b-buffer (cadr vdiff--buffers))
+               (code (nth 0 header))
+               (a-range (nth 1 header))
+               (b-range (nth 2 header))
+               (a-beg (car a-range))
+               (a-end (if (cdr-safe a-range)
+                          (cdr a-range)
+                        (car a-range)))
+               (a-norm-range (cons a-beg a-end))
+               (a-length (1+ (- a-end a-beg)))
+               (b-beg (car b-range))
+               (b-end (if (cdr-safe b-range)
+                          (cdr b-range)
+                        (car b-range)))
+               (b-norm-range (cons b-beg b-end))
+               (b-length (1+ (- b-end b-beg))))
+
+          (vdiff--add-folds
+           a-buffer b-buffer
+           (cons a-last-post-end (1- a-beg))
+           (cons b-last-post-end (1- b-beg)))
+          (setq a-last-post-end (1+ a-end))
+          (setq b-last-post-end (1+ b-end))
+
+          (cond ((string= code "d")
+                 (vdiff--add-subtraction-overlays
+                  b-buffer b-beg a-norm-range a-length)
+                 (vdiff--add-change-overlays
+                  a-buffer a-beg a-length b-norm-range t))
+
+                ((string= code "a")
+                 (vdiff--add-subtraction-overlays
+                  a-buffer a-beg b-norm-range b-length)
+                 (vdiff--add-change-overlays
+                  b-buffer b-beg b-length a-norm-range t))
+
+                ((and (string= code "c") (> a-length b-length))
+                 (vdiff--add-change-overlays
+                  a-buffer a-beg a-length b-norm-range)
+                 (vdiff--add-change-overlays
+                  b-buffer b-beg b-length a-norm-range
+                  nil (- a-length b-length)))
+
+                ((and (string= code "c") (< a-length b-length))
+                 (vdiff--add-change-overlays
+                  a-buffer a-beg a-length b-norm-range
+                  nil (- b-length a-length))
+                 (vdiff--add-change-overlays
+                  b-buffer b-beg b-length a-norm-range))
+
+                ((string= code "c")
+                 (vdiff--add-change-overlays
+                  a-buffer a-beg a-length b-norm-range)
+                 (vdiff--add-change-overlays
+                  b-buffer b-beg b-length a-norm-range))))))))
 
 ;; * Moving changes
 
+(defun vdiff--region-or-close-overlay ()
+  (if (region-active-p)
+      (list (region-beginning) (region-end))
+    (list (if (or (= (line-number-at-pos) 1)
+                  (vdiff--overlay-at-point
+                   nil (line-beginning-position)))
+              (line-beginning-position)
+            (save-excursion
+              (forward-line -1)
+              (line-beginning-position)))
+          (line-end-position))))
+
 (defun vdiff-send-changes (beg end &optional receive)
   "Send these changes to other vdiff buffer. If the region is
 active, send all changes found in the region. Otherwise use the
 changes under point or on the immediately preceding line."
   (interactive
-   (if (region-active-p)
-       (list (region-beginning) (region-end))
-     (list (if (or (= (line-number-at-pos) 1)
-                   (vdiff--overlay-at-point
-                    nil (line-beginning-position)))
-               (line-beginning-position)
-             (save-excursion
-               (forward-line -1)
-               (line-beginning-position)))
-           (line-end-position))))
+   (vdiff--region-or-close-overlay))
   (let* ((ovrs (overlays-in beg end)))
     (dolist (ovr ovrs)
       (cond ((memq (overlay-get ovr 'vdiff--type)
@@ -409,17 +472,7 @@ changes under point or on the immediately preceding line."
 other vdiff buffer. If the region is active, receive all
 corresponding changes found in the region. Otherwise use the
 changes under point or on the immediately preceding line."
-  (interactive
-   (if (region-active-p)
-       (list (region-beginning) (region-end))
-     (list (if (or (= (line-number-at-pos) 1)
-                   (vdiff--overlay-at-point
-                    nil (line-beginning-position)))
-               (line-beginning-position)
-             (save-excursion
-               (forward-line -1)
-               (line-beginning-position)))
-           (line-end-position))))
+  (interactive (vdiff--region-or-close-overlay))
   (vdiff-send-changes beg end t))
 
 (defun vdiff--transmit-change-overlay (chg-ovr &optional receive)
@@ -598,6 +651,43 @@ buffer and center both buffers at this line."
             (vdiff--translate-line
              this-line (vdiff--buffer-a-p)))))))))
 
+(defun vdiff-open-fold (beg end)
+  "Open folds between BEG and END, as well as corresponding ones
+in other vdiff buffer. If called interactively, either open fold
+at point or on prior line. If the region is active open all folds
+in the region."
+  (interactive (vdiff--region-or-close-overlay))
+  (dolist (ovr (overlays-at beg))
+    (when (eq (overlay-get ovr 'vdiff-type) 'fold)
+      (let ((other-fold (overlay-get ovr 'vdiff-other-fold)))
+        (dolist (ovr1 (list ovr other-fold))
+          (overlay-put ovr1 'vdiff-fold-open t)
+          (overlay-put ovr1 'display nil))))))
+
+(defun vdiff-close-fold (beg end)
+  "Close folds between BEG and END, as well as corresponding ones
+in other vdiff buffer. If called interactively, either close fold
+at point or on prior line. If the region is active close all
+folds in the region."
+  (interactive (vdiff--region-or-close-overlay))
+  (dolist (ovr (overlays-at beg))
+    (when (eq (overlay-get ovr 'vdiff-type) 'fold)
+      (let ((other-fold (overlay-get ovr 'vdiff-other-fold)))
+        (dolist (ovr1 (list ovr other-fold))
+          (overlay-put ovr1 'vdiff-fold-open nil)
+          (overlay-put ovr1 'display
+                       (overlay-get ovr1 'vdiff-fold-text)))))))
+
+(defun vdiff-open-all-folds ()
+  "Open all folds in both buffers"
+  (interactive)
+  (vdiff-open-fold (point-min) (point-max)))
+
+(defun vdiff-close-all-folds ()
+  "Close all folds in both buffers"
+  (interactive)
+  (vdiff-close-fold (point-min) (point-max)))
+
 ;; * Movement
 
 (defun vdiff-next-change ()
@@ -702,6 +792,10 @@ asked to select two buffers."
     (define-key map "s" 'vdiff-send-changes)
     (define-key map "r" 'vdiff-receive-changes)
     (define-key map "w" 'vdiff-save-buffers)
+    (define-key map "o" 'vdiff-open-fold)
+    (define-key map "O" 'vdiff-open-all-folds)
+    (define-key map "c" 'vdiff-close-fold)
+    (define-key map "C" 'vdiff-close-all-folds)
     map))
 
 (define-minor-mode vdiff-mode



reply via email to

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