aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/vc
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/vc')
-rw-r--r--lisp/vc/diff-mode.el204
-rw-r--r--lisp/vc/log-edit.el2
-rw-r--r--lisp/vc/vc.el17
3 files changed, 130 insertions, 93 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.
117This highlighting is the same as added by `font-lock-mode' 117This highlighting is the same as added by `font-lock-mode'
118when corresponding source files are visited normally. 118when corresponding source files are visited normally.
119Syntax highlighting is added over diff own highlighted changes. 119Syntax highlighting is added over diff-mode's own highlighted changes.
120 120
121If t, the default, highlight syntax only in Diff buffers created by Diff 121If t, the default, highlight syntax only in Diff buffers created by Diff
122commands that compare files or by VC commands that compare revisions. 122commands 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
126based on the current file contents. File-based fontification tries to 126based on the current file contents. File-based fontification tries to
127infer fontification from the compared files. 127infer fontification from the compared files.
128 128
129If revision-based or file-based method fails, use hunk-based method to get 129If `hunk-only' fontification is based on hunk alone, without full source.
130fontification from hunk alone if the value is `hunk-also'.
131
132If `hunk-only', fontification is based on hunk alone, without full source.
133It tries to highlight hunks without enough context that sometimes might result 130It tries to highlight hunks without enough context that sometimes might result
134in wrong fontification. This is the fastest option, but less reliable." 131in wrong fontification. This is the fastest option, but less reliable.
132
133If `hunk-also', use reliable file-based syntax highlighting when available
134and 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
2516of the mode according to FILE. 2540of the mode according to FILE.
2517TEXT is the literal source text from hunk. 2541TEXT is the literal source text from hunk.
2518LINE-NB is a pair of numbers: start line number and the number of 2542LINE-NB is a pair of numbers: start line number and the number of
2519lines in the hunk. NO-INIT means no initialization is needed to set major 2543lines in the hunk.
2520mode. When HUNK-ONLY is non-nil, then don't verify the existence of the 2544When HUNK-ONLY is non-nil, then don't verify the existence of the
2521hunk text in the source file. Otherwise, don't highlight the hunk if the 2545hunk text in the source file. Otherwise, don't highlight the hunk if the
2522hunk text is not found in the source file." 2546hunk 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)))
diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el
index 8bd1bbddb78..42710dd8dc9 100644
--- a/lisp/vc/log-edit.el
+++ b/lisp/vc/log-edit.el
@@ -350,7 +350,7 @@ The first subexpression is the actual text of the field.")
350(defun log-edit-goto-eoh () ;FIXME: Almost rfc822-goto-eoh! 350(defun log-edit-goto-eoh () ;FIXME: Almost rfc822-goto-eoh!
351 (goto-char (point-min)) 351 (goto-char (point-min))
352 (when (re-search-forward 352 (when (re-search-forward
353 "^\\([^[:alpha:]]\\|[[:alnum:]-]+[^[:alnum:]-:]\\)" nil 'move) 353 "^\\([^[:alpha:]]\\|[[:alnum:]-]+[^[:alnum:]-]\\)" nil 'move)
354 (goto-char (match-beginning 0)))) 354 (goto-char (match-beginning 0))))
355 355
356(defun log-edit--match-first-line (limit) 356(defun log-edit--match-first-line (limit)
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index e6f30c9f804..b992a8ebe09 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -1806,7 +1806,12 @@ Return t if the buffer had changes, nil otherwise."
1806 1806
1807;;;###autoload 1807;;;###autoload
1808(defun vc-version-diff (_files rev1 rev2) 1808(defun vc-version-diff (_files rev1 rev2)
1809 "Report diffs between REV1 and REV2 revisions of the fileset." 1809 "Report diffs between revisions REV1 and REV2 in the repository history.
1810This compares two revisions of the current fileset.
1811If REV1 is nil, it defaults to the current revision, i.e. revision
1812of the last commit.
1813If REV2 is nil, it defaults to the work tree, i.e. the current
1814state of each file in the fileset."
1810 (interactive (vc-diff-build-argument-list-internal)) 1815 (interactive (vc-diff-build-argument-list-internal))
1811 ;; All that was just so we could do argument completion! 1816 ;; All that was just so we could do argument completion!
1812 (when (and (not rev1) rev2) 1817 (when (and (not rev1) rev2)
@@ -1891,8 +1896,14 @@ The merge base is a common ancestor between REV1 and REV2 revisions."
1891 1896
1892;;;###autoload 1897;;;###autoload
1893(defun vc-version-ediff (files rev1 rev2) 1898(defun vc-version-ediff (files rev1 rev2)
1894 "Show differences between revisions of the fileset in the 1899 "Show differences between REV1 and REV2 of FILES using ediff.
1895repository history using ediff." 1900This compares two revisions of the files in FILES. Currently,
1901only a single file's revisions can be compared, i.e. FILES can
1902specify only one file name.
1903If REV1 is nil, it defaults to the current revision, i.e. revision
1904of the last commit.
1905If REV2 is nil, it defaults to the work tree, i.e. the current
1906state of each file in FILES."
1896 (interactive (vc-diff-build-argument-list-internal)) 1907 (interactive (vc-diff-build-argument-list-internal))
1897 ;; All that was just so we could do argument completion! 1908 ;; All that was just so we could do argument completion!
1898 (when (and (not rev1) rev2) 1909 (when (and (not rev1) rev2)