From: Alan Mackenzie Date: Sat, 30 Nov 2019 21:22:55 +0000 (+0000) Subject: CC Mode. Fix fontification bug with unterminated quotes on adjacent lines X-Git-Tag: emacs-27.0.90~472 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=757e66afdc1cd4f0a261d368cafd5009e04084a4;p=emacs.git CC Mode. Fix fontification bug with unterminated quotes on adjacent lines In particular, with these unterminated quotes on each of two adjacent lines, the following text was spuriously fontified with string face. * lisp/progmodes/cc-defs.el (c-search-backward-char-property-with-value-on-char): New macro. * lisp/progmodes/cc-mode.el (c-clear-string-fences): Check whether there is an unmatched quote at a lower buffer position which should match the current quote, rather than wrongly assuming the latter is unmatched and marking it with a punctuation syntax. (c-font-lock-fontify-region): Ensure all pertinent parts of the buffer have string fence properties applied before performing any syntactic operations on it; in particular, this applies to a quote at an earlier buffer position which "matches" one inside the region about to be fontified. --- diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index 6a9371e6f19..c6818819e74 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -1340,6 +1340,29 @@ nil; point is then left undefined." (search-forward-regexp "\\(\n\\|.\\)") ; to set the match-data. (point)))) +(defmacro c-search-backward-char-property-with-value-on-char + (property value char &optional limit) + "Search backward for a text-property PROPERTY having value VALUE on a +character with value CHAR. +LIMIT bounds the search. The value comparison is done with `equal'. +PROPERTY must be a constant. + +Leave point just before the character, and set the match data on +this character, and return point. If the search fails, return +nil; point is then left undefined." + `(let ((char-skip (concat "^" (char-to-string ,char))) + (-limit- (or ,limit (point-min))) + (-value- ,value)) + (while + (and + (progn (skip-chars-backward char-skip -limit-) + (> (point) -limit-)) + (not (equal (c-get-char-property (1- (point)) ,property) -value-))) + (backward-char)) + (when (> (point) -limit-) + (search-backward-regexp "\\(\n\\|.\\)") ; to set the match-data. + (point)))) + (defmacro c-search-forward-char-property-without-value-on-char (property value char &optional limit) "Search forward for a character CHAR without text property PROPERTY having diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 73160fc7a42..7fcc8a6d1c5 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -1233,6 +1233,15 @@ Note that the style variables are always made local to the buffer." ;; Check we haven't left any unbalanced "s. (save-excursion (setq pos beg) + ;; Is there already an unbalanced " before BEG? + (setq pos (c-min-property-position pos end 'c-fl-syn-tab)) + (when (< pos end) (goto-char pos)) + (when (and (save-match-data + (c-search-backward-char-property-with-value-on-char + 'c-fl-syn-tab '(15) ?\" + (max (- (point) 500) (point-min)))) + (not (equal (c-get-char-property (point) 'syntax-table) '(1)))) + (setq pos (1+ pos))) (while (< pos end) (setq pos (c-min-property-position pos end 'c-fl-syn-tab)) @@ -2234,44 +2243,69 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") ;; line was fouled up by context fontification. (save-restriction (widen) - (let (new-beg new-end new-region case-fold-search) - (if (and c-in-after-change-fontification - (< beg c-new-END) (> end c-new-BEG)) - ;; Region and the latest after-change fontification region overlap. - ;; Determine the upper and lower bounds of our adjusted region - ;; separately. - (progn - (if (<= beg c-new-BEG) - (setq c-in-after-change-fontification nil)) - (setq new-beg - (if (and (>= beg (c-point 'bol c-new-BEG)) - (<= beg c-new-BEG)) - ;; Either jit-lock has accepted `c-new-BEG', or has - ;; (probably) extended the change region spuriously to - ;; BOL, which position likely has a syntactically - ;; different position. To ensure correct fontification, - ;; we start at `c-new-BEG', assuming any characters to the - ;; left of `c-new-BEG' on the line do not require - ;; fontification. - c-new-BEG - (setq new-region (c-before-context-fl-expand-region beg end) - new-end (cdr new-region)) - (car new-region))) - (setq new-end - (if (and (>= end (c-point 'bol c-new-END)) - (<= end c-new-END)) - c-new-END - (or new-end - (cdr (c-before-context-fl-expand-region beg end)))))) - ;; Context (etc.) fontification. - (setq new-region (c-before-context-fl-expand-region beg end) - new-beg (car new-region) new-end (cdr new-region))) - (c-save-buffer-state nil - (unwind-protect - (progn (c-restore-string-fences new-beg new-end) - (funcall (default-value 'font-lock-fontify-region-function) - new-beg new-end verbose)) - (c-clear-string-fences)))))) + (let (new-beg new-end new-region case-fold-search string-fence-beg lim) + ;; Check how far back we need to extend the region where we reapply the + ;; string fence syntax-table properties. These must be in place for the + ;; coming fontification operations. + (save-excursion + (goto-char (if c-in-after-change-fontification + (min beg c-new-BEG) + beg)) + (setq lim (max (- (point) 500) (point-min))) + (while + (progn + (skip-chars-backward "^\"" lim) + (or (bobp) (backward-char)) + (save-excursion + (eq (logand (skip-chars-backward "\\\\") 1) 1)))) + (setq string-fence-beg + (cond ((c-get-char-property (point) 'c-fl-syn-tab) + (point)) + (c-in-after-change-fontification + c-new-BEG) + (t beg))) + (c-save-buffer-state nil + ;; Temporarily reapply the string fence syntax-table properties. + (c-with-extended-string-fences + string-fence-beg (if c-in-after-change-fontification + (max end c-new-END) + end) + + (if (and c-in-after-change-fontification + (< beg c-new-END) (> end c-new-BEG)) + ;; Region and the latest after-change fontification region overlap. + ;; Determine the upper and lower bounds of our adjusted region + ;; separately. + (progn + (if (<= beg c-new-BEG) + (setq c-in-after-change-fontification nil)) + (setq new-beg + (if (and (>= beg (c-point 'bol c-new-BEG)) + (<= beg c-new-BEG)) + ;; Either jit-lock has accepted `c-new-BEG', or has + ;; (probably) extended the change region spuriously + ;; to BOL, which position likely has a + ;; syntactically different position. To ensure + ;; correct fontification, we start at `c-new-BEG', + ;; assuming any characters to the left of + ;; `c-new-BEG' on the line do not require + ;; fontification. + c-new-BEG + (setq new-region (c-before-context-fl-expand-region beg end) + new-end (cdr new-region)) + (car new-region))) + (setq new-end + (if (and (>= end (c-point 'bol c-new-END)) + (<= end c-new-END)) + c-new-END + (or new-end + (cdr (c-before-context-fl-expand-region beg end)))))) + ;; Context (etc.) fontification. + (setq new-region (c-before-context-fl-expand-region beg end) + new-beg (car new-region) new-end (cdr new-region))) + ;; Finally invoke font lock's functionality. + (funcall (default-value 'font-lock-fontify-region-function) + new-beg new-end verbose))))))) (defun c-after-font-lock-init () ;; Put on `font-lock-mode-hook'. This function ensures our after-change