From 29ec1e48883dbdce8f9f81ac25d9ec38c474cdcb Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Wed, 27 Mar 2019 11:50:53 +0000 Subject: [PATCH] Improve C++ raw string fontification. Integrate the handling of raw string and ordinary string fontification. * lisp/progmodes/cc-defs.el (c-font-lock-flush) (c-search-forward-char-property-without-value-on-char): new macros. (c-point): In the 'eoll arm, check for eobp. (c-search-forward-char-property-with-value-on-char): Handle the &optional limit argument being nil. (c-clear-char-property-with-value-on-char-function) (c-clear-char-property-with-value-on-char): Return the position of the first cleared property. * lisp/progmodes/cc-engine.el (c-find-decl-prefix-search): Don't spuriously recognize the change of face at a ) as the start of a string (a "pseudo match"). (c-old-beg-rs c-old-end-rs): New variables. (c-raw-string-pos): Analyze raw string delimiters more carefully. (c-raw-string-in-end-delim): New function. (c-depropertize-raw-string): Largely rewritten. (c-before-change-check-raw-strings): New functionality: only remove the syntax-table text properties from raw strings whose delimiters are about to change. (c-propertize-raw-string-id): New function. (c-after-change-re-mark-raw-strings): Remove, incorporating functionality into other functions. (c-propertize-raw-string-opener): Largely rewritten. (c-after-change-re-mark-raw-strings): Removed. (c-after-change-unmark-raw-strings, c-after-change-unmark-raw-strings): New functions. * lisp/progmodes/cc-fonts.el (c-font-lock-raw-strings): Largely rewritten. * lisp/progmodes/cc-langs.el (c-before-font-lock-functions): Replace c-after-change-re-mark-unbalanced-strings by c-after-change-mark-abnormal-strings in the t, c+objc, c++ and java sections. Add c-after-change-unmark-raw-strings and remove c-after-change-re-mark-raw-strings from the c++ section. * lisp/progmodes/cc-mode.el (c-old-BEG c-old-END): Remove. (c-old-END-literality): New variable. (c-depropertize-CPP): Remove syntax-table properties from raw strings within macros. (c-before-change-check-unbalanced-strings): Call c-truncate-semi-nonlit-pos-cache to preserve the integrity of the cache. (c-before-change-check-unbalanced-strings): Call c-truncate-semi-nonlit-pos-cache, largely rewritten. (c-after-change-re-mark-unbalanced-strings): Renamed to c-after-change-mark-abnormal-strings. Call c-maybe-re-mark-raw-string. --- lisp/progmodes/cc-defs.el | 76 +++-- lisp/progmodes/cc-engine.el | 584 ++++++++++++++++++++++++++---------- lisp/progmodes/cc-fonts.el | 40 ++- lisp/progmodes/cc-langs.el | 10 +- lisp/progmodes/cc-mode.el | 90 +++--- 5 files changed, 562 insertions(+), 238 deletions(-) diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index 97272ca9d21..87ddf3ac1e2 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -212,6 +212,13 @@ This variant works around bugs in `eval-when-compile' in various `(cl-delete-duplicates ,cl-seq ,@cl-keys) `(delete-duplicates ,cl-seq ,@cl-keys)))) +(defmacro c-font-lock-flush (beg end) + "Declare the region BEG...END's fontification as out-of-date. +On XEmacs and older Emacsen, this refontifies that region immediately." + (if (fboundp 'font-lock-flush) + `(font-lock-flush ,beg ,end) + `(font-lock-fontify-region ,beg ,end))) + (defmacro c-point (position &optional point) "Return the value of certain commonly referenced POSITIONs relative to POINT. The current point is used if POINT isn't specified. POSITION can be @@ -258,10 +265,12 @@ to it is returned. This function does not modify the point or the mark." ((eq position 'eoll) `(save-excursion ,@(if point `((goto-char ,point))) - (while (progn - (end-of-line) - (prog1 (eq (logand 1 (skip-chars-backward "\\\\")) 1))) - (beginning-of-line 2)) + (while (and + (not (eobp)) + (progn + (end-of-line) + (prog1 (eq (logand 1 (skip-chars-backward "\\\\")) 1)))) + (forward-line)) (end-of-line) (point))) @@ -1214,7 +1223,7 @@ Leave point just after 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- ,limit) + (-limit- (or ,limit (point-max))) (-value- ,value)) (while (and @@ -1226,15 +1235,39 @@ nil; point is then left undefined." (search-forward-regexp ".") ; 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 +a value CHAR. +LIMIT bounds the search. The value comparison is done with `equal'. +PROPERTY must be a constant. + +Leave point just after 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-max))) + (-value- ,value)) + (while + (and + (progn (skip-chars-forward char-skip -limit-) + (< (point) -limit-)) + (equal (c-get-char-property (point) ,property) -value-)) + (forward-char)) + (when (< (point) -limit-) + (search-forward-regexp ".") ; to set the match-data. + (point)))) + (defun c-clear-char-property-with-value-on-char-function (from to property value char) "Remove all text-properties PROPERTY with value VALUE on characters with value CHAR from the region [FROM, TO), as tested by `equal'. These properties are assumed to be over individual characters, having been put there by c-put-char-property. POINT -remains unchanged." +remains unchanged. Return the position of the first removed +property, or nil." (let ((place from) - ) + first) (while ; loop round occurrences of (PROPERTY VALUE) (progn (while ; loop round changes in PROPERTY till we find VALUE @@ -1243,28 +1276,34 @@ remains unchanged." (not (equal (get-text-property place property) value))) (setq place (c-next-single-property-change place property nil to))) (< place to)) - (if (eq (char-after place) char) - (remove-text-properties place (1+ place) (cons property nil))) + (when (eq (char-after place) char) + (remove-text-properties place (1+ place) (cons property nil)) + (or first (setq first place))) ;; Do we have to do anything with stickiness here? - (setq place (1+ place))))) + (setq place (1+ place))) + first)) (defmacro c-clear-char-property-with-value-on-char (from to property value char) "Remove all text-properties PROPERTY with value VALUE on characters with value CHAR from the region [FROM, TO), as tested by `equal'. These properties are assumed to be over individual characters, having been put there by c-put-char-property. POINT -remains unchanged." +remains unchanged. Return the position of the first removed +property, or nil." (if c-use-extents ;; XEmacs `(let ((-property- ,property) - (-char- ,char)) + (-char- ,char) + (first (1+ (point-max)))) (map-extents (lambda (ext val) - (if (and (equal (extent-property ext -property-) val) - (eq (char-after - (extent-start-position ext)) - -char-)) - (delete-extent ext))) - nil ,from ,to ,value nil -property-)) + (when (and (equal (extent-property ext -property-) val) + (eq (char-after + (extent-start-position ext)) + -char-)) + (setq first (min first (extent-start-position ext))) + (delete-extent ext))) + nil ,from ,to ,value nil -property-) + (and (<= first (point-max)) first)) ;; GNU Emacs `(c-clear-char-property-with-value-on-char-function ,from ,to ,property ,value ,char))) @@ -1316,6 +1355,7 @@ with value CHAR in the region [FROM to)." ;(eval-after-load "edebug" ; 2006-07-09: def-edebug-spec is now in subr.el. ; '(progn (def-edebug-spec cc-eval-when-compile (&rest def-form)) +(def-edebug-spec c-font-lock-flush t) (def-edebug-spec c--mapcan t) (def-edebug-spec c--set-difference (form form &rest [symbolp form])) (def-edebug-spec c--intersection (form form &rest [symbolp form])) diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index cc3753a7ebd..1a8c5164906 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -5646,8 +5646,12 @@ comment at the start of cc-engine.el for more info." ;; Pseudo match inside a comment or string literal. Skip out ;; of comments and string literals. (while (progn - (goto-char (c-next-single-property-change - (point) 'face nil cfd-limit)) + (unless + (and (match-end 1) + (c-got-face-at (1- (point)) c-literal-faces) + (not (c-got-face-at (point) c-literal-faces))) + (goto-char (c-next-single-property-change + (point) 'face nil cfd-limit))) (and (< (point) cfd-limit) (c-got-face-at (point) c-literal-faces)))) t) ; Continue the loop over pseudo matches. @@ -6350,9 +6354,8 @@ comment at the start of cc-engine.el for more info." ;; Set by c-common-init in cc-mode.el. (defvar c-new-BEG) (defvar c-new-END) -;; Set by c-after-change in cc-mode.el. -(defvar c-old-BEG) -(defvar c-old-END) +;; Set by c-before-change-check-raw-strings. +(defvar c-old-END-literality) (defun c-before-change-check-<>-operators (beg end) ;; Unmark certain pairs of "< .... >" which are currently marked as @@ -6484,9 +6487,9 @@ comment at the start of cc-engine.el for more info." ;; A valid C++ raw string looks like ;; R"()" ;; , where is an identifier from 0 to 16 characters long, not containing -;; spaces, control characters, double quote or left/right paren. -;; can include anything which isn't the terminating )", including new -;; lines, "s, parentheses, etc. +;; spaces, control characters, or left/right paren. can include +;; anything which isn't the terminating )", including new lines, "s, +;; parentheses, etc. ;; ;; CC Mode handles C++ raw strings by the use of `syntax-table' text ;; properties as follows: @@ -6496,16 +6499,18 @@ comment at the start of cc-engine.el for more info." ;; contents is given the property value "punctuation" (`(1)') to prevent it ;; interacting with the "s in the delimiters. ;; -;; The font locking routine `c-font-lock-c++-raw-strings' (in cc-fonts.el) +;; The font locking routine `c-font-lock-raw-strings' (in cc-fonts.el) ;; recognizes valid raw strings, and fontifies the delimiters (apart from ;; the parentheses) with the default face and the parentheses and the ;; with font-lock-string-face. ;; ;; (ii) A valid, but unterminated, raw string opening delimiter gets the ;; "punctuation" value (`(1)') of the `syntax-table' text property, and the -;; open parenthesis gets the "string fence" value (`(15)'). +;; open parenthesis gets the "string fence" value (`(15)'). When such a +;; delimiter is found, no attempt is made in any way to "correct" any text +;; properties after the delimiter. ;; -;; `c-font-lock-c++-raw-strings' puts c-font-lock-warning-face on the entire +;; `c-font-lock-raw-strings' puts c-font-lock-warning-face on the entire ;; unmatched opening delimiter (from the R up to the open paren), and allows ;; the rest of the buffer to get font-lock-string-face, caused by the ;; unmatched "string fence" `syntax-table' text property value. @@ -6522,10 +6527,14 @@ comment at the start of cc-engine.el for more info." ;; already at the end of the macro, it gets the "punctuation" value, and no ;; "string fence"s are used. ;; -;; The effect on the fontification of either of these tactics is that rest of -;; the macro (if any) after the "(" gets font-lock-string-face, but the rest -;; of the file is fontified normally. +;; The effect on the fontification of either of these tactics is that the +;; rest of the macro (if any) after the "(" gets font-lock-string-face, but +;; the rest of the file is fontified normally. +;; The values of the function `c-raw-string-pos' at before-change-functions' +;; BEG and END. +(defvar c-old-beg-rs nil) +(defvar c-old-end-rs nil) (defun c-raw-string-pos () ;; Get POINT's relationship to any containing raw string. @@ -6542,7 +6551,7 @@ comment at the start of cc-engine.el for more info." ;; characters.) If the raw string is not terminated, E\) and E\" are set to ;; nil. ;; - ;; Note: this routine is dependant upon the correct syntax-table text + ;; Note: this function is dependant upon the correct syntax-table text ;; properties being set. (let ((state (c-state-semi-pp-to-literal (point))) open-quote-pos open-paren-pos close-paren-pos close-quote-pos id) @@ -6555,8 +6564,20 @@ comment at the start of cc-engine.el for more info." (search-backward "\"" (max (- (point) 17) (point-min)) t))) ((and (eq (cadr state) 'string) (goto-char (nth 2 state)) - (or (eq (char-after) ?\") - (search-backward "\"" (max (- (point) 17) (point-min)) t)) + (cond + ((eq (char-after) ?\")) + ((eq (char-after) ?\() + (let ((here (point))) + (goto-char (max (- (point) 18) (point-min))) + (while + (and + (search-forward-regexp + "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" + (1+ here) 'limit) + (< (point) here))) + (and (eq (point) (1+ here)) + (match-beginning 1) + (goto-char (1- (match-beginning 1))))))) (not (bobp))))) (eq (char-before) ?R) (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(")) @@ -6579,6 +6600,21 @@ comment at the start of cc-engine.el for more info." (t nil)) open-quote-pos open-paren-pos close-paren-pos close-quote-pos)))) +(defun c-raw-string-in-end-delim (beg end) + ;; If the region (BEG END) intersects a possible raw string terminator, + ;; return a cons of the position of the ) and the position of the " in the + ;; first one found. + (save-excursion + (goto-char (max (- beg 17) (point-min))) + (while + (and + (search-forward-regexp ")\\([^ ()\\\n\r\t]\\{0,16\\}\\)\"" + (min (+ end 17) (point-max)) t) + (<= (point) beg))) + (unless (or (<= (point) beg) + (>= (match-beginning 0) end)) + (cons (match-beginning 0) (match-end 1))))) + (defun c-depropertize-raw-string (id open-quote open-paren bound) ;; Point is immediately after a raw string opening delimiter. Remove any ;; `syntax-table' text properties associated with the delimiter (if it's @@ -6587,29 +6623,55 @@ comment at the start of cc-engine.el for more info." ;; ID, a string, is the delimiter's identifier. OPEN-QUOTE and OPEN-PAREN ;; are the buffer positions of the delimiter's components. BOUND is the ;; bound for searching for a matching closing delimiter; it is usually nil, - ;; but if we're inside a macro, it's the end of the macro. + ;; but if we're inside a macro, it's the end of the macro (i.e. just before + ;; the terminating \n). ;; ;; Point is moved to after the (terminated) raw string, or left after the ;; unmatched opening delimiter, as the case may be. The return value is of ;; no significance. - (let ((open-paren-prop (c-get-char-property open-paren 'syntax-table))) + (let ((open-paren-prop (c-get-char-property open-paren 'syntax-table)) + first) + ;; If the delimiter is "unclosed", or sombody's used " in their id, clear + ;; the 'syntax-table property from all of them. + (setq first (c-clear-char-property-with-value-on-char + open-quote open-paren 'syntax-table '(1) ?\")) + (if first (c-truncate-semi-nonlit-pos-cache first)) (cond ((null open-paren-prop) - ;; A terminated raw string + ;; Should be a terminated raw string... (when (search-forward (concat ")" id "\"") nil t) + ;; Yes, it is. :-) + ;; Clear any '(1)s from "s in the identifier. + (setq first (c-clear-char-property-with-value-on-char + (1+ (match-beginning 0)) (1- (match-end 0)) + 'syntax-table '(1) ?\")) + (if first (c-truncate-semi-nonlit-pos-cache first)) + ;; Clear any random `syntax-table' text properties from the contents. (let* ((closing-paren (match-beginning 0)) - (first-punctuation - (save-match-data - (goto-char (1+ open-paren)) - (and (c-search-forward-char-property 'syntax-table '(1) - closing-paren) - (1- (point))))) - ) - (when first-punctuation - (c-clear-char-property-with-value - first-punctuation (match-beginning 0) 'syntax-table '(1)) - (c-truncate-semi-nonlit-pos-cache first-punctuation) - )))) + (first-st + (and + (< (1+ open-paren) closing-paren) + (or + (and (c-get-char-property (1+ open-paren) 'syntax-table) + (1+ open-paren)) + (and + (setq first + (c-next-single-property-change + (1+ open-paren) 'syntax-table nil closing-paren)) + (< first closing-paren) + first))))) + (when first-st + (c-clear-char-properties first-st (match-beginning 0) + 'syntax-table) + (c-truncate-semi-nonlit-pos-cache first-st)) + (when (c-get-char-property (1- (match-end 0)) 'syntax-table) + ;; Was previously an unterminated (ordinary) string + (save-excursion + (goto-char (1- (match-end 0))) + (when (c-safe (c-forward-sexp)) ; to '(1) at EOL. + (c-clear-char-property (1- (point)) 'syntax-table)) + (c-clear-char-property (1- (match-end 0)) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (1- (match-end 0)))))))) ((or (and (equal open-paren-prop '(15)) (null bound)) (equal open-paren-prop '(1))) ;; An unterminated raw string either not in a macro, or in a macro with @@ -6623,13 +6685,8 @@ comment at the start of cc-engine.el for more info." (c-clear-char-property open-quote 'syntax-table) (c-truncate-semi-nonlit-pos-cache open-quote) (c-clear-char-property open-paren 'syntax-table) - (let ((after-string-fence-pos - (save-excursion - (goto-char (1+ open-paren)) - (c-search-forward-char-property 'syntax-table '(15) bound)))) - (when after-string-fence-pos - (c-clear-char-property (1- after-string-fence-pos) 'syntax-table))) - )))) + (c-clear-char-property-with-value (1+ open-paren) bound 'syntax-table + '(15)))))) (defun c-depropertize-raw-strings-in-region (start finish) ;; Remove any `syntax-table' text properties associated with C++ raw strings @@ -6669,37 +6726,89 @@ comment at the start of cc-engine.el for more info." (defun c-before-change-check-raw-strings (beg end) ;; This function clears `syntax-table' text properties from C++ raw strings - ;; in the region (c-new-BEG c-new-END). BEG and END are the standard - ;; arguments supplied to any before-change function. + ;; whose delimiters are about to change in the region (c-new-BEG c-new-END). + ;; BEG and END are the standard arguments supplied to any before-change + ;; function. ;; ;; Point is undefined on both entry and exit, and the return value has no ;; significance. ;; ;; This function is called as a before-change function solely due to its ;; membership of the C++ value of `c-get-state-before-change-functions'. + (goto-char end) + ;; We use the following to detect a R"( being swallowed into a string by + ;; the pending change. + (setq c-old-END-literality (c-in-literal)) (c-save-buffer-state - ((beg-rs (progn (goto-char beg) (c-raw-string-pos))) - (beg-plus (if (null beg-rs) - beg - (max beg - (1+ (or (nth 4 beg-rs) (nth 2 beg-rs)))))) - (end-rs (progn (goto-char end) (c-raw-string-pos))) ; FIXME!!! + (;; (beg-rs (progn (goto-char beg) (c-raw-string-pos))) + ;; (end-rs (progn (goto-char end) (c-raw-string-pos))) + ; FIXME!!! ; Optimize this so that we don't call ; `c-raw-string-pos' twice when once ; will do. (2016-06-02). - (end-minus (if (null end-rs) - end - (min end (cadr end-rs)))) - ) - (when beg-rs - (setq c-new-BEG (min c-new-BEG (1- (cadr beg-rs))))) - (c-depropertize-raw-strings-in-region c-new-BEG beg-plus) - - (when end-rs - (setq c-new-END (max c-new-END - (1+ (or (nth 4 end-rs) - (nth 2 end-rs)))))) - (c-depropertize-raw-strings-in-region end-minus c-new-END))) + (term-del (c-raw-string-in-end-delim beg end)) + Rquote close-quote) + (setq c-old-beg-rs (progn (goto-char beg) (c-raw-string-pos)) + c-old-end-rs (progn (goto-char end) (c-raw-string-pos))) + (cond + ;; We're not changing, or we're obliterating raw strings. + ((and (null c-old-beg-rs) (null c-old-end-rs))) + ;; We're changing the putative terminating delimiter of a raw string + ;; containing BEG. + ((and c-old-beg-rs term-del + (or (null (nth 3 c-old-beg-rs)) + (<= (car term-del) (nth 3 c-old-beg-rs)))) + (setq Rquote (1- (cadr c-old-beg-rs)) + close-quote (1+ (cdr term-del))) + (c-depropertize-raw-strings-in-region Rquote close-quote) + (setq c-new-BEG (min c-new-BEG Rquote) + c-new-END (max c-new-END close-quote))) + ;; We're breaking an escaped NL in a raw string in a macro. + ((and c-old-end-rs + (< beg end) + (goto-char end) (eq (char-before) ?\\) + (c-beginning-of-macro)) + (let ((bom (point)) + (eom (progn (c-end-of-macro) (point)))) + (c-depropertize-raw-strings-in-region bom eom) + (setq c-new-BEG (min c-new-BEG bom) + c-new-END (max c-new-END eom)))) + ;; We're changing only the contents of a raw string. + ((and (equal (cdr c-old-beg-rs) (cdr c-old-end-rs)) + (null (car c-old-beg-rs)) (null (car c-old-end-rs)))) + ((or + ;; We're removing (at least part of) the R" of the starting delim of a + ;; raw string: + (null c-old-beg-rs) + (and (eq beg (cadr c-old-beg-rs)) + (< beg end)) + ;; Or we're removing the ( of the starting delim of a raw string. + (and (eq (car c-old-beg-rs) 'open-delim) + (or (null c-old-end-rs) + (not (eq (car c-old-end-rs) 'open-delim)) + (not (equal (cdr c-old-beg-rs) (cdr c-old-end-rs)))))) + (let ((close (nth 4 (or c-old-end-rs c-old-beg-rs)))) + (setq Rquote (1- (cadr (or c-old-end-rs c-old-beg-rs))) + close-quote (if close (1+ close) (point-max)))) + (c-depropertize-raw-strings-in-region Rquote close-quote) + (setq c-new-BEG (min c-new-BEG Rquote) + c-new-END (max c-new-END close-quote))) + ;; We're changing only the text of the identifier of the opening + ;; delimiter of a raw string. + ((and (eq (car c-old-beg-rs) 'open-delim) + (equal c-old-beg-rs c-old-end-rs)))))) + +(defun c-propertize-raw-string-id (start end) + ;; If the raw string identifier between buffer positions START and END + ;; contains any double quote characters, put a punctuation syntax-table text + ;; property on them. The return value is of no significance. + (save-excursion + (goto-char start) + (while (and (skip-chars-forward "^\"" end) + (< (point) end)) + (c-put-char-property (point) 'syntax-table '(1)) + (c-truncate-semi-nonlit-pos-cache (point)) + (forward-char)))) (defun c-propertize-raw-string-opener (id open-quote open-paren bound) ;; Point is immediately after a raw string opening delimiter. Apply any @@ -6709,117 +6818,264 @@ comment at the start of cc-engine.el for more info." ;; ID, a string, is the delimiter's identifier. OPEN-QUOTE and OPEN-PAREN ;; are the buffer positions of the delimiter's components. BOUND is the ;; bound for searching for a matching closing delimiter; it is usually nil, - ;; but if we're inside a macro, it's the end of the macro. - ;; - ;; Point is moved to after the (terminated) raw string, or left after the - ;; unmatched opening delimiter, as the case may be. The return value is of - ;; no significance. - (if (search-forward (concat ")" id "\"") bound t) - (let ((end-string (match-beginning 0)) - (after-quote (match-end 0))) - (goto-char open-paren) - (while (progn (skip-syntax-forward "^\"" end-string) - (< (point) end-string)) - (c-put-char-property (point) 'syntax-table '(1)) ; punctuation - (c-truncate-semi-nonlit-pos-cache (point)) - (forward-char)) - (goto-char after-quote)) - (c-put-char-property open-quote 'syntax-table '(1)) ; punctuation - (c-truncate-semi-nonlit-pos-cache open-quote) - (c-put-char-property open-paren 'syntax-table '(15)) ; generic string - (when bound - ;; In a CPP construct, we try to apply a generic-string `syntax-table' - ;; text property to the last possible character in the string, so that - ;; only characters within the macro get "stringed out". - (goto-char bound) - (if (save-restriction - (narrow-to-region (1+ open-paren) (point-max)) - (re-search-backward - (eval-when-compile - ;; This regular expression matches either an escape pair (which - ;; isn't an escaped NL) (submatch 5) or a non-escaped character - ;; (which isn't itself a backslash) (submatch 10). The long - ;; preambles to these (respectively submatches 2-4 and 6-9) - ;; ensure that we have the correct parity for sequences of - ;; backslashes, etc.. - (concat "\\(" ; 1 - "\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)*" ; 2-4 - "\\(\\\\.\\)" ; 5 - "\\|" - "\\(\\`\\|[^\\]\\|\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)+\\)" ; 6-9 - "\\([^\\]\\)" ; 10 - "\\)" - "\\(\\\\\n\\)*\\=")) ; 11 - (1+ open-paren) t)) - (if (match-beginning 10) - (progn - (c-put-char-property (match-beginning 10) 'syntax-table '(15)) - (c-truncate-semi-nonlit-pos-cache (match-beginning 10))) - (c-put-char-property (match-beginning 5) 'syntax-table '(1)) - (c-put-char-property (1+ (match-beginning 5)) 'syntax-table '(15)) - (c-truncate-semi-nonlit-pos-cache (1+ (match-beginning 5)))) - (c-put-char-property open-paren 'syntax-table '(1))) - (goto-char bound)))) - -(defun c-after-change-re-mark-raw-strings (_beg _end _old-len) - ;; This function applies `syntax-table' text properties to C++ raw strings - ;; beginning in the region (c-new-BEG c-new-END). BEG, END, and OLD-LEN are - ;; the standard arguments supplied to any after-change function. + ;; but if we're inside a macro, it's the end of the macro (i.e. the position + ;; of the closing newline). + ;; + ;; Point is moved to after the (terminated) raw string and t is returned, or + ;; it is left after the unmatched opening delimiter and nil is returned. + (c-propertize-raw-string-id (1+ open-quote) open-paren) + (prog1 + (if (search-forward (concat ")" id "\"") bound t) + (let ((end-string (match-beginning 0)) + (after-quote (match-end 0))) + (c-propertize-raw-string-id + (1+ (match-beginning 0)) (1- (match-end 0))) + (goto-char open-paren) + (while (progn (skip-syntax-forward "^\"" end-string) + (< (point) end-string)) + (c-put-char-property (point) 'syntax-table '(1)) ; punctuation + (c-truncate-semi-nonlit-pos-cache (point)) + (forward-char)) + (goto-char after-quote) + t) + (c-put-char-property open-quote 'syntax-table '(1)) ; punctuation + (c-truncate-semi-nonlit-pos-cache open-quote) + (c-put-char-property open-paren 'syntax-table '(15)) ; generic string + (when bound + ;; In a CPP construct, we try to apply a generic-string + ;; `syntax-table' text property to the last possible character in + ;; the string, so that only characters within the macro get + ;; "stringed out". + (goto-char bound) + (if (save-restriction + (narrow-to-region (1+ open-paren) (point-max)) + (re-search-backward + (eval-when-compile + ;; This regular expression matches either an escape pair + ;; (which isn't an escaped NL) (submatch 5) or a + ;; non-escaped character (which isn't itself a backslash) + ;; (submatch 10). The long preambles to these + ;; (respectively submatches 2-4 and 6-9) ensure that we + ;; have the correct parity for sequences of backslashes, + ;; etc.. + (concat "\\(" ; 1 + "\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)*" ; 2-4 + "\\(\\\\.\\)" ; 5 + "\\|" + "\\(\\`\\|[^\\]\\|\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)+\\)" ; 6-9 + "\\([^\\]\\)" ; 10 + "\\)" + "\\(\\\\\n\\)*\\=")) ; 11 + (1+ open-paren) t)) + (if (match-beginning 10) + (progn + (c-put-char-property (match-beginning 10) 'syntax-table '(15)) + (c-truncate-semi-nonlit-pos-cache (match-beginning 10))) + (c-put-char-property (match-beginning 5) 'syntax-table '(1)) + (c-put-char-property (1+ (match-beginning 5)) 'syntax-table '(15)) + (c-truncate-semi-nonlit-pos-cache (1+ (match-beginning 5)))) + ;; (c-put-char-property open-paren 'syntax-table '(1)) + ) + (goto-char bound)) + nil) + ;; Ensure the opening delimiter will get refontified. + (c-font-lock-flush (1- open-quote) (1+ open-paren)))) + +(defun c-after-change-unmark-raw-strings (beg end _old-len) + ;; This function removes `syntax-table' text properties from any raw strings + ;; which have been affected by the current change. These are those which + ;; have been "stringed out" and from newly formed raw strings, or any + ;; existing raw string which the new text terminates. BEG, END, and + ;; _OLD-LEN are the standard arguments supplied to any + ;; after-change-function. ;; ;; Point is undefined on both entry and exit, and the return value has no ;; significance. ;; - ;; This function is called as an after-change function solely due to its + ;; This functions is called as an after-change function by virtue of its ;; membership of the C++ value of `c-before-font-lock-functions'. - (c-save-buffer-state () - ;; If the region (c-new-BEG c-new-END) has expanded, remove - ;; `syntax-table' text-properties from the new piece(s). - (when (< c-new-BEG c-old-BEG) - (let ((beg-rs (progn (goto-char c-old-BEG) (c-raw-string-pos)))) - (c-depropertize-raw-strings-in-region - c-new-BEG - (if beg-rs - (1+ (or (nth 4 beg-rs) (nth 2 beg-rs))) - c-old-BEG)))) - (when (> c-new-END c-old-END) - (let ((end-rs (progn (goto-char c-old-END) (c-raw-string-pos)))) - (c-depropertize-raw-strings-in-region - (if end-rs - (cadr end-rs) - c-old-END) - c-new-END))) + ;; (when (< beg end) + (c-save-buffer-state (found eoll state id found-beg found-end) + ;; Has an inserted " swallowed up a R"(, turning it into "...R"(? + (goto-char end) + (setq eoll (c-point 'eoll)) + (when (and (null c-old-END-literality) + (search-forward-regexp "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" + eoll t)) + (setq state (c-state-semi-pp-to-literal end)) + (when (eq (cadr state) 'string) + (unwind-protect + ;; Temporarily insert a closing string delimiter.... + (progn + (goto-char end) + (cond + ((c-characterp (nth 3 (car state))) + (insert (nth 3 (car state)))) + ((eq (nth 3 (car state)) t) + (insert ?\") + (c-put-char-property end 'syntax-table '(15)))) + (c-truncate-semi-nonlit-pos-cache end) + ;; ....ensure c-new-END extends right to the end of the about + ;; to be un-stringed raw string.... + (save-excursion + (goto-char (match-beginning 1)) + (let ((end-bs (c-raw-string-pos))) + (setq c-new-END + (max c-new-END + (if (nth 4 end-bs) + (1+ (nth 4 end-bs)) + eoll))))) + + ;; ...and clear `syntax-table' text propertes from the + ;; following raw strings. + (c-depropertize-raw-strings-in-region (point) (1+ eoll))) + ;; Remove the temporary string delimiter. + (goto-char end) + (delete-char 1)))) + + ;; Have we just created a new starting id? + (goto-char (max (- beg 18) (point-min))) + (while + (and + (setq found + (search-forward-regexp "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" + c-new-END 'bound)) + (<= (match-end 0) beg))) + (when (and found (<= (match-beginning 0) end)) + (setq c-new-BEG (min c-new-BEG (match-beginning 0))) + (c-depropertize-raw-strings-in-region c-new-BEG c-new-END)) + + ;; Have we invalidated an opening delimiter by typing into it? + (when (and c-old-beg-rs + (eq (car c-old-beg-rs) 'open-delim) + (equal (c-get-char-property (cadr c-old-beg-rs) + 'syntax-table) + '(1))) + (goto-char (1- (cadr c-old-beg-rs))) + (unless (looking-at "R\"[^ ()\\\n\r\t]\\{0,16\\}(") + (c-clear-char-property (1+ (point)) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (1+ (point))) + (if (c-search-forward-char-property 'syntax-table '(15) + (c-point 'eol)) + (c-clear-char-property (1- (point)) 'syntax-table)))) + + ;; Have we terminated an existing raw string by inserting or removing + ;; text? + (when (eq c-old-END-literality 'string) + (setq state (c-state-semi-pp-to-literal beg)) + (cond + ;; Possibly terminating a(n un)terminated raw string. + ((eq (nth 3 (car state)) t) + (goto-char (nth 8 (car state))) + (when + (and (eq (char-after) ?\() + (search-backward-regexp + "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)\\=" (- (point) 18) t)) + (setq id (match-string-no-properties 1) + found-beg (match-beginning 0) + found-end (1+ (match-end 0))))) + ;; Possibly terminating an already terminated raw string. + ((eq (nth 3 (car state)) ?\") + (goto-char (nth 8 (car state))) + (when + (and (eq (char-before) ?R) + (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(")) + (setq id (match-string-no-properties 1) + found-beg (1- (point)) + found-end (match-end 0))))) + (when id + (goto-char (max (- beg 18) (point-min))) + (when (search-forward (concat ")" id "\"") (+ end 1 (length id)) t) + ;; Has an earlier close delimiter just been inserted into an + ;; already terminated raw string? + (if (and (eq (nth 3 (car state)) ?\") + (search-forward (concat ")" id "\"") nil t)) + (setq found-end (point))) + (setq c-new-BEG (min c-new-BEG found-beg) + c-new-END (max c-new-END found-end)) + (c-clear-char-properties found-beg found-end 'syntax-table) + (c-truncate-semi-nonlit-pos-cache found-beg)))) + + ;; Are there any raw strings in a newly created macro? + (when (< beg end) + (goto-char beg) + (setq found-beg (point)) + (when (search-forward-regexp c-anchored-cpp-prefix end t) + (c-end-of-macro) + (c-depropertize-raw-strings-in-region found-beg (point)))))) - (goto-char c-new-BEG) - (while (and (< (point) c-new-END) - (re-search-forward - (concat "\\(" ; 1 - c-anchored-cpp-prefix ; 2 - "\\)\\|\\(" ; 3 - "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" ; 4 - "\\)") - c-new-END t)) - (when (save-excursion - (goto-char (match-beginning 0)) (not (c-in-literal))) - (if (match-beginning 4) ; the id - ;; We've found a raw string. +(defun c-maybe-re-mark-raw-string () + ;; When this function is called, point is immediately after a ". If this " + ;; is the characteristic " of of a raw string delimiter, apply the pertinent + ;; `syntax-table' text properties to the entire raw string (when properly + ;; terminated) or just the delimiter (otherwise). + ;; + ;; If the " is in any way part of a raw string, return non-nil. Otherwise + ;; return nil. + (let ((here (point)) + in-macro macro-end id Rquote found) + (cond + ((and + (eq (char-before (1- (point))) ?R) + (looking-at "\\([^ ()\\\n\r\t]\\{0,16\\}\\)(")) + (save-excursion + (setq in-macro (c-beginning-of-macro)) + (setq macro-end (when in-macro + (c-end-of-macro) + (point) ;; (min (1+ (point)) (point-max)) + ))) + (if (not + (c-propertize-raw-string-opener + (match-string-no-properties 1) ; id + (1- (point)) ; open quote + (match-end 1) ; open paren + macro-end)) ; bound (end of macro) or nil. + (goto-char (or macro-end (point-max)))) + t) + ((save-excursion + (and + (search-backward-regexp ")\\([^ ()\\\n\r\t]\\{0,16\\}\\)\"\\=" nil t) + (setq id (match-string-no-properties 1)) + (let* ((quoted-id (regexp-quote id)) + (quoted-id-depth (regexp-opt-depth quoted-id))) + (while + (and + ;; Search back for an opening delimiter with identifier `id'. + ;; A closing delimiter with `id' "blocks" our search. + (search-backward-regexp ; This could be slow. + (concat "\\(R\"" quoted-id "(\\)" + "\\|" + "\\()" quoted-id "\"\\)") + nil t) + (setq found t) + (if (eq (c-in-literal) 'string) + (match-beginning 1) + (match-beginning (+ 2 quoted-id-depth))))) + (and found + (null (c-in-literal)) + (match-beginning 1))) + (setq Rquote (point)))) + (save-excursion + (goto-char Rquote) + (setq in-macro (c-beginning-of-macro)) + (setq macro-end (when in-macro + (c-end-of-macro) + (point)))) + (if (or (not in-macro) + (<= here macro-end)) + (progn (c-propertize-raw-string-opener - (match-string-no-properties 4) ; id - (1+ (match-beginning 3)) ; open quote - (match-end 4) ; open paren - nil) ; bound - ;; We've found a CPP construct. Search for raw strings within it. - (goto-char (match-beginning 2)) ; the "#" - (c-end-of-macro) - (let ((eom (point))) - (goto-char (match-end 2)) ; after the "#". - (while (and (< (point) eom) - (c-syntactic-re-search-forward - "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" eom t)) - (c-propertize-raw-string-opener - (match-string-no-properties 1) ; id - (1+ (match-beginning 0)) ; open quote - (match-end 1) ; open paren - eom)))))))) ; bound + id (1+ (point)) (match-end 1) macro-end) + (goto-char here) + t) + (goto-char here) + nil)) + + (t + ;; If the " is in another part of a raw string (whether as part of the + ;; identifier, or in the string itself) the `syntax-table' text + ;; properties on the raw string will be current. So, we can use... + (c-raw-string-pos))))) ;; Handling of small scale constructs like types and names. diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index 0b41eff1577..e7a3748af43 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -1674,25 +1674,36 @@ casts and declarations are fontified. Used on level 2 and higher." (goto-char string-start) (and (eq (char-before) ?R) (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(") - (match-string-no-properties 1)))))) + (match-string-no-properties 1))))) + (content-start (and raw-id (point)))) + ;; We go round the next loop twice per raw string, once for each "end". (while (< (point) limit) (if raw-id + ;; Search for the raw string end delimiter (progn - (if (search-forward-regexp (concat ")\\(" (regexp-quote raw-id) "\\)\"") - limit 'limit) - (c-put-font-lock-face (match-beginning 1) (point) 'default)) + (when (search-forward-regexp (concat ")\\(" (regexp-quote raw-id) "\\)\"") + limit 'limit) + (c-put-font-lock-face content-start (match-beginning 1) + 'font-lock-string-face) + (c-remove-font-lock-face (match-beginning 1) (point))) (setq raw-id nil)) - + ;; Search for the start of a raw string. (when (search-forward-regexp "R\\(\"\\)\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" limit 'limit) (when - (or (and (eobp) - (eq (c-get-char-property (1- (point)) 'face) - 'font-lock-warning-face)) - (eq (c-get-char-property (point) 'face) 'font-lock-string-face) - (and (equal (c-get-char-property (match-end 2) 'syntax-table) '(1)) - (equal (c-get-char-property (match-beginning 1) 'syntax-table) - '(1)))) + ;; Make sure we're not in a comment or string. + (and + (not (memq (c-get-char-property (match-beginning 0) 'face) + '(font-lock-comment-face font-lock-comment-delimiter-face + font-lock-string-face))) + (or (and (eobp) + (eq (c-get-char-property (1- (point)) 'face) + 'font-lock-warning-face)) + (not (eq (c-get-char-property (point) 'face) 'font-lock-comment-face)) + ;; (eq (c-get-char-property (point) 'face) 'font-lock-string-face) + (and (equal (c-get-char-property (match-end 2) 'syntax-table) '(1)) + (equal (c-get-char-property (match-beginning 1) 'syntax-table) + '(1))))) (let ((paren-prop (c-get-char-property (1- (point)) 'syntax-table))) (if paren-prop (progn @@ -1703,8 +1714,9 @@ casts and declarations are fontified. Used on level 2 and higher." (equal paren-prop '(15)) (not (c-search-forward-char-property 'syntax-table '(15) limit))) (goto-char limit))) - (c-put-font-lock-face (match-beginning 1) (match-end 2) 'default) - (setq raw-id (match-string-no-properties 2))))))))) + (c-remove-font-lock-face (match-beginning 0) (match-end 2)) + (setq raw-id (match-string-no-properties 2)) + (setq content-start (match-end 0))))))))) nil) (defun c-font-lock-c++-lambda-captures (limit) diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 7cc8029e0a3..22b7b602f1e 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -497,25 +497,25 @@ parameters \(point-min) and \(point-max).") ;; For documentation see the following c-lang-defvar of the same name. ;; The value here may be a list of functions or a single function. t '(c-depropertize-new-text - c-after-change-re-mark-unbalanced-strings + c-after-change-mark-abnormal-strings c-change-expand-fl-region) (c objc) '(c-depropertize-new-text c-parse-quotes-after-change - c-after-change-re-mark-unbalanced-strings + c-after-change-mark-abnormal-strings c-extend-font-lock-region-for-macros c-neutralize-syntax-in-CPP c-change-expand-fl-region) c++ '(c-depropertize-new-text + c-after-change-unmark-raw-strings c-parse-quotes-after-change - c-after-change-re-mark-unbalanced-strings + c-after-change-mark-abnormal-strings c-extend-font-lock-region-for-macros - c-after-change-re-mark-raw-strings c-neutralize-syntax-in-CPP c-restore-<>-properties c-change-expand-fl-region) java '(c-depropertize-new-text c-parse-quotes-after-change - c-after-change-re-mark-unbalanced-strings + c-after-change-mark-abnormal-strings c-restore-<>-properties c-change-expand-fl-region) awk '(c-depropertize-new-text diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 8343978fc38..c1fb6aa0915 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -678,14 +678,12 @@ that requires a literal mode spec at compile time." (make-variable-buffer-local 'c-new-BEG) (defvar c-new-END 0) (make-variable-buffer-local 'c-new-END) -;; The following two variables record the values of `c-new-BEG' and -;; `c-new-END' just after `c-new-END' has been adjusted for the length of text -;; inserted or removed. They may be read by any after-change function (but -;; should not be altered by one). -(defvar c-old-BEG 0) -(make-variable-buffer-local 'c-old-BEG) -(defvar c-old-END 0) -(make-variable-buffer-local 'c-old-END) + +;; Buffer local variable which notes the value of calling `c-in-literal' just +;; before a change. It is one of 'string, 'c, 'c++ (for the two sorts of +;; comments), or nil. +(defvar c-old-END-literality nil) +(make-variable-buffer-local 'c-old-END-literality) (defun c-common-init (&optional mode) "Common initialization for all CC Mode modes. @@ -900,7 +898,8 @@ Note that the style variables are always made local to the buffer." (defun c-depropertize-CPP (beg end) ;; Remove the punctuation syntax-table text property from the CPP parts of - ;; (c-new-BEG c-new-END). + ;; (c-new-BEG c-new-END), and remove all syntax-table properties from any + ;; raw strings within these CPP parts. ;; ;; This function is in the C/C++/ObjC values of ;; `c-get-state-before-change-functions' and is called exclusively as a @@ -912,6 +911,7 @@ Note that the style variables are always made local to the buffer." (goto-char (match-beginning 1)) (setq m-beg (point)) (c-end-of-macro) + (save-excursion (c-depropertize-raw-strings-in-region m-beg (point))) (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1))) (while (and (< (point) end) @@ -920,14 +920,16 @@ Note that the style variables are always made local to the buffer." (goto-char (match-beginning 1)) (setq m-beg (point)) (c-end-of-macro)) - (if (and ss-found (> (point) end)) - (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1))) + (when (and ss-found (> (point) end)) + (save-excursion (c-depropertize-raw-strings-in-region m-beg (point))) + (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1))) (while (and (< (point) c-new-END) (search-forward-regexp c-anchored-cpp-prefix c-new-END 'bound)) (goto-char (match-beginning 1)) (setq m-beg (point)) (c-end-of-macro) + (save-excursion (c-depropertize-raw-strings-in-region m-beg (point))) (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1))))) @@ -1213,6 +1215,7 @@ Note that the style variables are always made local to the buffer." "\"\\|\\s|" (point-max) t t) (progn (c-clear-char-property (1- (point)) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (1- (point))) (not (eq (char-before) ?\"))))) (eq (char-before) ?\")) (progn @@ -1247,27 +1250,38 @@ Note that the style variables are always made local to the buffer." (forward-char) (backward-sexp) (c-clear-char-property eoll-1 'syntax-table) + (c-truncate-semi-nonlit-pos-cache eoll-1) (c-clear-char-property (point) 'syntax-table)) ;; Opening " at EOB. (c-clear-char-property (1- (point)) 'syntax-table)) - (if (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) - ;; Opening " on last line of text (without EOL). - (c-clear-char-property (point) 'syntax-table)))) + (when (and (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) + (eq (char-after) ?\")) ; Ignore an unterminated raw string's (. + ;; Opening " on last line of text (without EOL). + (c-clear-char-property (point) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (point))))) (t (goto-char end) ; point-max - (if (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) - (c-clear-char-property (point) 'syntax-table)))) + (when + (and + (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) + (eq (char-after) ?\")) + (c-clear-char-property (point) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (point))))) (unless (and c-multiline-string-start-char (not (c-characterp c-multiline-string-start-char))) - (when (eq end-literal-type 'string) - (c-clear-char-property (1- (cdr end-limits)) 'syntax-table)) + (when (and (eq end-literal-type 'string) + (not (eq (char-before (cdr end-limits)) ?\())) + (c-clear-char-property (1- (cdr end-limits)) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (1- (cdr end-limits)))) - (when (eq beg-literal-type 'string) + (when (and (eq beg-literal-type 'string) + (eq (char-after (car beg-limits)) ?\")) (setq c-new-BEG (min c-new-BEG (car beg-limits))) - (c-clear-char-property (car beg-limits) 'syntax-table))))) + (c-clear-char-property (car beg-limits) 'syntax-table) + (c-truncate-semi-nonlit-pos-cache (car beg-limits)))))) -(defun c-after-change-re-mark-unbalanced-strings (beg end _old-len) +(defun c-after-change-mark-abnormal-strings (beg end _old-len) ;; Mark any unbalanced strings in the region (c-new-BEG c-new-END) with ;; string fence syntax-table text properties. ;; @@ -1318,7 +1332,8 @@ Note that the style variables are always made local to the buffer." (min (1+ (point)) (point-max))))) ((and (null beg-literal-type) (goto-char beg) - (eq (char-before) c-multiline-string-start-char) + (and (not (bobp)) + (eq (char-before) c-multiline-string-start-char)) (memq (char-after) c-string-delims)) (cons (point) (progn @@ -1343,22 +1358,24 @@ Note that the style variables are always made local to the buffer." (while (progn (setq s (parse-partial-sexp (point) c-new-END nil nil s 'syntax-table)) - (and (< (point) c-new-END) - (or (not (nth 3 s)) - (not (memq (char-before) c-string-delims)))))) + (and (< (point) c-new-END) + (or (not (nth 3 s)) + (not (memq (char-before) c-string-delims)))))) ;; We're at the start of a string. (memq (char-before) c-string-delims))) - (if (c-unescaped-nls-in-string-p (1- (point))) - (looking-at "\\(\\\\\\(.\\|\n\\|\r\\)\\|[^\"]\\)*") - (looking-at (cdr (assq (char-before) c-string-innards-re-alist)))) - (cond - ((memq (char-after (match-end 0)) '(?\n ?\r)) - (c-put-char-property (1- (point)) 'syntax-table '(15)) - (c-put-char-property (match-end 0) 'syntax-table '(15))) - ((or (eq (match-end 0) (point-max)) - (eq (char-after (match-end 0)) ?\\)) ; \ at EOB - (c-put-char-property (1- (point)) 'syntax-table '(15)))) - (goto-char (min (1+ (match-end 0)) (point-max))) + (unless (and (c-major-mode-is 'c++-mode) + (c-maybe-re-mark-raw-string)) + (if (c-unescaped-nls-in-string-p (1- (point))) + (looking-at "\\(\\\\\\(.\\|\n|\\\r\\)\\|[^\"]\\)*") + (looking-at (cdr (assq (char-before) c-string-innards-re-alist)))) + (cond + ((memq (char-after (match-end 0)) '(?\n ?\r)) + (c-put-char-property (1- (point)) 'syntax-table '(15)) + (c-put-char-property (match-end 0) 'syntax-table '(15))) + ((or (eq (match-end 0) (point-max)) + (eq (char-after (match-end 0)) ?\\)) ; \ at EOB + (c-put-char-property (1- (point)) 'syntax-table '(15)))) + (goto-char (min (1+ (match-end 0)) (point-max)))) (setq s nil))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1721,7 +1738,6 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") ;; (c-new-BEG c-new-END) will be the region to fontify. It may become ;; larger than (beg end). (setq c-new-END (- (+ c-new-END (- end beg)) old-len)) - (setq c-old-BEG c-new-BEG c-old-END c-new-END) (unless (c-called-from-text-property-change-p) (setq c-just-done-before-change nil) -- 2.39.5