aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2018-10-21 11:05:49 -0400
committerStefan Monnier2018-10-21 11:05:49 -0400
commit17252062b03defe9eac6a510e88b87932ef400fe (patch)
tree5dc9d05befd582c2eacb990186857eaffbc19cce
parent67d3b40e0cba5f34b1c7aacc4e1ccea6300eae76 (diff)
downloademacs-17252062b03defe9eac6a510e88b87932ef400fe.tar.gz
emacs-17252062b03defe9eac6a510e88b87932ef400fe.zip
* 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'.
-rw-r--r--lisp/vc/diff-mode.el119
1 files changed, 105 insertions, 14 deletions
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index 6c189c13cd4..cf523685086 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."
1341 (diff-hunk-next arg) 1341 (diff-hunk-next arg)
1342 (diff-goto-source)) 1342 (diff-goto-source))
1343 1343
1344(defun diff--font-lock-cleanup ()
1345 (remove-overlays nil nil 'diff-mode 'fine)
1346 (when font-lock-mode
1347 (make-local-variable 'font-lock-extra-managed-props)
1348 ;; Added when diff--font-lock-prettify is non-nil!
1349 (cl-pushnew 'display font-lock-extra-managed-props)))
1350
1344(defvar whitespace-style) 1351(defvar whitespace-style)
1345(defvar whitespace-trailing-regexp) 1352(defvar whitespace-trailing-regexp)
1346 1353
@@ -1358,12 +1365,10 @@ You can also switch between context diff and unified diff with \\[diff-context->
1358or vice versa with \\[diff-unified->context] and you can also reverse the direction of 1365or vice versa with \\[diff-unified->context] and you can also reverse the direction of
1359a diff with \\[diff-reverse-direction]. 1366a diff with \\[diff-reverse-direction].
1360 1367
1361 \\{diff-mode-map}" 1368\\{diff-mode-map}"
1362 1369
1363 (set (make-local-variable 'font-lock-defaults) diff-font-lock-defaults) 1370 (set (make-local-variable 'font-lock-defaults) diff-font-lock-defaults)
1364 (add-hook 'font-lock-mode-hook 1371 (add-hook 'font-lock-mode-hook #'diff--font-lock-cleanup nil 'local)
1365 (lambda () (remove-overlays nil nil 'diff-mode 'fine))
1366 nil 'local)
1367 (set (make-local-variable 'outline-regexp) diff-outline-regexp) 1372 (set (make-local-variable 'outline-regexp) diff-outline-regexp)
1368 (set (make-local-variable 'imenu-generic-expression) 1373 (set (make-local-variable 'imenu-generic-expression)
1369 diff-imenu-generic-expression) 1374 diff-imenu-generic-expression)
@@ -1408,6 +1413,8 @@ a diff with \\[diff-reverse-direction].
1408 #'diff-current-defun) 1413 #'diff-current-defun)
1409 (set (make-local-variable 'add-log-buffer-file-name-function) 1414 (set (make-local-variable 'add-log-buffer-file-name-function)
1410 (lambda () (diff-find-file-name nil 'noprompt))) 1415 (lambda () (diff-find-file-name nil 'noprompt)))
1416 (add-function :filter-return (local 'filter-buffer-substring-function)
1417 #'diff--filter-substring)
1411 (unless (buffer-file-name) 1418 (unless (buffer-file-name)
1412 (hack-dir-local-variables-non-file-buffer))) 1419 (hack-dir-local-variables-non-file-buffer)))
1413 1420
@@ -2088,6 +2095,7 @@ Return new point, if it was moved."
2088 (diff--refine-hunk beg end) 2095 (diff--refine-hunk beg end)
2089 (let ((ol (make-overlay beg end))) 2096 (let ((ol (make-overlay beg end)))
2090 (overlay-put ol 'diff--font-lock-refined t) 2097 (overlay-put ol 'diff--font-lock-refined t)
2098 (overlay-put ol 'diff-mode 'fine)
2091 (overlay-put ol 'evaporate t) 2099 (overlay-put ol 'evaporate t)
2092 (overlay-put ol 'modification-hooks 2100 (overlay-put ol 'modification-hooks
2093 '(diff--font-lock-refine--refresh)))) 2101 '(diff--font-lock-refine--refresh))))
@@ -2204,19 +2212,80 @@ fixed, visit it in a buffer."
2204 2212
2205;;; Prettifying from font-lock 2213;;; Prettifying from font-lock
2206 2214
2215(define-fringe-bitmap 'diff-fringe-add
2216 [#b00000000
2217 #b00000000
2218 #b00010000
2219 #b00010000
2220 #b01111100
2221 #b00010000
2222 #b00010000
2223 #b00000000
2224 #b00000000]
2225 nil nil 'center)
2226
2227(define-fringe-bitmap 'diff-fringe-del
2228 [#b00000000
2229 #b00000000
2230 #b00000000
2231 #b00000000
2232 #b01111100
2233 #b00000000
2234 #b00000000
2235 #b00000000
2236 #b00000000]
2237 nil nil 'center)
2238
2239(define-fringe-bitmap 'diff-fringe-rep
2240 [#b00000000
2241 #b00010000
2242 #b00010000
2243 #b00010000
2244 #b00010000
2245 #b00010000
2246 #b00000000
2247 #b00010000
2248 #b00000000]
2249 nil nil 'center)
2250
2251(define-fringe-bitmap 'diff-fringe-nul
2252 ;; Maybe there should be such an "empty" bitmap defined by default?
2253 [#b00000000
2254 #b00000000
2255 #b00000000
2256 #b00000000
2257 #b00000000
2258 #b00000000
2259 #b00000000
2260 #b00000000
2261 #b00000000]
2262 nil nil 'center)
2263
2207(defun diff--font-lock-prettify (limit) 2264(defun diff--font-lock-prettify (limit)
2208 ;; Mimicks the output of Magit's diff.
2209 ;; FIXME: This has only been tested with Git's diff output.
2210 (when diff-font-lock-prettify 2265 (when diff-font-lock-prettify
2266 (save-excursion
2267 ;; FIXME: Include the first space for context-style hunks!
2268 (while (re-search-forward "^[-+! ]" limit t)
2269 (let ((spec (alist-get (char-before)
2270 '((?+ . (left-fringe diff-fringe-add diff-added))
2271 (?- . (left-fringe diff-fringe-del diff-removed))
2272 (?! . (left-fringe diff-fringe-rep diff-changed))
2273 (?\s . (left-fringe diff-fringe-nul))))))
2274 (put-text-property (match-beginning 0) (match-end 0) 'display spec))))
2275 ;; Mimicks the output of Magit's diff.
2276 ;; FIXME: This has only been tested with Git's diff output.
2211 (while (re-search-forward "^diff " limit t) 2277 (while (re-search-forward "^diff " limit t)
2278 ;; FIXME: Switching between context<->unified leads to messed up
2279 ;; file headers by cutting the `display' property in chunks!
2212 (when (save-excursion 2280 (when (save-excursion
2213 (forward-line 0) 2281 (forward-line 0)
2214 (looking-at (eval-when-compile 2282 (looking-at
2215 (concat "diff.*\n" 2283 (eval-when-compile
2216 "\\(?:\\(?:new file\\|deleted\\).*\n\\)?" 2284 (concat "diff.*\n"
2217 "\\(?:index.*\n\\)?" 2285 "\\(?:\\(?:new file\\|deleted\\).*\n\\)?"
2218 "--- \\(?:/dev/null\\|a/\\(.*\\)\\)\n" 2286 "\\(?:index.*\n\\)?"
2219 "\\+\\+\\+ \\(?:/dev/null\\|b/\\(.*\\)\\)\n")))) 2287 "--- \\(?:/dev/null\\|a/\\(.*\\)\\)\n"
2288 "\\+\\+\\+ \\(?:/dev/null\\|b/\\(.*\\)\\)\n"))))
2220 (put-text-property (match-beginning 0) 2289 (put-text-property (match-beginning 0)
2221 (or (match-beginning 2) (match-beginning 1)) 2290 (or (match-beginning 2) (match-beginning 1))
2222 'display (propertize 2291 'display (propertize
@@ -2230,6 +2299,28 @@ fixed, visit it in a buffer."
2230 'display ""))))) 2299 'display "")))))
2231 nil) 2300 nil)
2232 2301
2302(defun diff--filter-substring (str)
2303 (when diff-font-lock-prettify
2304 ;; Strip the `display' properties added by diff-font-lock-prettify,
2305 ;; since they look weird when you kill&yank!
2306 (remove-text-properties 0 (length str) '(display nil) str)
2307 ;; We could also try to only remove those `display' properties actually
2308 ;; added by diff-font-lock-prettify rather than removing them all blindly.
2309 ;; E.g.:
2310 ;;(let ((len (length str))
2311 ;; (i 0))
2312 ;; (while (and (< i len)
2313 ;; (setq i (text-property-not-all i len 'display nil str)))
2314 ;; (let* ((val (get-text-property i 'display str))
2315 ;; (end (or (text-property-not-all i len 'display val str) len)))
2316 ;; ;; FIXME: Check for display props that prettify the file header!
2317 ;; (when (eq 'left-fringe (car-safe val))
2318 ;; ;; FIXME: Should we check that it's a diff-fringe-* bitmap?
2319 ;; (remove-text-properties i end '(display nil) str))
2320 ;; (setq i end))))
2321 )
2322 str)
2323
2233;;; Support for converting a diff to diff3 markers via `wiggle'. 2324;;; Support for converting a diff to diff3 markers via `wiggle'.
2234 2325
2235;; Wiggle can be found at http://neil.brown.name/wiggle/ or in your nearest 2326;; Wiggle can be found at http://neil.brown.name/wiggle/ or in your nearest
@@ -2255,7 +2346,7 @@ conflict."
2255 (set-buffer (prog1 tmpbuf (setq tmpbuf (current-buffer)))) 2346 (set-buffer (prog1 tmpbuf (setq tmpbuf (current-buffer))))
2256 (when (buffer-modified-p filebuf) 2347 (when (buffer-modified-p filebuf)
2257 (save-some-buffers nil (lambda () (eq (current-buffer) filebuf))) 2348 (save-some-buffers nil (lambda () (eq (current-buffer) filebuf)))
2258 (if (buffer-modified-p filebuf) (error "Abort!"))) 2349 (if (buffer-modified-p filebuf) (user-error "Abort!")))
2259 (write-region (car bounds) (cadr bounds) patchfile nil 'silent) 2350 (write-region (car bounds) (cadr bounds) patchfile nil 'silent)
2260 (let ((exitcode 2351 (let ((exitcode
2261 (call-process "wiggle" nil (list tmpbuf errfile) nil 2352 (call-process "wiggle" nil (list tmpbuf errfile) nil