aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2019-03-27 11:50:53 +0000
committerAlan Mackenzie2019-03-27 11:50:53 +0000
commit29ec1e48883dbdce8f9f81ac25d9ec38c474cdcb (patch)
treece9c31a6c3c6d4c0b521b24264294f897a4c4216
parentc26704483726d454cd554406d41dd7bfde537454 (diff)
downloademacs-29ec1e48883dbdce8f9f81ac25d9ec38c474cdcb.tar.gz
emacs-29ec1e48883dbdce8f9f81ac25d9ec38c474cdcb.zip
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.
-rw-r--r--lisp/progmodes/cc-defs.el76
-rw-r--r--lisp/progmodes/cc-engine.el584
-rw-r--r--lisp/progmodes/cc-fonts.el40
-rw-r--r--lisp/progmodes/cc-langs.el10
-rw-r--r--lisp/progmodes/cc-mode.el90
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
212 `(cl-delete-duplicates ,cl-seq ,@cl-keys) 212 `(cl-delete-duplicates ,cl-seq ,@cl-keys)
213 `(delete-duplicates ,cl-seq ,@cl-keys)))) 213 `(delete-duplicates ,cl-seq ,@cl-keys))))
214 214
215(defmacro c-font-lock-flush (beg end)
216 "Declare the region BEG...END's fontification as out-of-date.
217On XEmacs and older Emacsen, this refontifies that region immediately."
218 (if (fboundp 'font-lock-flush)
219 `(font-lock-flush ,beg ,end)
220 `(font-lock-fontify-region ,beg ,end)))
221
215(defmacro c-point (position &optional point) 222(defmacro c-point (position &optional point)
216 "Return the value of certain commonly referenced POSITIONs relative to POINT. 223 "Return the value of certain commonly referenced POSITIONs relative to POINT.
217The current point is used if POINT isn't specified. POSITION can be 224The 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."
258 ((eq position 'eoll) 265 ((eq position 'eoll)
259 `(save-excursion 266 `(save-excursion
260 ,@(if point `((goto-char ,point))) 267 ,@(if point `((goto-char ,point)))
261 (while (progn 268 (while (and
262 (end-of-line) 269 (not (eobp))
263 (prog1 (eq (logand 1 (skip-chars-backward "\\\\")) 1))) 270 (progn
264 (beginning-of-line 2)) 271 (end-of-line)
272 (prog1 (eq (logand 1 (skip-chars-backward "\\\\")) 1))))
273 (forward-line))
265 (end-of-line) 274 (end-of-line)
266 (point))) 275 (point)))
267 276
@@ -1214,7 +1223,7 @@ Leave point just after the character, and set the match data on
1214this character, and return point. If the search fails, return 1223this character, and return point. If the search fails, return
1215nil; point is then left undefined." 1224nil; point is then left undefined."
1216 `(let ((char-skip (concat "^" (char-to-string ,char))) 1225 `(let ((char-skip (concat "^" (char-to-string ,char)))
1217 (-limit- ,limit) 1226 (-limit- (or ,limit (point-max)))
1218 (-value- ,value)) 1227 (-value- ,value))
1219 (while 1228 (while
1220 (and 1229 (and
@@ -1226,15 +1235,39 @@ nil; point is then left undefined."
1226 (search-forward-regexp ".") ; to set the match-data. 1235 (search-forward-regexp ".") ; to set the match-data.
1227 (point)))) 1236 (point))))
1228 1237
1238(defmacro c-search-forward-char-property-without-value-on-char
1239 (property value char &optional limit)
1240 "Search forward for a character CHAR without text property PROPERTY having
1241a value CHAR.
1242LIMIT bounds the search. The value comparison is done with `equal'.
1243PROPERTY must be a constant.
1244
1245Leave point just after the character, and set the match data on
1246this character, and return point. If the search fails, return
1247nil; point is then left undefined."
1248 `(let ((char-skip (concat "^" (char-to-string ,char)))
1249 (-limit- (or ,limit (point-max)))
1250 (-value- ,value))
1251 (while
1252 (and
1253 (progn (skip-chars-forward char-skip -limit-)
1254 (< (point) -limit-))
1255 (equal (c-get-char-property (point) ,property) -value-))
1256 (forward-char))
1257 (when (< (point) -limit-)
1258 (search-forward-regexp ".") ; to set the match-data.
1259 (point))))
1260
1229(defun c-clear-char-property-with-value-on-char-function (from to property 1261(defun c-clear-char-property-with-value-on-char-function (from to property
1230 value char) 1262 value char)
1231 "Remove all text-properties PROPERTY with value VALUE on 1263 "Remove all text-properties PROPERTY with value VALUE on
1232characters with value CHAR from the region [FROM, TO), as tested 1264characters with value CHAR from the region [FROM, TO), as tested
1233by `equal'. These properties are assumed to be over individual 1265by `equal'. These properties are assumed to be over individual
1234characters, having been put there by c-put-char-property. POINT 1266characters, having been put there by c-put-char-property. POINT
1235remains unchanged." 1267remains unchanged. Return the position of the first removed
1268property, or nil."
1236 (let ((place from) 1269 (let ((place from)
1237 ) 1270 first)
1238 (while ; loop round occurrences of (PROPERTY VALUE) 1271 (while ; loop round occurrences of (PROPERTY VALUE)
1239 (progn 1272 (progn
1240 (while ; loop round changes in PROPERTY till we find VALUE 1273 (while ; loop round changes in PROPERTY till we find VALUE
@@ -1243,28 +1276,34 @@ remains unchanged."
1243 (not (equal (get-text-property place property) value))) 1276 (not (equal (get-text-property place property) value)))
1244 (setq place (c-next-single-property-change place property nil to))) 1277 (setq place (c-next-single-property-change place property nil to)))
1245 (< place to)) 1278 (< place to))
1246 (if (eq (char-after place) char) 1279 (when (eq (char-after place) char)
1247 (remove-text-properties place (1+ place) (cons property nil))) 1280 (remove-text-properties place (1+ place) (cons property nil))
1281 (or first (setq first place)))
1248 ;; Do we have to do anything with stickiness here? 1282 ;; Do we have to do anything with stickiness here?
1249 (setq place (1+ place))))) 1283 (setq place (1+ place)))
1284 first))
1250 1285
1251(defmacro c-clear-char-property-with-value-on-char (from to property value char) 1286(defmacro c-clear-char-property-with-value-on-char (from to property value char)
1252 "Remove all text-properties PROPERTY with value VALUE on 1287 "Remove all text-properties PROPERTY with value VALUE on
1253characters with value CHAR from the region [FROM, TO), as tested 1288characters with value CHAR from the region [FROM, TO), as tested
1254by `equal'. These properties are assumed to be over individual 1289by `equal'. These properties are assumed to be over individual
1255characters, having been put there by c-put-char-property. POINT 1290characters, having been put there by c-put-char-property. POINT
1256remains unchanged." 1291remains unchanged. Return the position of the first removed
1292property, or nil."
1257 (if c-use-extents 1293 (if c-use-extents
1258 ;; XEmacs 1294 ;; XEmacs
1259 `(let ((-property- ,property) 1295 `(let ((-property- ,property)
1260 (-char- ,char)) 1296 (-char- ,char)
1297 (first (1+ (point-max))))
1261 (map-extents (lambda (ext val) 1298 (map-extents (lambda (ext val)
1262 (if (and (equal (extent-property ext -property-) val) 1299 (when (and (equal (extent-property ext -property-) val)
1263 (eq (char-after 1300 (eq (char-after
1264 (extent-start-position ext)) 1301 (extent-start-position ext))
1265 -char-)) 1302 -char-))
1266 (delete-extent ext))) 1303 (setq first (min first (extent-start-position ext)))
1267 nil ,from ,to ,value nil -property-)) 1304 (delete-extent ext)))
1305 nil ,from ,to ,value nil -property-)
1306 (and (<= first (point-max)) first))
1268 ;; GNU Emacs 1307 ;; GNU Emacs
1269 `(c-clear-char-property-with-value-on-char-function ,from ,to ,property 1308 `(c-clear-char-property-with-value-on-char-function ,from ,to ,property
1270 ,value ,char))) 1309 ,value ,char)))
@@ -1316,6 +1355,7 @@ with value CHAR in the region [FROM to)."
1316;(eval-after-load "edebug" ; 2006-07-09: def-edebug-spec is now in subr.el. 1355;(eval-after-load "edebug" ; 2006-07-09: def-edebug-spec is now in subr.el.
1317; '(progn 1356; '(progn
1318(def-edebug-spec cc-eval-when-compile (&rest def-form)) 1357(def-edebug-spec cc-eval-when-compile (&rest def-form))
1358(def-edebug-spec c-font-lock-flush t)
1319(def-edebug-spec c--mapcan t) 1359(def-edebug-spec c--mapcan t)
1320(def-edebug-spec c--set-difference (form form &rest [symbolp form])) 1360(def-edebug-spec c--set-difference (form form &rest [symbolp form]))
1321(def-edebug-spec c--intersection (form form &rest [symbolp form])) 1361(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."
5646 ;; Pseudo match inside a comment or string literal. Skip out 5646 ;; Pseudo match inside a comment or string literal. Skip out
5647 ;; of comments and string literals. 5647 ;; of comments and string literals.
5648 (while (progn 5648 (while (progn
5649 (goto-char (c-next-single-property-change 5649 (unless
5650 (point) 'face nil cfd-limit)) 5650 (and (match-end 1)
5651 (c-got-face-at (1- (point)) c-literal-faces)
5652 (not (c-got-face-at (point) c-literal-faces)))
5653 (goto-char (c-next-single-property-change
5654 (point) 'face nil cfd-limit)))
5651 (and (< (point) cfd-limit) 5655 (and (< (point) cfd-limit)
5652 (c-got-face-at (point) c-literal-faces)))) 5656 (c-got-face-at (point) c-literal-faces))))
5653 t) ; Continue the loop over pseudo matches. 5657 t) ; Continue the loop over pseudo matches.
@@ -6350,9 +6354,8 @@ comment at the start of cc-engine.el for more info."
6350;; Set by c-common-init in cc-mode.el. 6354;; Set by c-common-init in cc-mode.el.
6351(defvar c-new-BEG) 6355(defvar c-new-BEG)
6352(defvar c-new-END) 6356(defvar c-new-END)
6353;; Set by c-after-change in cc-mode.el. 6357;; Set by c-before-change-check-raw-strings.
6354(defvar c-old-BEG) 6358(defvar c-old-END-literality)
6355(defvar c-old-END)
6356 6359
6357(defun c-before-change-check-<>-operators (beg end) 6360(defun c-before-change-check-<>-operators (beg end)
6358 ;; Unmark certain pairs of "< .... >" which are currently marked as 6361 ;; Unmark certain pairs of "< .... >" which are currently marked as
@@ -6484,9 +6487,9 @@ comment at the start of cc-engine.el for more info."
6484;; A valid C++ raw string looks like 6487;; A valid C++ raw string looks like
6485;; R"<id>(<contents>)<id>" 6488;; R"<id>(<contents>)<id>"
6486;; , where <id> is an identifier from 0 to 16 characters long, not containing 6489;; , where <id> is an identifier from 0 to 16 characters long, not containing
6487;; spaces, control characters, double quote or left/right paren. <contents> 6490;; spaces, control characters, or left/right paren. <contents> can include
6488;; can include anything which isn't the terminating )<id>", including new 6491;; anything which isn't the terminating )<id>", including new lines, "s,
6489;; lines, "s, parentheses, etc. 6492;; parentheses, etc.
6490;; 6493;;
6491;; CC Mode handles C++ raw strings by the use of `syntax-table' text 6494;; CC Mode handles C++ raw strings by the use of `syntax-table' text
6492;; properties as follows: 6495;; properties as follows:
@@ -6496,16 +6499,18 @@ comment at the start of cc-engine.el for more info."
6496;; contents is given the property value "punctuation" (`(1)') to prevent it 6499;; contents is given the property value "punctuation" (`(1)') to prevent it
6497;; interacting with the "s in the delimiters. 6500;; interacting with the "s in the delimiters.
6498;; 6501;;
6499;; The font locking routine `c-font-lock-c++-raw-strings' (in cc-fonts.el) 6502;; The font locking routine `c-font-lock-raw-strings' (in cc-fonts.el)
6500;; recognizes valid raw strings, and fontifies the delimiters (apart from 6503;; recognizes valid raw strings, and fontifies the delimiters (apart from
6501;; the parentheses) with the default face and the parentheses and the 6504;; the parentheses) with the default face and the parentheses and the
6502;; <contents> with font-lock-string-face. 6505;; <contents> with font-lock-string-face.
6503;; 6506;;
6504;; (ii) A valid, but unterminated, raw string opening delimiter gets the 6507;; (ii) A valid, but unterminated, raw string opening delimiter gets the
6505;; "punctuation" value (`(1)') of the `syntax-table' text property, and the 6508;; "punctuation" value (`(1)') of the `syntax-table' text property, and the
6506;; open parenthesis gets the "string fence" value (`(15)'). 6509;; open parenthesis gets the "string fence" value (`(15)'). When such a
6510;; delimiter is found, no attempt is made in any way to "correct" any text
6511;; properties after the delimiter.
6507;; 6512;;
6508;; `c-font-lock-c++-raw-strings' puts c-font-lock-warning-face on the entire 6513;; `c-font-lock-raw-strings' puts c-font-lock-warning-face on the entire
6509;; unmatched opening delimiter (from the R up to the open paren), and allows 6514;; unmatched opening delimiter (from the R up to the open paren), and allows
6510;; the rest of the buffer to get font-lock-string-face, caused by the 6515;; the rest of the buffer to get font-lock-string-face, caused by the
6511;; unmatched "string fence" `syntax-table' text property value. 6516;; unmatched "string fence" `syntax-table' text property value.
@@ -6522,10 +6527,14 @@ comment at the start of cc-engine.el for more info."
6522;; already at the end of the macro, it gets the "punctuation" value, and no 6527;; already at the end of the macro, it gets the "punctuation" value, and no
6523;; "string fence"s are used. 6528;; "string fence"s are used.
6524;; 6529;;
6525;; The effect on the fontification of either of these tactics is that rest of 6530;; The effect on the fontification of either of these tactics is that the
6526;; the macro (if any) after the "(" gets font-lock-string-face, but the rest 6531;; rest of the macro (if any) after the "(" gets font-lock-string-face, but
6527;; of the file is fontified normally. 6532;; the rest of the file is fontified normally.
6528 6533
6534;; The values of the function `c-raw-string-pos' at before-change-functions'
6535;; BEG and END.
6536(defvar c-old-beg-rs nil)
6537(defvar c-old-end-rs nil)
6529 6538
6530(defun c-raw-string-pos () 6539(defun c-raw-string-pos ()
6531 ;; Get POINT's relationship to any containing raw string. 6540 ;; Get POINT's relationship to any containing raw string.
@@ -6542,7 +6551,7 @@ comment at the start of cc-engine.el for more info."
6542 ;; characters.) If the raw string is not terminated, E\) and E\" are set to 6551 ;; characters.) If the raw string is not terminated, E\) and E\" are set to
6543 ;; nil. 6552 ;; nil.
6544 ;; 6553 ;;
6545 ;; Note: this routine is dependant upon the correct syntax-table text 6554 ;; Note: this function is dependant upon the correct syntax-table text
6546 ;; properties being set. 6555 ;; properties being set.
6547 (let ((state (c-state-semi-pp-to-literal (point))) 6556 (let ((state (c-state-semi-pp-to-literal (point)))
6548 open-quote-pos open-paren-pos close-paren-pos close-quote-pos id) 6557 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."
6555 (search-backward "\"" (max (- (point) 17) (point-min)) t))) 6564 (search-backward "\"" (max (- (point) 17) (point-min)) t)))
6556 ((and (eq (cadr state) 'string) 6565 ((and (eq (cadr state) 'string)
6557 (goto-char (nth 2 state)) 6566 (goto-char (nth 2 state))
6558 (or (eq (char-after) ?\") 6567 (cond
6559 (search-backward "\"" (max (- (point) 17) (point-min)) t)) 6568 ((eq (char-after) ?\"))
6569 ((eq (char-after) ?\()
6570 (let ((here (point)))
6571 (goto-char (max (- (point) 18) (point-min)))
6572 (while
6573 (and
6574 (search-forward-regexp
6575 "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)("
6576 (1+ here) 'limit)
6577 (< (point) here)))
6578 (and (eq (point) (1+ here))
6579 (match-beginning 1)
6580 (goto-char (1- (match-beginning 1)))))))
6560 (not (bobp))))) 6581 (not (bobp)))))
6561 (eq (char-before) ?R) 6582 (eq (char-before) ?R)
6562 (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(")) 6583 (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)("))
@@ -6579,6 +6600,21 @@ comment at the start of cc-engine.el for more info."
6579 (t nil)) 6600 (t nil))
6580 open-quote-pos open-paren-pos close-paren-pos close-quote-pos)))) 6601 open-quote-pos open-paren-pos close-paren-pos close-quote-pos))))
6581 6602
6603(defun c-raw-string-in-end-delim (beg end)
6604 ;; If the region (BEG END) intersects a possible raw string terminator,
6605 ;; return a cons of the position of the ) and the position of the " in the
6606 ;; first one found.
6607 (save-excursion
6608 (goto-char (max (- beg 17) (point-min)))
6609 (while
6610 (and
6611 (search-forward-regexp ")\\([^ ()\\\n\r\t]\\{0,16\\}\\)\""
6612 (min (+ end 17) (point-max)) t)
6613 (<= (point) beg)))
6614 (unless (or (<= (point) beg)
6615 (>= (match-beginning 0) end))
6616 (cons (match-beginning 0) (match-end 1)))))
6617
6582(defun c-depropertize-raw-string (id open-quote open-paren bound) 6618(defun c-depropertize-raw-string (id open-quote open-paren bound)
6583 ;; Point is immediately after a raw string opening delimiter. Remove any 6619 ;; Point is immediately after a raw string opening delimiter. Remove any
6584 ;; `syntax-table' text properties associated with the delimiter (if it's 6620 ;; `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."
6587 ;; ID, a string, is the delimiter's identifier. OPEN-QUOTE and OPEN-PAREN 6623 ;; ID, a string, is the delimiter's identifier. OPEN-QUOTE and OPEN-PAREN
6588 ;; are the buffer positions of the delimiter's components. BOUND is the 6624 ;; are the buffer positions of the delimiter's components. BOUND is the
6589 ;; bound for searching for a matching closing delimiter; it is usually nil, 6625 ;; bound for searching for a matching closing delimiter; it is usually nil,
6590 ;; but if we're inside a macro, it's the end of the macro. 6626 ;; but if we're inside a macro, it's the end of the macro (i.e. just before
6627 ;; the terminating \n).
6591 ;; 6628 ;;
6592 ;; Point is moved to after the (terminated) raw string, or left after the 6629 ;; Point is moved to after the (terminated) raw string, or left after the
6593 ;; unmatched opening delimiter, as the case may be. The return value is of 6630 ;; unmatched opening delimiter, as the case may be. The return value is of
6594 ;; no significance. 6631 ;; no significance.
6595 (let ((open-paren-prop (c-get-char-property open-paren 'syntax-table))) 6632 (let ((open-paren-prop (c-get-char-property open-paren 'syntax-table))
6633 first)
6634 ;; If the delimiter is "unclosed", or sombody's used " in their id, clear
6635 ;; the 'syntax-table property from all of them.
6636 (setq first (c-clear-char-property-with-value-on-char
6637 open-quote open-paren 'syntax-table '(1) ?\"))
6638 (if first (c-truncate-semi-nonlit-pos-cache first))
6596 (cond 6639 (cond
6597 ((null open-paren-prop) 6640 ((null open-paren-prop)
6598 ;; A terminated raw string 6641 ;; Should be a terminated raw string...
6599 (when (search-forward (concat ")" id "\"") nil t) 6642 (when (search-forward (concat ")" id "\"") nil t)
6643 ;; Yes, it is. :-)
6644 ;; Clear any '(1)s from "s in the identifier.
6645 (setq first (c-clear-char-property-with-value-on-char
6646 (1+ (match-beginning 0)) (1- (match-end 0))
6647 'syntax-table '(1) ?\"))
6648 (if first (c-truncate-semi-nonlit-pos-cache first))
6649 ;; Clear any random `syntax-table' text properties from the contents.
6600 (let* ((closing-paren (match-beginning 0)) 6650 (let* ((closing-paren (match-beginning 0))
6601 (first-punctuation 6651 (first-st
6602 (save-match-data 6652 (and
6603 (goto-char (1+ open-paren)) 6653 (< (1+ open-paren) closing-paren)
6604 (and (c-search-forward-char-property 'syntax-table '(1) 6654 (or
6605 closing-paren) 6655 (and (c-get-char-property (1+ open-paren) 'syntax-table)
6606 (1- (point))))) 6656 (1+ open-paren))
6607 ) 6657 (and
6608 (when first-punctuation 6658 (setq first
6609 (c-clear-char-property-with-value 6659 (c-next-single-property-change
6610 first-punctuation (match-beginning 0) 'syntax-table '(1)) 6660 (1+ open-paren) 'syntax-table nil closing-paren))
6611 (c-truncate-semi-nonlit-pos-cache first-punctuation) 6661 (< first closing-paren)
6612 )))) 6662 first)))))
6663 (when first-st
6664 (c-clear-char-properties first-st (match-beginning 0)
6665 'syntax-table)
6666 (c-truncate-semi-nonlit-pos-cache first-st))
6667 (when (c-get-char-property (1- (match-end 0)) 'syntax-table)
6668 ;; Was previously an unterminated (ordinary) string
6669 (save-excursion
6670 (goto-char (1- (match-end 0)))
6671 (when (c-safe (c-forward-sexp)) ; to '(1) at EOL.
6672 (c-clear-char-property (1- (point)) 'syntax-table))
6673 (c-clear-char-property (1- (match-end 0)) 'syntax-table)
6674 (c-truncate-semi-nonlit-pos-cache (1- (match-end 0))))))))
6613 ((or (and (equal open-paren-prop '(15)) (null bound)) 6675 ((or (and (equal open-paren-prop '(15)) (null bound))
6614 (equal open-paren-prop '(1))) 6676 (equal open-paren-prop '(1)))
6615 ;; An unterminated raw string either not in a macro, or in a macro with 6677 ;; 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."
6623 (c-clear-char-property open-quote 'syntax-table) 6685 (c-clear-char-property open-quote 'syntax-table)
6624 (c-truncate-semi-nonlit-pos-cache open-quote) 6686 (c-truncate-semi-nonlit-pos-cache open-quote)
6625 (c-clear-char-property open-paren 'syntax-table) 6687 (c-clear-char-property open-paren 'syntax-table)
6626 (let ((after-string-fence-pos 6688 (c-clear-char-property-with-value (1+ open-paren) bound 'syntax-table
6627 (save-excursion 6689 '(15))))))
6628 (goto-char (1+ open-paren))
6629 (c-search-forward-char-property 'syntax-table '(15) bound))))
6630 (when after-string-fence-pos
6631 (c-clear-char-property (1- after-string-fence-pos) 'syntax-table)))
6632 ))))
6633 6690
6634(defun c-depropertize-raw-strings-in-region (start finish) 6691(defun c-depropertize-raw-strings-in-region (start finish)
6635 ;; Remove any `syntax-table' text properties associated with C++ raw strings 6692 ;; 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."
6669 6726
6670(defun c-before-change-check-raw-strings (beg end) 6727(defun c-before-change-check-raw-strings (beg end)
6671 ;; This function clears `syntax-table' text properties from C++ raw strings 6728 ;; This function clears `syntax-table' text properties from C++ raw strings
6672 ;; in the region (c-new-BEG c-new-END). BEG and END are the standard 6729 ;; whose delimiters are about to change in the region (c-new-BEG c-new-END).
6673 ;; arguments supplied to any before-change function. 6730 ;; BEG and END are the standard arguments supplied to any before-change
6731 ;; function.
6674 ;; 6732 ;;
6675 ;; Point is undefined on both entry and exit, and the return value has no 6733 ;; Point is undefined on both entry and exit, and the return value has no
6676 ;; significance. 6734 ;; significance.
6677 ;; 6735 ;;
6678 ;; This function is called as a before-change function solely due to its 6736 ;; This function is called as a before-change function solely due to its
6679 ;; membership of the C++ value of `c-get-state-before-change-functions'. 6737 ;; membership of the C++ value of `c-get-state-before-change-functions'.
6738 (goto-char end)
6739 ;; We use the following to detect a R"<id>( being swallowed into a string by
6740 ;; the pending change.
6741 (setq c-old-END-literality (c-in-literal))
6680 (c-save-buffer-state 6742 (c-save-buffer-state
6681 ((beg-rs (progn (goto-char beg) (c-raw-string-pos))) 6743 (;; (beg-rs (progn (goto-char beg) (c-raw-string-pos)))
6682 (beg-plus (if (null beg-rs) 6744 ;; (end-rs (progn (goto-char end) (c-raw-string-pos)))
6683 beg 6745 ; FIXME!!!
6684 (max beg
6685 (1+ (or (nth 4 beg-rs) (nth 2 beg-rs))))))
6686 (end-rs (progn (goto-char end) (c-raw-string-pos))) ; FIXME!!!
6687 ; Optimize this so that we don't call 6746 ; Optimize this so that we don't call
6688 ; `c-raw-string-pos' twice when once 6747 ; `c-raw-string-pos' twice when once
6689 ; will do. (2016-06-02). 6748 ; will do. (2016-06-02).
6690 (end-minus (if (null end-rs) 6749 (term-del (c-raw-string-in-end-delim beg end))
6691 end 6750 Rquote close-quote)
6692 (min end (cadr end-rs)))) 6751 (setq c-old-beg-rs (progn (goto-char beg) (c-raw-string-pos))
6693 ) 6752 c-old-end-rs (progn (goto-char end) (c-raw-string-pos)))
6694 (when beg-rs 6753 (cond
6695 (setq c-new-BEG (min c-new-BEG (1- (cadr beg-rs))))) 6754 ;; We're not changing, or we're obliterating raw strings.
6696 (c-depropertize-raw-strings-in-region c-new-BEG beg-plus) 6755 ((and (null c-old-beg-rs) (null c-old-end-rs)))
6697 6756 ;; We're changing the putative terminating delimiter of a raw string
6698 (when end-rs 6757 ;; containing BEG.
6699 (setq c-new-END (max c-new-END 6758 ((and c-old-beg-rs term-del
6700 (1+ (or (nth 4 end-rs) 6759 (or (null (nth 3 c-old-beg-rs))
6701 (nth 2 end-rs)))))) 6760 (<= (car term-del) (nth 3 c-old-beg-rs))))
6702 (c-depropertize-raw-strings-in-region end-minus c-new-END))) 6761 (setq Rquote (1- (cadr c-old-beg-rs))
6762 close-quote (1+ (cdr term-del)))
6763 (c-depropertize-raw-strings-in-region Rquote close-quote)
6764 (setq c-new-BEG (min c-new-BEG Rquote)
6765 c-new-END (max c-new-END close-quote)))
6766 ;; We're breaking an escaped NL in a raw string in a macro.
6767 ((and c-old-end-rs
6768 (< beg end)
6769 (goto-char end) (eq (char-before) ?\\)
6770 (c-beginning-of-macro))
6771 (let ((bom (point))
6772 (eom (progn (c-end-of-macro) (point))))
6773 (c-depropertize-raw-strings-in-region bom eom)
6774 (setq c-new-BEG (min c-new-BEG bom)
6775 c-new-END (max c-new-END eom))))
6776 ;; We're changing only the contents of a raw string.
6777 ((and (equal (cdr c-old-beg-rs) (cdr c-old-end-rs))
6778 (null (car c-old-beg-rs)) (null (car c-old-end-rs))))
6779 ((or
6780 ;; We're removing (at least part of) the R" of the starting delim of a
6781 ;; raw string:
6782 (null c-old-beg-rs)
6783 (and (eq beg (cadr c-old-beg-rs))
6784 (< beg end))
6785 ;; Or we're removing the ( of the starting delim of a raw string.
6786 (and (eq (car c-old-beg-rs) 'open-delim)
6787 (or (null c-old-end-rs)
6788 (not (eq (car c-old-end-rs) 'open-delim))
6789 (not (equal (cdr c-old-beg-rs) (cdr c-old-end-rs))))))
6790 (let ((close (nth 4 (or c-old-end-rs c-old-beg-rs))))
6791 (setq Rquote (1- (cadr (or c-old-end-rs c-old-beg-rs)))
6792 close-quote (if close (1+ close) (point-max))))
6793 (c-depropertize-raw-strings-in-region Rquote close-quote)
6794 (setq c-new-BEG (min c-new-BEG Rquote)
6795 c-new-END (max c-new-END close-quote)))
6796 ;; We're changing only the text of the identifier of the opening
6797 ;; delimiter of a raw string.
6798 ((and (eq (car c-old-beg-rs) 'open-delim)
6799 (equal c-old-beg-rs c-old-end-rs))))))
6800
6801(defun c-propertize-raw-string-id (start end)
6802 ;; If the raw string identifier between buffer positions START and END
6803 ;; contains any double quote characters, put a punctuation syntax-table text
6804 ;; property on them. The return value is of no significance.
6805 (save-excursion
6806 (goto-char start)
6807 (while (and (skip-chars-forward "^\"" end)
6808 (< (point) end))
6809 (c-put-char-property (point) 'syntax-table '(1))
6810 (c-truncate-semi-nonlit-pos-cache (point))
6811 (forward-char))))
6703 6812
6704(defun c-propertize-raw-string-opener (id open-quote open-paren bound) 6813(defun c-propertize-raw-string-opener (id open-quote open-paren bound)
6705 ;; Point is immediately after a raw string opening delimiter. Apply any 6814 ;; 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."
6709 ;; ID, a string, is the delimiter's identifier. OPEN-QUOTE and OPEN-PAREN 6818 ;; ID, a string, is the delimiter's identifier. OPEN-QUOTE and OPEN-PAREN
6710 ;; are the buffer positions of the delimiter's components. BOUND is the 6819 ;; are the buffer positions of the delimiter's components. BOUND is the
6711 ;; bound for searching for a matching closing delimiter; it is usually nil, 6820 ;; bound for searching for a matching closing delimiter; it is usually nil,
6712 ;; but if we're inside a macro, it's the end of the macro. 6821 ;; but if we're inside a macro, it's the end of the macro (i.e. the position
6713 ;; 6822 ;; of the closing newline).
6714 ;; Point is moved to after the (terminated) raw string, or left after the 6823 ;;
6715 ;; unmatched opening delimiter, as the case may be. The return value is of 6824 ;; Point is moved to after the (terminated) raw string and t is returned, or
6716 ;; no significance. 6825 ;; it is left after the unmatched opening delimiter and nil is returned.
6717 (if (search-forward (concat ")" id "\"") bound t) 6826 (c-propertize-raw-string-id (1+ open-quote) open-paren)
6718 (let ((end-string (match-beginning 0)) 6827 (prog1
6719 (after-quote (match-end 0))) 6828 (if (search-forward (concat ")" id "\"") bound t)
6720 (goto-char open-paren) 6829 (let ((end-string (match-beginning 0))
6721 (while (progn (skip-syntax-forward "^\"" end-string) 6830 (after-quote (match-end 0)))
6722 (< (point) end-string)) 6831 (c-propertize-raw-string-id
6723 (c-put-char-property (point) 'syntax-table '(1)) ; punctuation 6832 (1+ (match-beginning 0)) (1- (match-end 0)))
6724 (c-truncate-semi-nonlit-pos-cache (point)) 6833 (goto-char open-paren)
6725 (forward-char)) 6834 (while (progn (skip-syntax-forward "^\"" end-string)
6726 (goto-char after-quote)) 6835 (< (point) end-string))
6727 (c-put-char-property open-quote 'syntax-table '(1)) ; punctuation 6836 (c-put-char-property (point) 'syntax-table '(1)) ; punctuation
6728 (c-truncate-semi-nonlit-pos-cache open-quote) 6837 (c-truncate-semi-nonlit-pos-cache (point))
6729 (c-put-char-property open-paren 'syntax-table '(15)) ; generic string 6838 (forward-char))
6730 (when bound 6839 (goto-char after-quote)
6731 ;; In a CPP construct, we try to apply a generic-string `syntax-table' 6840 t)
6732 ;; text property to the last possible character in the string, so that 6841 (c-put-char-property open-quote 'syntax-table '(1)) ; punctuation
6733 ;; only characters within the macro get "stringed out". 6842 (c-truncate-semi-nonlit-pos-cache open-quote)
6734 (goto-char bound) 6843 (c-put-char-property open-paren 'syntax-table '(15)) ; generic string
6735 (if (save-restriction 6844 (when bound
6736 (narrow-to-region (1+ open-paren) (point-max)) 6845 ;; In a CPP construct, we try to apply a generic-string
6737 (re-search-backward 6846 ;; `syntax-table' text property to the last possible character in
6738 (eval-when-compile 6847 ;; the string, so that only characters within the macro get
6739 ;; This regular expression matches either an escape pair (which 6848 ;; "stringed out".
6740 ;; isn't an escaped NL) (submatch 5) or a non-escaped character 6849 (goto-char bound)
6741 ;; (which isn't itself a backslash) (submatch 10). The long 6850 (if (save-restriction
6742 ;; preambles to these (respectively submatches 2-4 and 6-9) 6851 (narrow-to-region (1+ open-paren) (point-max))
6743 ;; ensure that we have the correct parity for sequences of 6852 (re-search-backward
6744 ;; backslashes, etc.. 6853 (eval-when-compile
6745 (concat "\\(" ; 1 6854 ;; This regular expression matches either an escape pair
6746 "\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)*" ; 2-4 6855 ;; (which isn't an escaped NL) (submatch 5) or a
6747 "\\(\\\\.\\)" ; 5 6856 ;; non-escaped character (which isn't itself a backslash)
6748 "\\|" 6857 ;; (submatch 10). The long preambles to these
6749 "\\(\\`\\|[^\\]\\|\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)+\\)" ; 6-9 6858 ;; (respectively submatches 2-4 and 6-9) ensure that we
6750 "\\([^\\]\\)" ; 10 6859 ;; have the correct parity for sequences of backslashes,
6751 "\\)" 6860 ;; etc..
6752 "\\(\\\\\n\\)*\\=")) ; 11 6861 (concat "\\(" ; 1
6753 (1+ open-paren) t)) 6862 "\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)*" ; 2-4
6754 (if (match-beginning 10) 6863 "\\(\\\\.\\)" ; 5
6755 (progn 6864 "\\|"
6756 (c-put-char-property (match-beginning 10) 'syntax-table '(15)) 6865 "\\(\\`\\|[^\\]\\|\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)+\\)" ; 6-9
6757 (c-truncate-semi-nonlit-pos-cache (match-beginning 10))) 6866 "\\([^\\]\\)" ; 10
6758 (c-put-char-property (match-beginning 5) 'syntax-table '(1)) 6867 "\\)"
6759 (c-put-char-property (1+ (match-beginning 5)) 'syntax-table '(15)) 6868 "\\(\\\\\n\\)*\\=")) ; 11
6760 (c-truncate-semi-nonlit-pos-cache (1+ (match-beginning 5)))) 6869 (1+ open-paren) t))
6761 (c-put-char-property open-paren 'syntax-table '(1))) 6870 (if (match-beginning 10)
6762 (goto-char bound)))) 6871 (progn
6763 6872 (c-put-char-property (match-beginning 10) 'syntax-table '(15))
6764(defun c-after-change-re-mark-raw-strings (_beg _end _old-len) 6873 (c-truncate-semi-nonlit-pos-cache (match-beginning 10)))
6765 ;; This function applies `syntax-table' text properties to C++ raw strings 6874 (c-put-char-property (match-beginning 5) 'syntax-table '(1))
6766 ;; beginning in the region (c-new-BEG c-new-END). BEG, END, and OLD-LEN are 6875 (c-put-char-property (1+ (match-beginning 5)) 'syntax-table '(15))
6767 ;; the standard arguments supplied to any after-change function. 6876 (c-truncate-semi-nonlit-pos-cache (1+ (match-beginning 5))))
6877 ;; (c-put-char-property open-paren 'syntax-table '(1))
6878 )
6879 (goto-char bound))
6880 nil)
6881 ;; Ensure the opening delimiter will get refontified.
6882 (c-font-lock-flush (1- open-quote) (1+ open-paren))))
6883
6884(defun c-after-change-unmark-raw-strings (beg end _old-len)
6885 ;; This function removes `syntax-table' text properties from any raw strings
6886 ;; which have been affected by the current change. These are those which
6887 ;; have been "stringed out" and from newly formed raw strings, or any
6888 ;; existing raw string which the new text terminates. BEG, END, and
6889 ;; _OLD-LEN are the standard arguments supplied to any
6890 ;; after-change-function.
6768 ;; 6891 ;;
6769 ;; Point is undefined on both entry and exit, and the return value has no 6892 ;; Point is undefined on both entry and exit, and the return value has no
6770 ;; significance. 6893 ;; significance.
6771 ;; 6894 ;;
6772 ;; This function is called as an after-change function solely due to its 6895 ;; This functions is called as an after-change function by virtue of its
6773 ;; membership of the C++ value of `c-before-font-lock-functions'. 6896 ;; membership of the C++ value of `c-before-font-lock-functions'.
6774 (c-save-buffer-state () 6897 ;; (when (< beg end)
6775 ;; If the region (c-new-BEG c-new-END) has expanded, remove 6898 (c-save-buffer-state (found eoll state id found-beg found-end)
6776 ;; `syntax-table' text-properties from the new piece(s). 6899 ;; Has an inserted " swallowed up a R"(, turning it into "...R"(?
6777 (when (< c-new-BEG c-old-BEG) 6900 (goto-char end)
6778 (let ((beg-rs (progn (goto-char c-old-BEG) (c-raw-string-pos)))) 6901 (setq eoll (c-point 'eoll))
6779 (c-depropertize-raw-strings-in-region 6902 (when (and (null c-old-END-literality)
6780 c-new-BEG 6903 (search-forward-regexp "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)("
6781 (if beg-rs 6904 eoll t))
6782 (1+ (or (nth 4 beg-rs) (nth 2 beg-rs))) 6905 (setq state (c-state-semi-pp-to-literal end))
6783 c-old-BEG)))) 6906 (when (eq (cadr state) 'string)
6784 (when (> c-new-END c-old-END) 6907 (unwind-protect
6785 (let ((end-rs (progn (goto-char c-old-END) (c-raw-string-pos)))) 6908 ;; Temporarily insert a closing string delimiter....
6786 (c-depropertize-raw-strings-in-region 6909 (progn
6787 (if end-rs 6910 (goto-char end)
6788 (cadr end-rs) 6911 (cond
6789 c-old-END) 6912 ((c-characterp (nth 3 (car state)))
6790 c-new-END))) 6913 (insert (nth 3 (car state))))
6914 ((eq (nth 3 (car state)) t)
6915 (insert ?\")
6916 (c-put-char-property end 'syntax-table '(15))))
6917 (c-truncate-semi-nonlit-pos-cache end)
6918 ;; ....ensure c-new-END extends right to the end of the about
6919 ;; to be un-stringed raw string....
6920 (save-excursion
6921 (goto-char (match-beginning 1))
6922 (let ((end-bs (c-raw-string-pos)))
6923 (setq c-new-END
6924 (max c-new-END
6925 (if (nth 4 end-bs)
6926 (1+ (nth 4 end-bs))
6927 eoll)))))
6928
6929 ;; ...and clear `syntax-table' text propertes from the
6930 ;; following raw strings.
6931 (c-depropertize-raw-strings-in-region (point) (1+ eoll)))
6932 ;; Remove the temporary string delimiter.
6933 (goto-char end)
6934 (delete-char 1))))
6935
6936 ;; Have we just created a new starting id?
6937 (goto-char (max (- beg 18) (point-min)))
6938 (while
6939 (and
6940 (setq found
6941 (search-forward-regexp "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)("
6942 c-new-END 'bound))
6943 (<= (match-end 0) beg)))
6944 (when (and found (<= (match-beginning 0) end))
6945 (setq c-new-BEG (min c-new-BEG (match-beginning 0)))
6946 (c-depropertize-raw-strings-in-region c-new-BEG c-new-END))
6947
6948 ;; Have we invalidated an opening delimiter by typing into it?
6949 (when (and c-old-beg-rs
6950 (eq (car c-old-beg-rs) 'open-delim)
6951 (equal (c-get-char-property (cadr c-old-beg-rs)
6952 'syntax-table)
6953 '(1)))
6954 (goto-char (1- (cadr c-old-beg-rs)))
6955 (unless (looking-at "R\"[^ ()\\\n\r\t]\\{0,16\\}(")
6956 (c-clear-char-property (1+ (point)) 'syntax-table)
6957 (c-truncate-semi-nonlit-pos-cache (1+ (point)))
6958 (if (c-search-forward-char-property 'syntax-table '(15)
6959 (c-point 'eol))
6960 (c-clear-char-property (1- (point)) 'syntax-table))))
6961
6962 ;; Have we terminated an existing raw string by inserting or removing
6963 ;; text?
6964 (when (eq c-old-END-literality 'string)
6965 (setq state (c-state-semi-pp-to-literal beg))
6966 (cond
6967 ;; Possibly terminating a(n un)terminated raw string.
6968 ((eq (nth 3 (car state)) t)
6969 (goto-char (nth 8 (car state)))
6970 (when
6971 (and (eq (char-after) ?\()
6972 (search-backward-regexp
6973 "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)\\=" (- (point) 18) t))
6974 (setq id (match-string-no-properties 1)
6975 found-beg (match-beginning 0)
6976 found-end (1+ (match-end 0)))))
6977 ;; Possibly terminating an already terminated raw string.
6978 ((eq (nth 3 (car state)) ?\")
6979 (goto-char (nth 8 (car state)))
6980 (when
6981 (and (eq (char-before) ?R)
6982 (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)("))
6983 (setq id (match-string-no-properties 1)
6984 found-beg (1- (point))
6985 found-end (match-end 0)))))
6986 (when id
6987 (goto-char (max (- beg 18) (point-min)))
6988 (when (search-forward (concat ")" id "\"") (+ end 1 (length id)) t)
6989 ;; Has an earlier close delimiter just been inserted into an
6990 ;; already terminated raw string?
6991 (if (and (eq (nth 3 (car state)) ?\")
6992 (search-forward (concat ")" id "\"") nil t))
6993 (setq found-end (point)))
6994 (setq c-new-BEG (min c-new-BEG found-beg)
6995 c-new-END (max c-new-END found-end))
6996 (c-clear-char-properties found-beg found-end 'syntax-table)
6997 (c-truncate-semi-nonlit-pos-cache found-beg))))
6998
6999 ;; Are there any raw strings in a newly created macro?
7000 (when (< beg end)
7001 (goto-char beg)
7002 (setq found-beg (point))
7003 (when (search-forward-regexp c-anchored-cpp-prefix end t)
7004 (c-end-of-macro)
7005 (c-depropertize-raw-strings-in-region found-beg (point))))))
6791 7006
6792 (goto-char c-new-BEG) 7007(defun c-maybe-re-mark-raw-string ()
6793 (while (and (< (point) c-new-END) 7008 ;; When this function is called, point is immediately after a ". If this "
6794 (re-search-forward 7009 ;; is the characteristic " of of a raw string delimiter, apply the pertinent
6795 (concat "\\(" ; 1 7010 ;; `syntax-table' text properties to the entire raw string (when properly
6796 c-anchored-cpp-prefix ; 2 7011 ;; terminated) or just the delimiter (otherwise).
6797 "\\)\\|\\(" ; 3 7012 ;;
6798 "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" ; 4 7013 ;; If the " is in any way part of a raw string, return non-nil. Otherwise
6799 "\\)") 7014 ;; return nil.
6800 c-new-END t)) 7015 (let ((here (point))
6801 (when (save-excursion 7016 in-macro macro-end id Rquote found)
6802 (goto-char (match-beginning 0)) (not (c-in-literal))) 7017 (cond
6803 (if (match-beginning 4) ; the id 7018 ((and
6804 ;; We've found a raw string. 7019 (eq (char-before (1- (point))) ?R)
7020 (looking-at "\\([^ ()\\\n\r\t]\\{0,16\\}\\)("))
7021 (save-excursion
7022 (setq in-macro (c-beginning-of-macro))
7023 (setq macro-end (when in-macro
7024 (c-end-of-macro)
7025 (point) ;; (min (1+ (point)) (point-max))
7026 )))
7027 (if (not
7028 (c-propertize-raw-string-opener
7029 (match-string-no-properties 1) ; id
7030 (1- (point)) ; open quote
7031 (match-end 1) ; open paren
7032 macro-end)) ; bound (end of macro) or nil.
7033 (goto-char (or macro-end (point-max))))
7034 t)
7035 ((save-excursion
7036 (and
7037 (search-backward-regexp ")\\([^ ()\\\n\r\t]\\{0,16\\}\\)\"\\=" nil t)
7038 (setq id (match-string-no-properties 1))
7039 (let* ((quoted-id (regexp-quote id))
7040 (quoted-id-depth (regexp-opt-depth quoted-id)))
7041 (while
7042 (and
7043 ;; Search back for an opening delimiter with identifier `id'.
7044 ;; A closing delimiter with `id' "blocks" our search.
7045 (search-backward-regexp ; This could be slow.
7046 (concat "\\(R\"" quoted-id "(\\)"
7047 "\\|"
7048 "\\()" quoted-id "\"\\)")
7049 nil t)
7050 (setq found t)
7051 (if (eq (c-in-literal) 'string)
7052 (match-beginning 1)
7053 (match-beginning (+ 2 quoted-id-depth)))))
7054 (and found
7055 (null (c-in-literal))
7056 (match-beginning 1)))
7057 (setq Rquote (point))))
7058 (save-excursion
7059 (goto-char Rquote)
7060 (setq in-macro (c-beginning-of-macro))
7061 (setq macro-end (when in-macro
7062 (c-end-of-macro)
7063 (point))))
7064 (if (or (not in-macro)
7065 (<= here macro-end))
7066 (progn
6805 (c-propertize-raw-string-opener 7067 (c-propertize-raw-string-opener
6806 (match-string-no-properties 4) ; id 7068 id (1+ (point)) (match-end 1) macro-end)
6807 (1+ (match-beginning 3)) ; open quote 7069 (goto-char here)
6808 (match-end 4) ; open paren 7070 t)
6809 nil) ; bound 7071 (goto-char here)
6810 ;; We've found a CPP construct. Search for raw strings within it. 7072 nil))
6811 (goto-char (match-beginning 2)) ; the "#" 7073
6812 (c-end-of-macro) 7074 (t
6813 (let ((eom (point))) 7075 ;; If the " is in another part of a raw string (whether as part of the
6814 (goto-char (match-end 2)) ; after the "#". 7076 ;; identifier, or in the string itself) the `syntax-table' text
6815 (while (and (< (point) eom) 7077 ;; properties on the raw string will be current. So, we can use...
6816 (c-syntactic-re-search-forward 7078 (c-raw-string-pos)))))
6817 "R\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" eom t))
6818 (c-propertize-raw-string-opener
6819 (match-string-no-properties 1) ; id
6820 (1+ (match-beginning 0)) ; open quote
6821 (match-end 1) ; open paren
6822 eom)))))))) ; bound
6823 7079
6824 7080
6825;; Handling of small scale constructs like types and names. 7081;; 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."
1674 (goto-char string-start) 1674 (goto-char string-start)
1675 (and (eq (char-before) ?R) 1675 (and (eq (char-before) ?R)
1676 (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(") 1676 (looking-at "\"\\([^ ()\\\n\r\t]\\{0,16\\}\\)(")
1677 (match-string-no-properties 1)))))) 1677 (match-string-no-properties 1)))))
1678 (content-start (and raw-id (point))))
1679 ;; We go round the next loop twice per raw string, once for each "end".
1678 (while (< (point) limit) 1680 (while (< (point) limit)
1679 (if raw-id 1681 (if raw-id
1682 ;; Search for the raw string end delimiter
1680 (progn 1683 (progn
1681 (if (search-forward-regexp (concat ")\\(" (regexp-quote raw-id) "\\)\"") 1684 (when (search-forward-regexp (concat ")\\(" (regexp-quote raw-id) "\\)\"")
1682 limit 'limit) 1685 limit 'limit)
1683 (c-put-font-lock-face (match-beginning 1) (point) 'default)) 1686 (c-put-font-lock-face content-start (match-beginning 1)
1687 'font-lock-string-face)
1688 (c-remove-font-lock-face (match-beginning 1) (point)))
1684 (setq raw-id nil)) 1689 (setq raw-id nil))
1685 1690 ;; Search for the start of a raw string.
1686 (when (search-forward-regexp 1691 (when (search-forward-regexp
1687 "R\\(\"\\)\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" limit 'limit) 1692 "R\\(\"\\)\\([^ ()\\\n\r\t]\\{0,16\\}\\)(" limit 'limit)
1688 (when 1693 (when
1689 (or (and (eobp) 1694 ;; Make sure we're not in a comment or string.
1690 (eq (c-get-char-property (1- (point)) 'face) 1695 (and
1691 'font-lock-warning-face)) 1696 (not (memq (c-get-char-property (match-beginning 0) 'face)
1692 (eq (c-get-char-property (point) 'face) 'font-lock-string-face) 1697 '(font-lock-comment-face font-lock-comment-delimiter-face
1693 (and (equal (c-get-char-property (match-end 2) 'syntax-table) '(1)) 1698 font-lock-string-face)))
1694 (equal (c-get-char-property (match-beginning 1) 'syntax-table) 1699 (or (and (eobp)
1695 '(1)))) 1700 (eq (c-get-char-property (1- (point)) 'face)
1701 'font-lock-warning-face))
1702 (not (eq (c-get-char-property (point) 'face) 'font-lock-comment-face))
1703 ;; (eq (c-get-char-property (point) 'face) 'font-lock-string-face)
1704 (and (equal (c-get-char-property (match-end 2) 'syntax-table) '(1))
1705 (equal (c-get-char-property (match-beginning 1) 'syntax-table)
1706 '(1)))))
1696 (let ((paren-prop (c-get-char-property (1- (point)) 'syntax-table))) 1707 (let ((paren-prop (c-get-char-property (1- (point)) 'syntax-table)))
1697 (if paren-prop 1708 (if paren-prop
1698 (progn 1709 (progn
@@ -1703,8 +1714,9 @@ casts and declarations are fontified. Used on level 2 and higher."
1703 (equal paren-prop '(15)) 1714 (equal paren-prop '(15))
1704 (not (c-search-forward-char-property 'syntax-table '(15) limit))) 1715 (not (c-search-forward-char-property 'syntax-table '(15) limit)))
1705 (goto-char limit))) 1716 (goto-char limit)))
1706 (c-put-font-lock-face (match-beginning 1) (match-end 2) 'default) 1717 (c-remove-font-lock-face (match-beginning 0) (match-end 2))
1707 (setq raw-id (match-string-no-properties 2))))))))) 1718 (setq raw-id (match-string-no-properties 2))
1719 (setq content-start (match-end 0)))))))))
1708 nil) 1720 nil)
1709 1721
1710(defun c-font-lock-c++-lambda-captures (limit) 1722(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).")
497 ;; For documentation see the following c-lang-defvar of the same name. 497 ;; For documentation see the following c-lang-defvar of the same name.
498 ;; The value here may be a list of functions or a single function. 498 ;; The value here may be a list of functions or a single function.
499 t '(c-depropertize-new-text 499 t '(c-depropertize-new-text
500 c-after-change-re-mark-unbalanced-strings 500 c-after-change-mark-abnormal-strings
501 c-change-expand-fl-region) 501 c-change-expand-fl-region)
502 (c objc) '(c-depropertize-new-text 502 (c objc) '(c-depropertize-new-text
503 c-parse-quotes-after-change 503 c-parse-quotes-after-change
504 c-after-change-re-mark-unbalanced-strings 504 c-after-change-mark-abnormal-strings
505 c-extend-font-lock-region-for-macros 505 c-extend-font-lock-region-for-macros
506 c-neutralize-syntax-in-CPP 506 c-neutralize-syntax-in-CPP
507 c-change-expand-fl-region) 507 c-change-expand-fl-region)
508 c++ '(c-depropertize-new-text 508 c++ '(c-depropertize-new-text
509 c-after-change-unmark-raw-strings
509 c-parse-quotes-after-change 510 c-parse-quotes-after-change
510 c-after-change-re-mark-unbalanced-strings 511 c-after-change-mark-abnormal-strings
511 c-extend-font-lock-region-for-macros 512 c-extend-font-lock-region-for-macros
512 c-after-change-re-mark-raw-strings
513 c-neutralize-syntax-in-CPP 513 c-neutralize-syntax-in-CPP
514 c-restore-<>-properties 514 c-restore-<>-properties
515 c-change-expand-fl-region) 515 c-change-expand-fl-region)
516 java '(c-depropertize-new-text 516 java '(c-depropertize-new-text
517 c-parse-quotes-after-change 517 c-parse-quotes-after-change
518 c-after-change-re-mark-unbalanced-strings 518 c-after-change-mark-abnormal-strings
519 c-restore-<>-properties 519 c-restore-<>-properties
520 c-change-expand-fl-region) 520 c-change-expand-fl-region)
521 awk '(c-depropertize-new-text 521 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."
678(make-variable-buffer-local 'c-new-BEG) 678(make-variable-buffer-local 'c-new-BEG)
679(defvar c-new-END 0) 679(defvar c-new-END 0)
680(make-variable-buffer-local 'c-new-END) 680(make-variable-buffer-local 'c-new-END)
681;; The following two variables record the values of `c-new-BEG' and 681
682;; `c-new-END' just after `c-new-END' has been adjusted for the length of text 682;; Buffer local variable which notes the value of calling `c-in-literal' just
683;; inserted or removed. They may be read by any after-change function (but 683;; before a change. It is one of 'string, 'c, 'c++ (for the two sorts of
684;; should not be altered by one). 684;; comments), or nil.
685(defvar c-old-BEG 0) 685(defvar c-old-END-literality nil)
686(make-variable-buffer-local 'c-old-BEG) 686(make-variable-buffer-local 'c-old-END-literality)
687(defvar c-old-END 0)
688(make-variable-buffer-local 'c-old-END)
689 687
690(defun c-common-init (&optional mode) 688(defun c-common-init (&optional mode)
691 "Common initialization for all CC Mode modes. 689 "Common initialization for all CC Mode modes.
@@ -900,7 +898,8 @@ Note that the style variables are always made local to the buffer."
900 898
901(defun c-depropertize-CPP (beg end) 899(defun c-depropertize-CPP (beg end)
902 ;; Remove the punctuation syntax-table text property from the CPP parts of 900 ;; Remove the punctuation syntax-table text property from the CPP parts of
903 ;; (c-new-BEG c-new-END). 901 ;; (c-new-BEG c-new-END), and remove all syntax-table properties from any
902 ;; raw strings within these CPP parts.
904 ;; 903 ;;
905 ;; This function is in the C/C++/ObjC values of 904 ;; This function is in the C/C++/ObjC values of
906 ;; `c-get-state-before-change-functions' and is called exclusively as a 905 ;; `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."
912 (goto-char (match-beginning 1)) 911 (goto-char (match-beginning 1))
913 (setq m-beg (point)) 912 (setq m-beg (point))
914 (c-end-of-macro) 913 (c-end-of-macro)
914 (save-excursion (c-depropertize-raw-strings-in-region m-beg (point)))
915 (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1))) 915 (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1)))
916 916
917 (while (and (< (point) end) 917 (while (and (< (point) end)
@@ -920,14 +920,16 @@ Note that the style variables are always made local to the buffer."
920 (goto-char (match-beginning 1)) 920 (goto-char (match-beginning 1))
921 (setq m-beg (point)) 921 (setq m-beg (point))
922 (c-end-of-macro)) 922 (c-end-of-macro))
923 (if (and ss-found (> (point) end)) 923 (when (and ss-found (> (point) end))
924 (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1))) 924 (save-excursion (c-depropertize-raw-strings-in-region m-beg (point)))
925 (c-clear-char-property-with-value m-beg (point) 'syntax-table '(1)))
925 926
926 (while (and (< (point) c-new-END) 927 (while (and (< (point) c-new-END)
927 (search-forward-regexp c-anchored-cpp-prefix c-new-END 'bound)) 928 (search-forward-regexp c-anchored-cpp-prefix c-new-END 'bound))
928 (goto-char (match-beginning 1)) 929 (goto-char (match-beginning 1))
929 (setq m-beg (point)) 930 (setq m-beg (point))
930 (c-end-of-macro) 931 (c-end-of-macro)
932 (save-excursion (c-depropertize-raw-strings-in-region m-beg (point)))
931 (c-clear-char-property-with-value 933 (c-clear-char-property-with-value
932 m-beg (point) 'syntax-table '(1))))) 934 m-beg (point) 'syntax-table '(1)))))
933 935
@@ -1213,6 +1215,7 @@ Note that the style variables are always made local to the buffer."
1213 "\"\\|\\s|" (point-max) t t) 1215 "\"\\|\\s|" (point-max) t t)
1214 (progn 1216 (progn
1215 (c-clear-char-property (1- (point)) 'syntax-table) 1217 (c-clear-char-property (1- (point)) 'syntax-table)
1218 (c-truncate-semi-nonlit-pos-cache (1- (point)))
1216 (not (eq (char-before) ?\"))))) 1219 (not (eq (char-before) ?\")))))
1217 (eq (char-before) ?\")) 1220 (eq (char-before) ?\"))
1218 (progn 1221 (progn
@@ -1247,27 +1250,38 @@ Note that the style variables are always made local to the buffer."
1247 (forward-char) 1250 (forward-char)
1248 (backward-sexp) 1251 (backward-sexp)
1249 (c-clear-char-property eoll-1 'syntax-table) 1252 (c-clear-char-property eoll-1 'syntax-table)
1253 (c-truncate-semi-nonlit-pos-cache eoll-1)
1250 (c-clear-char-property (point) 'syntax-table)) 1254 (c-clear-char-property (point) 'syntax-table))
1251 ;; Opening " at EOB. 1255 ;; Opening " at EOB.
1252 (c-clear-char-property (1- (point)) 'syntax-table)) 1256 (c-clear-char-property (1- (point)) 'syntax-table))
1253 (if (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) 1257 (when (and (c-search-backward-char-property 'syntax-table '(15) c-new-BEG)
1254 ;; Opening " on last line of text (without EOL). 1258 (eq (char-after) ?\")) ; Ignore an unterminated raw string's (.
1255 (c-clear-char-property (point) 'syntax-table)))) 1259 ;; Opening " on last line of text (without EOL).
1260 (c-clear-char-property (point) 'syntax-table)
1261 (c-truncate-semi-nonlit-pos-cache (point)))))
1256 1262
1257 (t (goto-char end) ; point-max 1263 (t (goto-char end) ; point-max
1258 (if (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) 1264 (when
1259 (c-clear-char-property (point) 'syntax-table)))) 1265 (and
1266 (c-search-backward-char-property 'syntax-table '(15) c-new-BEG)
1267 (eq (char-after) ?\"))
1268 (c-clear-char-property (point) 'syntax-table)
1269 (c-truncate-semi-nonlit-pos-cache (point)))))
1260 1270
1261 (unless (and c-multiline-string-start-char 1271 (unless (and c-multiline-string-start-char
1262 (not (c-characterp c-multiline-string-start-char))) 1272 (not (c-characterp c-multiline-string-start-char)))
1263 (when (eq end-literal-type 'string) 1273 (when (and (eq end-literal-type 'string)
1264 (c-clear-char-property (1- (cdr end-limits)) 'syntax-table)) 1274 (not (eq (char-before (cdr end-limits)) ?\()))
1275 (c-clear-char-property (1- (cdr end-limits)) 'syntax-table)
1276 (c-truncate-semi-nonlit-pos-cache (1- (cdr end-limits))))
1265 1277
1266 (when (eq beg-literal-type 'string) 1278 (when (and (eq beg-literal-type 'string)
1279 (eq (char-after (car beg-limits)) ?\"))
1267 (setq c-new-BEG (min c-new-BEG (car beg-limits))) 1280 (setq c-new-BEG (min c-new-BEG (car beg-limits)))
1268 (c-clear-char-property (car beg-limits) 'syntax-table))))) 1281 (c-clear-char-property (car beg-limits) 'syntax-table)
1282 (c-truncate-semi-nonlit-pos-cache (car beg-limits))))))
1269 1283
1270(defun c-after-change-re-mark-unbalanced-strings (beg end _old-len) 1284(defun c-after-change-mark-abnormal-strings (beg end _old-len)
1271 ;; Mark any unbalanced strings in the region (c-new-BEG c-new-END) with 1285 ;; Mark any unbalanced strings in the region (c-new-BEG c-new-END) with
1272 ;; string fence syntax-table text properties. 1286 ;; string fence syntax-table text properties.
1273 ;; 1287 ;;
@@ -1318,7 +1332,8 @@ Note that the style variables are always made local to the buffer."
1318 (min (1+ (point)) (point-max))))) 1332 (min (1+ (point)) (point-max)))))
1319 ((and (null beg-literal-type) 1333 ((and (null beg-literal-type)
1320 (goto-char beg) 1334 (goto-char beg)
1321 (eq (char-before) c-multiline-string-start-char) 1335 (and (not (bobp))
1336 (eq (char-before) c-multiline-string-start-char))
1322 (memq (char-after) c-string-delims)) 1337 (memq (char-after) c-string-delims))
1323 (cons (point) 1338 (cons (point)
1324 (progn 1339 (progn
@@ -1343,22 +1358,24 @@ Note that the style variables are always made local to the buffer."
1343 (while (progn 1358 (while (progn
1344 (setq s (parse-partial-sexp (point) c-new-END nil 1359 (setq s (parse-partial-sexp (point) c-new-END nil
1345 nil s 'syntax-table)) 1360 nil s 'syntax-table))
1346 (and (< (point) c-new-END) 1361 (and (< (point) c-new-END)
1347 (or (not (nth 3 s)) 1362 (or (not (nth 3 s))
1348 (not (memq (char-before) c-string-delims)))))) 1363 (not (memq (char-before) c-string-delims))))))
1349 ;; We're at the start of a string. 1364 ;; We're at the start of a string.
1350 (memq (char-before) c-string-delims))) 1365 (memq (char-before) c-string-delims)))
1351 (if (c-unescaped-nls-in-string-p (1- (point))) 1366 (unless (and (c-major-mode-is 'c++-mode)
1352 (looking-at "\\(\\\\\\(.\\|\n\\|\r\\)\\|[^\"]\\)*") 1367 (c-maybe-re-mark-raw-string))
1353 (looking-at (cdr (assq (char-before) c-string-innards-re-alist)))) 1368 (if (c-unescaped-nls-in-string-p (1- (point)))
1354 (cond 1369 (looking-at "\\(\\\\\\(.\\|\n|\\\r\\)\\|[^\"]\\)*")
1355 ((memq (char-after (match-end 0)) '(?\n ?\r)) 1370 (looking-at (cdr (assq (char-before) c-string-innards-re-alist))))
1356 (c-put-char-property (1- (point)) 'syntax-table '(15)) 1371 (cond
1357 (c-put-char-property (match-end 0) 'syntax-table '(15))) 1372 ((memq (char-after (match-end 0)) '(?\n ?\r))
1358 ((or (eq (match-end 0) (point-max)) 1373 (c-put-char-property (1- (point)) 'syntax-table '(15))
1359 (eq (char-after (match-end 0)) ?\\)) ; \ at EOB 1374 (c-put-char-property (match-end 0) 'syntax-table '(15)))
1360 (c-put-char-property (1- (point)) 'syntax-table '(15)))) 1375 ((or (eq (match-end 0) (point-max))
1361 (goto-char (min (1+ (match-end 0)) (point-max))) 1376 (eq (char-after (match-end 0)) ?\\)) ; \ at EOB
1377 (c-put-char-property (1- (point)) 'syntax-table '(15))))
1378 (goto-char (min (1+ (match-end 0)) (point-max))))
1362 (setq s nil))))) 1379 (setq s nil)))))
1363 1380
1364;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1381;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1721,7 +1738,6 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".")
1721 ;; (c-new-BEG c-new-END) will be the region to fontify. It may become 1738 ;; (c-new-BEG c-new-END) will be the region to fontify. It may become
1722 ;; larger than (beg end). 1739 ;; larger than (beg end).
1723 (setq c-new-END (- (+ c-new-END (- end beg)) old-len)) 1740 (setq c-new-END (- (+ c-new-END (- end beg)) old-len))
1724 (setq c-old-BEG c-new-BEG c-old-END c-new-END)
1725 1741
1726 (unless (c-called-from-text-property-change-p) 1742 (unless (c-called-from-text-property-change-p)
1727 (setq c-just-done-before-change nil) 1743 (setq c-just-done-before-change nil)