emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master 1725206: * lisp/vc/diff-mode.el: Improve diff-font-


From: Stefan Monnier
Subject: [Emacs-diffs] master 1725206: * lisp/vc/diff-mode.el: Improve diff-font-lock-prettify
Date: Sun, 21 Oct 2018 11:05:55 -0400 (EDT)

branch: master
commit 17252062b03defe9eac6a510e88b87932ef400fe
Author: Stefan Monnier <address@hidden>
Commit: Stefan Monnier <address@hidden>

    * lisp/vc/diff-mode.el: Improve diff-font-lock-prettify
    
    A few tweaks to the previous code for corner case problems, and a new
    feature, which is to move the +/- signs to the left fringe.
    
    (diff--font-lock-cleanup, diff--filter-substring): New functions.
    (diff-mode): Use them.
    (diff--font-lock-refined): Mark the overall overlays as `diff-mode
    fine` as well, so they get properly cleaned up when changing mode.
    (diff-fringe-add, diff-fringe-del, diff-fringe-rep, diff-fringe-nul):
    New bitmaps.
    (diff--font-lock-prettify): Move the +/- signs to the fringe.
    (diff-wiggle): Use 'user-error'.
---
 lisp/vc/diff-mode.el | 119 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 105 insertions(+), 14 deletions(-)

diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index 6c189c1..cf52368 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -1341,6 +1341,13 @@ See `after-change-functions' for the meaning of BEG, END 
and LEN."
   (diff-hunk-next arg)
   (diff-goto-source))
 
+(defun diff--font-lock-cleanup ()
+  (remove-overlays nil nil 'diff-mode 'fine)
+  (when font-lock-mode
+    (make-local-variable 'font-lock-extra-managed-props)
+    ;; Added when diff--font-lock-prettify is non-nil!
+    (cl-pushnew 'display font-lock-extra-managed-props)))
+
 (defvar whitespace-style)
 (defvar whitespace-trailing-regexp)
 
@@ -1358,12 +1365,10 @@ You can also switch between context diff and unified 
diff with \\[diff-context->
 or vice versa with \\[diff-unified->context] and you can also reverse the 
direction of
 a diff with \\[diff-reverse-direction].
 
-   \\{diff-mode-map}"
+\\{diff-mode-map}"
 
   (set (make-local-variable 'font-lock-defaults) diff-font-lock-defaults)
-  (add-hook 'font-lock-mode-hook
-            (lambda () (remove-overlays nil nil 'diff-mode 'fine))
-            nil 'local)
+  (add-hook 'font-lock-mode-hook #'diff--font-lock-cleanup nil 'local)
   (set (make-local-variable 'outline-regexp) diff-outline-regexp)
   (set (make-local-variable 'imenu-generic-expression)
        diff-imenu-generic-expression)
@@ -1408,6 +1413,8 @@ a diff with \\[diff-reverse-direction].
        #'diff-current-defun)
   (set (make-local-variable 'add-log-buffer-file-name-function)
        (lambda () (diff-find-file-name nil 'noprompt)))
+  (add-function :filter-return (local 'filter-buffer-substring-function)
+                #'diff--filter-substring)
   (unless (buffer-file-name)
     (hack-dir-local-variables-non-file-buffer)))
 
@@ -2088,6 +2095,7 @@ Return new point, if it was moved."
             (diff--refine-hunk beg end)
             (let ((ol (make-overlay beg end)))
               (overlay-put ol 'diff--font-lock-refined t)
+              (overlay-put ol 'diff-mode 'fine)
               (overlay-put ol 'evaporate t)
               (overlay-put ol 'modification-hooks
                            '(diff--font-lock-refine--refresh))))
@@ -2204,19 +2212,80 @@ fixed, visit it in a buffer."
 
 ;;; Prettifying from font-lock
 
+(define-fringe-bitmap 'diff-fringe-add
+  [#b00000000
+   #b00000000
+   #b00010000
+   #b00010000
+   #b01111100
+   #b00010000
+   #b00010000
+   #b00000000
+   #b00000000]
+  nil nil 'center)
+
+(define-fringe-bitmap 'diff-fringe-del
+  [#b00000000
+   #b00000000
+   #b00000000
+   #b00000000
+   #b01111100
+   #b00000000
+   #b00000000
+   #b00000000
+   #b00000000]
+  nil nil 'center)
+
+(define-fringe-bitmap 'diff-fringe-rep
+  [#b00000000
+   #b00010000
+   #b00010000
+   #b00010000
+   #b00010000
+   #b00010000
+   #b00000000
+   #b00010000
+   #b00000000]
+  nil nil 'center)
+
+(define-fringe-bitmap 'diff-fringe-nul
+  ;; Maybe there should be such an "empty" bitmap defined by default?
+  [#b00000000
+   #b00000000
+   #b00000000
+   #b00000000
+   #b00000000
+   #b00000000
+   #b00000000
+   #b00000000
+   #b00000000]
+  nil nil 'center)
+
 (defun diff--font-lock-prettify (limit)
-  ;; Mimicks the output of Magit's diff.
-  ;; FIXME: This has only been tested with Git's diff output.
   (when diff-font-lock-prettify
+    (save-excursion
+      ;; FIXME: Include the first space for context-style hunks!
+      (while (re-search-forward "^[-+! ]" limit t)
+        (let ((spec (alist-get (char-before)
+                               '((?+ . (left-fringe diff-fringe-add 
diff-added))
+                                 (?- . (left-fringe diff-fringe-del 
diff-removed))
+                                 (?! . (left-fringe diff-fringe-rep 
diff-changed))
+                                 (?\s . (left-fringe diff-fringe-nul))))))
+          (put-text-property (match-beginning 0) (match-end 0) 'display 
spec))))
+    ;; Mimicks the output of Magit's diff.
+    ;; FIXME: This has only been tested with Git's diff output.
     (while (re-search-forward "^diff " limit t)
+      ;; FIXME: Switching between context<->unified leads to messed up
+      ;; file headers by cutting the `display' property in chunks!
       (when (save-excursion
-                  (forward-line 0)
-                  (looking-at (eval-when-compile
-                                (concat "diff.*\n"
-                                        "\\(?:\\(?:new 
file\\|deleted\\).*\n\\)?"
-                                        "\\(?:index.*\n\\)?"
-                                        "--- \\(?:/dev/null\\|a/\\(.*\\)\\)\n"
-                                        "\\+\\+\\+ 
\\(?:/dev/null\\|b/\\(.*\\)\\)\n"))))
+              (forward-line 0)
+              (looking-at
+               (eval-when-compile
+                 (concat "diff.*\n"
+                         "\\(?:\\(?:new file\\|deleted\\).*\n\\)?"
+                         "\\(?:index.*\n\\)?"
+                         "--- \\(?:/dev/null\\|a/\\(.*\\)\\)\n"
+                         "\\+\\+\\+ \\(?:/dev/null\\|b/\\(.*\\)\\)\n"))))
         (put-text-property (match-beginning 0)
                            (or (match-beginning 2) (match-beginning 1))
                            'display (propertize
@@ -2230,6 +2299,28 @@ fixed, visit it in a buffer."
                              'display "")))))
   nil)
 
+(defun diff--filter-substring (str)
+  (when diff-font-lock-prettify
+    ;; Strip the `display' properties added by diff-font-lock-prettify,
+    ;; since they look weird when you kill&yank!
+    (remove-text-properties 0 (length str) '(display nil) str)
+    ;; We could also try to only remove those `display' properties actually
+    ;; added by diff-font-lock-prettify rather than removing them all blindly.
+    ;; E.g.:
+    ;;(let ((len (length str))
+    ;;      (i 0))
+    ;;  (while (and (< i len)
+    ;;              (setq i (text-property-not-all i len 'display nil str)))
+    ;;    (let* ((val (get-text-property i 'display str))
+    ;;           (end (or (text-property-not-all i len 'display val str) len)))
+    ;;      ;; FIXME: Check for display props that prettify the file header!
+    ;;      (when (eq 'left-fringe (car-safe val))
+    ;;        ;; FIXME: Should we check that it's a diff-fringe-* bitmap?
+    ;;        (remove-text-properties i end '(display nil) str))
+    ;;      (setq i end))))
+    )
+  str)
+
 ;;; Support for converting a diff to diff3 markers via `wiggle'.
 
 ;; Wiggle can be found at http://neil.brown.name/wiggle/ or in your nearest
@@ -2255,7 +2346,7 @@ conflict."
           (set-buffer (prog1 tmpbuf (setq tmpbuf (current-buffer))))
           (when (buffer-modified-p filebuf)
             (save-some-buffers nil (lambda () (eq (current-buffer) filebuf)))
-            (if (buffer-modified-p filebuf) (error "Abort!")))
+            (if (buffer-modified-p filebuf) (user-error "Abort!")))
           (write-region (car bounds) (cadr bounds) patchfile nil 'silent)
           (let ((exitcode
                  (call-process "wiggle" nil (list tmpbuf errfile) nil



reply via email to

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