diff options
| author | Stefan Monnier | 2018-10-21 11:05:49 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2018-10-21 11:05:49 -0400 |
| commit | 17252062b03defe9eac6a510e88b87932ef400fe (patch) | |
| tree | 5dc9d05befd582c2eacb990186857eaffbc19cce | |
| parent | 67d3b40e0cba5f34b1c7aacc4e1ccea6300eae76 (diff) | |
| download | emacs-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.el | 119 |
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-> | |||
| 1358 | or vice versa with \\[diff-unified->context] and you can also reverse the direction of | 1365 | or vice versa with \\[diff-unified->context] and you can also reverse the direction of |
| 1359 | a diff with \\[diff-reverse-direction]. | 1366 | a 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 |