diff options
| author | Stephen Leake | 2019-04-11 14:00:02 -0700 |
|---|---|---|
| committer | Stephen Leake | 2019-04-11 14:00:02 -0700 |
| commit | 7ba7def5caf7ec9d9bebffff489f0a658229fbda (patch) | |
| tree | e0cfcb59937ca0528fb81769d7d48a904a91f5dc /lisp/vc/diff-mode.el | |
| parent | 7768581172e11be52b1fcd8224f4594e126bbdb7 (diff) | |
| parent | de238b39e335c6814283faa171b35145f124edf2 (diff) | |
| download | emacs-7ba7def5caf7ec9d9bebffff489f0a658229fbda.tar.gz emacs-7ba7def5caf7ec9d9bebffff489f0a658229fbda.zip | |
Merge commit 'de238b39e335c6814283faa171b35145f124edf2'
Diffstat (limited to 'lisp/vc/diff-mode.el')
| -rw-r--r-- | lisp/vc/diff-mode.el | 204 |
1 files changed, 115 insertions, 89 deletions
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index dbde284da84..8940c7e09a6 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el | |||
| @@ -116,7 +116,7 @@ You can always manually refine a hunk with `diff-refine-hunk'." | |||
| 116 | "If non-nil, diff hunk font-lock includes source language syntax highlighting. | 116 | "If non-nil, diff hunk font-lock includes source language syntax highlighting. |
| 117 | This highlighting is the same as added by `font-lock-mode' | 117 | This highlighting is the same as added by `font-lock-mode' |
| 118 | when corresponding source files are visited normally. | 118 | when corresponding source files are visited normally. |
| 119 | Syntax highlighting is added over diff own highlighted changes. | 119 | Syntax highlighting is added over diff-mode's own highlighted changes. |
| 120 | 120 | ||
| 121 | If t, the default, highlight syntax only in Diff buffers created by Diff | 121 | If t, the default, highlight syntax only in Diff buffers created by Diff |
| 122 | commands that compare files or by VC commands that compare revisions. | 122 | commands that compare files or by VC commands that compare revisions. |
| @@ -126,17 +126,17 @@ For diffs against the working-tree version of a file, the highlighting is | |||
| 126 | based on the current file contents. File-based fontification tries to | 126 | based on the current file contents. File-based fontification tries to |
| 127 | infer fontification from the compared files. | 127 | infer fontification from the compared files. |
| 128 | 128 | ||
| 129 | If revision-based or file-based method fails, use hunk-based method to get | 129 | If `hunk-only' fontification is based on hunk alone, without full source. |
| 130 | fontification from hunk alone if the value is `hunk-also'. | ||
| 131 | |||
| 132 | If `hunk-only', fontification is based on hunk alone, without full source. | ||
| 133 | It tries to highlight hunks without enough context that sometimes might result | 130 | It tries to highlight hunks without enough context that sometimes might result |
| 134 | in wrong fontification. This is the fastest option, but less reliable." | 131 | in wrong fontification. This is the fastest option, but less reliable. |
| 132 | |||
| 133 | If `hunk-also', use reliable file-based syntax highlighting when available | ||
| 134 | and hunk-based syntax highlighting otherwise as a fallback." | ||
| 135 | :version "27.1" | 135 | :version "27.1" |
| 136 | :type '(choice (const :tag "Don't highlight syntax" nil) | 136 | :type '(choice (const :tag "Don't highlight syntax" nil) |
| 137 | (const :tag "Hunk-based also" hunk-also) | ||
| 138 | (const :tag "Hunk-based only" hunk-only) | 137 | (const :tag "Hunk-based only" hunk-only) |
| 139 | (const :tag "Highlight syntax" t))) | 138 | (const :tag "Highlight syntax" t) |
| 139 | (const :tag "Allow hunk-based fallback" hunk-also))) | ||
| 140 | 140 | ||
| 141 | (defvar diff-vc-backend nil | 141 | (defvar diff-vc-backend nil |
| 142 | "The VC backend that created the current Diff buffer, if any.") | 142 | "The VC backend that created the current Diff buffer, if any.") |
| @@ -144,9 +144,8 @@ in wrong fontification. This is the fastest option, but less reliable." | |||
| 144 | (defvar diff-vc-revisions nil | 144 | (defvar diff-vc-revisions nil |
| 145 | "The VC revisions compared in the current Diff buffer, if any.") | 145 | "The VC revisions compared in the current Diff buffer, if any.") |
| 146 | 146 | ||
| 147 | (defvar diff-default-directory nil | 147 | (defvar-local diff-default-directory nil |
| 148 | "The default directory where the current Diff buffer was created.") | 148 | "The default directory where the current Diff buffer was created.") |
| 149 | (make-variable-buffer-local 'diff-default-directory) | ||
| 150 | 149 | ||
| 151 | (defvar diff-outline-regexp | 150 | (defvar diff-outline-regexp |
| 152 | "\\([*+][*+][*+] [^0-9]\\|@@ ...\\|\\*\\*\\* [0-9].\\|--- [0-9]..\\)") | 151 | "\\([*+][*+][*+] [^0-9]\\|@@ ...\\|\\*\\*\\* [0-9].\\|--- [0-9]..\\)") |
| @@ -2423,7 +2422,9 @@ When OLD is non-nil, highlight the hunk from the old source." | |||
| 2423 | (let* ((hunk (buffer-substring-no-properties beg end)) | 2422 | (let* ((hunk (buffer-substring-no-properties beg end)) |
| 2424 | ;; Trim a trailing newline to find hunk in diff-syntax-fontify-props | 2423 | ;; Trim a trailing newline to find hunk in diff-syntax-fontify-props |
| 2425 | ;; in diffs that have no newline at end of diff file. | 2424 | ;; in diffs that have no newline at end of diff file. |
| 2426 | (text (string-trim-right (or (with-demoted-errors (diff-hunk-text hunk (not old) nil)) ""))) | 2425 | (text (string-trim-right |
| 2426 | (or (with-demoted-errors (diff-hunk-text hunk (not old) nil)) | ||
| 2427 | ""))) | ||
| 2427 | (line (if (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?") | 2428 | (line (if (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?") |
| 2428 | (if old (match-string 1) | 2429 | (if old (match-string 1) |
| 2429 | (if (match-end 3) (match-string 3) (match-string 1))))) | 2430 | (if (match-end 3) (match-string 3) (match-string 1))))) |
| @@ -2432,83 +2433,106 @@ When OLD is non-nil, highlight the hunk from the old source." | |||
| 2432 | (list (string-to-number (match-string 1 line)) | 2433 | (list (string-to-number (match-string 1 line)) |
| 2433 | (string-to-number (match-string 2 line))) | 2434 | (string-to-number (match-string 2 line))) |
| 2434 | (list (string-to-number line) 1)))) ; One-line diffs | 2435 | (list (string-to-number line) 1)))) ; One-line diffs |
| 2435 | props) | 2436 | (props |
| 2436 | (cond | 2437 | (or |
| 2437 | ((and diff-vc-backend (not (eq diff-font-lock-syntax 'hunk-only))) | 2438 | (when (and diff-vc-backend |
| 2438 | (let* ((file (diff-find-file-name old t)) | 2439 | (not (eq diff-font-lock-syntax 'hunk-only))) |
| 2439 | (revision (and file (if (not old) (nth 1 diff-vc-revisions) | 2440 | (let* ((file (diff-find-file-name old t)) |
| 2440 | (or (nth 0 diff-vc-revisions) | 2441 | (revision (and file (if (not old) (nth 1 diff-vc-revisions) |
| 2441 | (vc-working-revision file)))))) | 2442 | (or (nth 0 diff-vc-revisions) |
| 2442 | (if file | 2443 | (vc-working-revision file)))))) |
| 2443 | (if (not revision) | 2444 | (when file |
| 2444 | ;; Get properties from the current working revision | 2445 | (if (not revision) |
| 2445 | (when (and (not old) (file-exists-p file) (file-regular-p file)) | 2446 | ;; Get properties from the current working revision |
| 2446 | ;; Try to reuse an existing buffer | 2447 | (when (and (not old) (file-exists-p file) |
| 2447 | (if (get-file-buffer (expand-file-name file)) | 2448 | (file-regular-p file)) |
| 2448 | (with-current-buffer (get-file-buffer (expand-file-name file)) | 2449 | (let ((buf (get-file-buffer (expand-file-name file)))) |
| 2449 | (setq props (diff-syntax-fontify-props nil text line-nb))) | 2450 | ;; Try to reuse an existing buffer |
| 2450 | ;; Get properties from the file | 2451 | (if buf |
| 2451 | (with-temp-buffer | 2452 | (with-current-buffer buf |
| 2452 | (insert-file-contents file) | 2453 | (diff-syntax-fontify-props nil text line-nb)) |
| 2453 | (setq props (diff-syntax-fontify-props file text line-nb))))) | 2454 | ;; Get properties from the file |
| 2454 | ;; Get properties from a cached revision | 2455 | (with-temp-buffer |
| 2455 | (let* ((buffer-name (format " *diff-syntax:%s.~%s~*" | 2456 | (insert-file-contents file) |
| 2456 | (expand-file-name file) revision)) | 2457 | (diff-syntax-fontify-props file text line-nb))))) |
| 2457 | (buffer (gethash buffer-name diff-syntax-fontify-revisions))) | 2458 | ;; Get properties from a cached revision |
| 2458 | (unless (and buffer (buffer-live-p buffer)) | 2459 | (let* ((buffer-name (format " *diff-syntax:%s.~%s~*" |
| 2459 | (let* ((vc-buffer (ignore-errors | 2460 | (expand-file-name file) |
| 2460 | (vc-find-revision-no-save | 2461 | revision)) |
| 2461 | (expand-file-name file) revision | 2462 | (buffer (gethash buffer-name |
| 2462 | diff-vc-backend | 2463 | diff-syntax-fontify-revisions))) |
| 2463 | (get-buffer-create buffer-name))))) | 2464 | (unless (and buffer (buffer-live-p buffer)) |
| 2464 | (when vc-buffer | 2465 | (let* ((vc-buffer (ignore-errors |
| 2465 | (setq buffer vc-buffer) | 2466 | (vc-find-revision-no-save |
| 2466 | (puthash buffer-name buffer diff-syntax-fontify-revisions)))) | 2467 | (expand-file-name file) revision |
| 2467 | (when buffer | 2468 | diff-vc-backend |
| 2468 | (with-current-buffer buffer | 2469 | (get-buffer-create buffer-name))))) |
| 2469 | (setq props (diff-syntax-fontify-props file text line-nb)))))) | 2470 | (when vc-buffer |
| 2470 | ;; If file is unavailable, get properties from the hunk alone | 2471 | (setq buffer vc-buffer) |
| 2471 | (setq file (car (diff-hunk-file-names old))) | 2472 | (puthash buffer-name buffer |
| 2472 | (with-temp-buffer | 2473 | diff-syntax-fontify-revisions)))) |
| 2473 | (insert text) | 2474 | (when buffer |
| 2474 | (setq props (diff-syntax-fontify-props file text line-nb t)))))) | 2475 | (with-current-buffer buffer |
| 2475 | ((and diff-default-directory (not (eq diff-font-lock-syntax 'hunk-only))) | 2476 | (diff-syntax-fontify-props file text line-nb)))))))) |
| 2476 | (let ((file (car (diff-hunk-file-names old)))) | 2477 | (let ((file (car (diff-hunk-file-names old)))) |
| 2477 | (if (and file (file-exists-p file) (file-regular-p file)) | 2478 | (cond |
| 2478 | ;; Try to get full text from the file | 2479 | ((and file diff-default-directory |
| 2479 | (with-temp-buffer | 2480 | (not (eq diff-font-lock-syntax 'hunk-only)) |
| 2480 | (insert-file-contents file) | 2481 | (not diff-vc-backend) |
| 2481 | (setq props (diff-syntax-fontify-props file text line-nb))) | 2482 | (file-readable-p file) (file-regular-p file)) |
| 2482 | ;; Otherwise, get properties from the hunk alone | 2483 | ;; Try to get full text from the file. |
| 2483 | (with-temp-buffer | 2484 | (with-temp-buffer |
| 2484 | (insert text) | 2485 | (insert-file-contents file) |
| 2485 | (setq props (diff-syntax-fontify-props file text line-nb t)))))) | 2486 | (diff-syntax-fontify-props file text line-nb))) |
| 2486 | ((memq diff-font-lock-syntax '(hunk-also hunk-only)) | 2487 | ;; Otherwise, get properties from the hunk alone |
| 2487 | (let ((file (car (diff-hunk-file-names old)))) | 2488 | ((memq diff-font-lock-syntax '(hunk-also hunk-only)) |
| 2488 | (with-temp-buffer | 2489 | (with-temp-buffer |
| 2489 | (insert text) | 2490 | (insert text) |
| 2490 | (setq props (diff-syntax-fontify-props file text line-nb t)))))) | 2491 | (diff-syntax-fontify-props file text line-nb t)))))))) |
| 2491 | 2492 | ||
| 2492 | ;; Put properties over the hunk text | 2493 | ;; Put properties over the hunk text |
| 2493 | (goto-char beg) | 2494 | (goto-char beg) |
| 2494 | (when (and props (eq (diff-hunk-style) 'unified)) | 2495 | (when (and props (eq (diff-hunk-style) 'unified)) |
| 2495 | (while (< (progn (forward-line 1) (point)) end) | 2496 | (while (< (progn (forward-line 1) (point)) end) |
| 2496 | (when (or (and (not old) (not (looking-at-p "[-<]"))) | 2497 | ;; Skip the "\ No newline at end of file" lines as well as the lines |
| 2497 | (and old (not (looking-at-p "[+>]")))) | 2498 | ;; corresponding to the "other" version. |
| 2498 | (unless (looking-at-p "\\\\") ; skip "\ No newline at end of file" | 2499 | (unless (looking-at-p (if old "[+>\\]" "[-<\\]")) |
| 2499 | (if (and old (not (looking-at-p "[-<]"))) | 2500 | (if (and old (not (looking-at-p "[-<]"))) |
| 2500 | ;; Fontify context lines only from new source, | 2501 | ;; Fontify context lines only from new source, |
| 2501 | ;; don't refontify context lines from old source. | 2502 | ;; don't refontify context lines from old source. |
| 2502 | (pop props) | 2503 | (pop props) |
| 2503 | (let ((line-props (pop props)) | 2504 | (let ((line-props (pop props)) |
| 2504 | (bol (1+ (point)))) | 2505 | (bol (1+ (point)))) |
| 2505 | (dolist (prop line-props) | 2506 | (dolist (prop line-props) |
| 2506 | (let ((ol (make-overlay (+ bol (nth 0 prop)) | 2507 | ;; Ideally, we'd want to use text-properties as in: |
| 2507 | (+ bol (nth 1 prop)) | 2508 | ;; |
| 2508 | nil 'front-advance nil))) | 2509 | ;; (add-face-text-property |
| 2509 | (overlay-put ol 'diff-mode 'syntax) | 2510 | ;; (+ bol (nth 0 prop)) (+ bol (nth 1 prop)) |
| 2510 | (overlay-put ol 'evaporate t) | 2511 | ;; (nth 2 prop) 'append) |
| 2511 | (overlay-put ol 'face (nth 2 prop)))))))))))) | 2512 | ;; |
| 2513 | ;; rather than overlays here, but they'd get removed by later | ||
| 2514 | ;; font-locking. | ||
| 2515 | ;; This is because we also apply faces outside of the | ||
| 2516 | ;; beg...end chunk currently font-locked and when font-lock | ||
| 2517 | ;; later comes to handle the rest of the hunk that we already | ||
| 2518 | ;; handled we don't (want to) redo it (we work at | ||
| 2519 | ;; hunk-granularity rather than font-lock's own chunk | ||
| 2520 | ;; granularity). | ||
| 2521 | ;; I see two ways to fix this: | ||
| 2522 | ;; - don't immediately apply the props that fall outside of | ||
| 2523 | ;; font-lock's chunk but stash them somewhere (e.g. in another | ||
| 2524 | ;; text property) and only later when font-lock comes back | ||
| 2525 | ;; move them to `face'. | ||
| 2526 | ;; - change the code so work at font-lock's chunk granularity | ||
| 2527 | ;; (this seems doable without too much extra overhead, | ||
| 2528 | ;; contrary to the refine highlighting, which inherently | ||
| 2529 | ;; works at a different granularity). | ||
| 2530 | (let ((ol (make-overlay (+ bol (nth 0 prop)) | ||
| 2531 | (+ bol (nth 1 prop)) | ||
| 2532 | nil 'front-advance nil))) | ||
| 2533 | (overlay-put ol 'diff-mode 'syntax) | ||
| 2534 | (overlay-put ol 'evaporate t) | ||
| 2535 | (overlay-put ol 'face (nth 2 prop))))))))))) | ||
| 2512 | 2536 | ||
| 2513 | (defun diff-syntax-fontify-props (file text line-nb &optional hunk-only) | 2537 | (defun diff-syntax-fontify-props (file text line-nb &optional hunk-only) |
| 2514 | "Get font-lock properties from the source code. | 2538 | "Get font-lock properties from the source code. |
| @@ -2516,21 +2540,23 @@ FILE is the name of the source file. If non-nil, it requests initialization | |||
| 2516 | of the mode according to FILE. | 2540 | of the mode according to FILE. |
| 2517 | TEXT is the literal source text from hunk. | 2541 | TEXT is the literal source text from hunk. |
| 2518 | LINE-NB is a pair of numbers: start line number and the number of | 2542 | LINE-NB is a pair of numbers: start line number and the number of |
| 2519 | lines in the hunk. NO-INIT means no initialization is needed to set major | 2543 | lines in the hunk. |
| 2520 | mode. When HUNK-ONLY is non-nil, then don't verify the existence of the | 2544 | When HUNK-ONLY is non-nil, then don't verify the existence of the |
| 2521 | hunk text in the source file. Otherwise, don't highlight the hunk if the | 2545 | hunk text in the source file. Otherwise, don't highlight the hunk if the |
| 2522 | hunk text is not found in the source file." | 2546 | hunk text is not found in the source file." |
| 2523 | (when file | 2547 | (when file |
| 2524 | ;; When initialization is requested, we should be in a brand new | 2548 | ;; When initialization is requested, we should be in a brand new |
| 2525 | ;; temp buffer. | 2549 | ;; temp buffer. |
| 2526 | (cl-assert (eq t buffer-undo-list)) | ||
| 2527 | (cl-assert (not font-lock-mode)) | ||
| 2528 | (cl-assert (null buffer-file-name)) | 2550 | (cl-assert (null buffer-file-name)) |
| 2529 | (let ((enable-local-variables :safe) ;; to find `mode:' | 2551 | (let ((enable-local-variables :safe) ;; to find `mode:' |
| 2530 | (buffer-file-name file)) | 2552 | (buffer-file-name file)) |
| 2531 | (set-auto-mode) | 2553 | (set-auto-mode) |
| 2532 | (when (and (memq 'generic-mode-find-file-hook find-file-hook) | 2554 | ;; FIXME: Is this really worth the trouble? |
| 2533 | (fboundp 'generic-mode-find-file-hook)) | 2555 | (when (and (fboundp 'generic-mode-find-file-hook) |
| 2556 | (memq #'generic-mode-find-file-hook | ||
| 2557 | ;; There's no point checking the buffer-local value, | ||
| 2558 | ;; we're in a fresh new buffer. | ||
| 2559 | (default-value 'find-file-hook))) | ||
| 2534 | (generic-mode-find-file-hook)))) | 2560 | (generic-mode-find-file-hook)))) |
| 2535 | 2561 | ||
| 2536 | (let ((font-lock-defaults (or font-lock-defaults '(nil t))) | 2562 | (let ((font-lock-defaults (or font-lock-defaults '(nil t))) |