1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-02-27 18:30:47 -08:00

CC Mode: Enhance C++ Mode raw strings to multi-line strings for any language

* lisp/progmodes/cc-defs.el (cadar, caddr, cdddr): Add defsubsts for these for
when they are missing from the host Emacs.
(c-point): Add new `position' 'boll "beginning of logical line".
(c-clear-char-properties): Return the position of the lowest removed
property.

* lisp/progmodes/cc-engine.el (c-full-pp-to-literal): Fix for rare case where
LIMIT < START in parse-partial-sexp.
(c-old-beg-rs, c-old-end-rs, c-raw-string-end-delim-disrupted)
(c-raw-string-pos, c-raw-string-in-end-delim, c-depropertize-raw-string)
(c-depropertize-raw-strings-in-region, c-before-change-check-raw-strings)
(c-propertize-raw-string-id, c-propertize-raw-string-opener): Old functions
and variables removed or renamed "raw" -> "ml" and adapted.
(c-old-beg-ml, c-old-1-beg-ml, c-old-end-ml, c-beg-pos, c-end-pos)
(c-ml-string-end-delim-disrupted, c-depropertize-ml-string-delims)
(c-ml-string-delims-around-point,c-position-wrt-ml-delims)
(c-before-change-check-ml-strings, c-after-change-unmark-ml-strings)
(c-maybe-re-mark-ml-string, c-propertize-ml-string-id)
(c-propertize-ml-string-opener, c-depropertize-ml-string)
(c-depropertize-ml-strings-in-region): New functions and variables adapted and
possibly renamed from "raw" -> "ml".
(c-ml-string-make-closer-re, c-ml-string-make-opener-re)
(c-c++-make-ml-string-closer-re, c-c++-make-ml-string-opener-re)
(c-get-ml-closer, c-ml-string-opener-around-point)
(c-ml-string-opener-intersects-region, c-ml-string-opener-at-or-around-point)
(c-ml-string-back-to-neutral, c-ml-string-in-end-delim, c-neutralize-pos)
(c-neutralized-prop): New functions and variables.

* lisp/progmodes/cc-fonts.el (c-basic-matchers-before): Replace
c-font-lock-raw-strings with c-font-lock-ml-strings.
(c-font-lock-ml-strings): New function taking the place of the old
c-font-lock-ml-strings.

* lisp/progmodes/cc-langs.el (c-get-state-before-change-functions): Move
c-depropertize-CPP to the second item of the C++ entry, and replace
c-before-change-check-raw-strings by c-before-change-check-ml-strings.  Add a
new entry for Pike Mode.
(c-before-font-lock-functions): (Replace c-after-change-unmark-raw-strings by
c-after-change-unmark-ml-strings in the C++ entry, and add a new entry for
Pike Mode.
(c-ml-string-backslash-escapes, c-ml-string-non-punc-skip-chars)
(c-ml-string-opener-re, c-ml-string-max-opener-len, c-ml-string-any-closer-re)
(c-ml-string-max-closer-len, c-ml-string-max-closer-len-no-leader)
(c-ml-string-back-closer-re, c-make-ml-string-closer-re-function)
(c-make-ml-string-opener-re-function, c-ml-string-cpp-or-opener-re)
(c-cpp-or-ml-match-offset): New c-lang-defconsts and c-land-defvars.
(c-multiline-string-start-char): Remove the Pike Mode setting.

* lisp/progmodes/cc-mode.el (c-depropertize-CPP): Test for general ml strings
rather than C++ raw strings.
(c-unescaped-nls-in-string-p): Handle languages with ml strings.
(c-clear-string-fences): Fix bug with wrong parenthesisation.
(c-before-change-check-unbalanced-strings)
(c-after-change-mark-abnormal-strings, c-after-change-escape-NL-in-string):
Adapt for multi-line strings.
This commit is contained in:
Alan Mackenzie 2021-08-12 19:04:28 +00:00
parent 5d50acd0a6
commit c4d34d24e3
5 changed files with 1189 additions and 574 deletions

View file

@ -174,6 +174,10 @@ This variant works around bugs in `eval-when-compile' in various
;;; Macros.
(or (fboundp 'cadar) (defsubst cadar (elt) (car (cdar elt))))
(or (fboundp 'caddr) (defsubst caddr (elt) (car (cddr elt))))
(or (fboundp 'cdddr) (defsubst cdddr (elt) (cdr (cddr elt))))
(defmacro c--mapcan (fun liszt)
;; CC Mode equivalent of `mapcan' which bridges the difference
;; between the host [X]Emacsen."
@ -236,6 +240,7 @@ The current point is used if POINT isn't specified. POSITION can be
one of the following symbols:
`bol' -- beginning of line
`boll' -- beginning of logical line (i.e. without preceding escaped NL)
`eol' -- end of line
`eoll' -- end of logical line (i.e. without escaped NL)
`bod' -- beginning of defun
@ -266,6 +271,15 @@ to it is returned. This function does not modify the point or the mark."
(beginning-of-line)
(point))))
((eq position 'boll)
`(save-excursion
,@(if point `((goto-char ,point)))
(while (progn (beginning-of-line)
(when (not (bobp))
(eq (char-before (1- (point))) ?\\)))
(backward-char))
(point)))
((eq position 'eol)
(if (and (cc-bytecomp-fboundp 'line-end-position) (not point))
'(line-end-position)
@ -1254,6 +1268,9 @@ MODE is either a mode symbol or a list of mode symbols."
;; region that has been put with `c-put-char-property'. PROPERTY is
;; assumed to be constant.
;;
;; The returned value is the buffer position of the lowest character
;; whose PROPERTY was removed, or nil if there was none.
;;
;; Note that this function does not clean up the property from the
;; lists of the `rear-nonsticky' properties in the region, if such
;; are used. Thus it should not be used for common properties like
@ -1262,20 +1279,28 @@ MODE is either a mode symbol or a list of mode symbols."
;; This macro does hidden buffer changes.
(declare (debug t))
(setq property (eval property))
(if c-use-extents
;; XEmacs.
`(map-extents (lambda (ext ignored)
(delete-extent ext))
nil ,from ,to nil nil ',property)
;; Emacs.
(if (and (fboundp 'syntax-ppss)
(eq `,property 'syntax-table))
`(let ((-from- ,from) (-to- ,to))
(setq c-syntax-table-hwm
(min c-syntax-table-hwm
(c-min-property-position -from- -to- ',property)))
(remove-text-properties -from- -to- '(,property nil)))
`(remove-text-properties ,from ,to '(,property nil)))))
`(let* ((-to- ,to)
(ret (c-min-property-position ,from -to- ',property)))
(if (< ret -to-)
(progn
,(cond
(c-use-extents
;; XEmacs
`(map-extents (lambda (ext ignored)
(delete-extent ext))
nil ret -to- nil nil ',property))
((and (fboundp 'syntax-ppss)
(eq property 'syntax-table))
;; Emacs 'syntax-table
`(progn
(setq c-syntax-table-hwm
(min c-syntax-table-hwm ret))
(remove-text-properties ret -to- '(,property nil))))
(t
;; Emacs other property.
`(remove-text-properties ret -to- '(,property nil))))
ret)
nil)))
(defmacro c-clear-syn-tab-properties (from to)
;; Remove all occurrences of the `syntax-table' and `c-fl-syn-tab' text

File diff suppressed because it is too large Load diff

View file

@ -781,9 +781,9 @@ casts and declarations are fontified. Used on level 2 and higher."
;; Invalid single quotes.
c-font-lock-invalid-single-quotes
;; Fontify C++ raw strings.
,@(when (c-major-mode-is 'c++-mode)
'(c-font-lock-raw-strings))
;; Fontify multiline strings.
,@(when (c-lang-const c-ml-string-opener-re)
'(c-font-lock-ml-strings))
;; Fontify keyword constants.
,@(when (c-lang-const c-constant-kwds)
@ -1737,8 +1737,8 @@ casts and declarations are fontified. Used on level 2 and higher."
(c-font-lock-declarators limit t in-typedef
(not (c-bs-at-toplevel-p (point)))))))))))
(defun c-font-lock-raw-strings (limit)
;; Fontify C++ raw strings.
(defun c-font-lock-ml-strings (limit)
;; Fontify multi-line strings.
;;
;; This function will be called from font-lock for a region bounded by POINT
;; and LIMIT, as though it were to identify a keyword for
@ -1748,52 +1748,75 @@ casts and declarations are fontified. Used on level 2 and higher."
(let* ((state (c-semi-pp-to-literal (point)))
(string-start (and (eq (cadr state) 'string)
(car (cddr state))))
(raw-id (and string-start
(c-at-c++-raw-string-opener string-start)
(match-string-no-properties 1)))
(content-start (and raw-id (point))))
(open-delim (and string-start
(save-excursion
(goto-char (1+ string-start))
(c-ml-string-opener-around-point))))
(string-delims (and open-delim
(cons open-delim (c-get-ml-closer open-delim))))
found)
;; 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
(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
;; 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
(c-put-font-lock-face (match-beginning 0) (match-end 0)
'font-lock-warning-face)
(when
(and
(equal paren-prop '(15))
(not (c-search-forward-char-property 'syntax-table '(15) limit)))
(goto-char limit)))
(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)
(cond
;; Point is not in an ml string
((not string-delims)
(while (and (setq found (re-search-forward c-ml-string-opener-re
limit 'limit))
(> (match-beginning 0) (point-min))
(memq (c-get-char-property (1- (match-beginning 0)) 'face)
'(font-lock-comment-face font-lock-string-face
font-lock-comment-delimiter-face))))
(when found
(setq open-delim (cons (match-beginning 1)
(cons (match-end 1) (match-beginning 2)))
string-delims (cons open-delim (c-get-ml-closer open-delim)))
(goto-char (caar string-delims))))
;; Point is in the body of an ml string.
((and string-delims
(>= (point) (cadar string-delims))
(or (not (cdr string-delims))
(< (point) (cadr string-delims))))
(if (cdr string-delims)
(goto-char (cadr string-delims))
(if (equal (c-get-char-property (1- (cadar string-delims))
'syntax-table)
'(15)) ; "Always" the case.
;; The next search should be successful for an unterminated ml
;; string inside a macro, but not for any other unterminated
;; string.
(progn
(or (c-search-forward-char-property 'syntax-table '(15) limit)
(goto-char limit))
(setq string-delims nil))
(c-benign-error "Missing '(15) syntax-table property at %d"
(1- (cadar string-delims)))
(setq string-delims nil))))
;; Point is at or in a closing delimiter
((and string-delims
(cdr string-delims)
(>= (point) (cadr string-delims)))
(c-put-font-lock-face (cadr string-delims) (1+ (cadr string-delims))
'font-lock-string-face)
(c-remove-font-lock-face (1+ (cadr string-delims))
(caddr string-delims))
(goto-char (caddr string-delims))
(setq string-delims nil))
;; point is at or in an opening delimiter.
(t
(if (cdr string-delims)
(progn
(c-remove-font-lock-face (caar string-delims)
(1- (cadar string-delims)))
(c-put-font-lock-face (1- (cadar string-delims))
(cadar string-delims)
'font-lock-string-face))
(c-put-font-lock-face (caar string-delims) (cadar string-delims)
'font-lock-warning-face))
(goto-char (cadar string-delims)))))
nil))
(defun c-font-lock-c++-lambda-captures (limit)
;; Fontify the lambda capture component of C++ lambda declarations.

View file

@ -453,9 +453,9 @@ so that all identifiers are recognized as words.")
;; The value here may be a list of functions or a single function.
t 'c-before-change-check-unbalanced-strings
c++ '(c-extend-region-for-CPP
c-before-change-check-raw-strings
c-before-change-check-<>-operators
c-depropertize-CPP
c-before-change-check-ml-strings
c-before-change-check-<>-operators
c-truncate-bs-cache
c-before-change-check-unbalanced-strings
c-parse-quotes-before-change)
@ -467,6 +467,8 @@ so that all identifiers are recognized as words.")
java '(c-parse-quotes-before-change
c-before-change-check-unbalanced-strings
c-before-change-check-<>-operators)
pike '(c-before-change-check-ml-strings
c-before-change-check-unbalanced-strings)
awk 'c-awk-record-region-clear-NL)
(c-lang-defvar c-get-state-before-change-functions
(let ((fs (c-lang-const c-get-state-before-change-functions)))
@ -506,7 +508,7 @@ parameters \(point-min) and \(point-max).")
c-change-expand-fl-region)
c++ '(c-depropertize-new-text
c-after-change-escape-NL-in-string
c-after-change-unmark-raw-strings
c-after-change-unmark-ml-strings
c-parse-quotes-after-change
c-after-change-mark-abnormal-strings
c-extend-font-lock-region-for-macros
@ -519,6 +521,11 @@ parameters \(point-min) and \(point-max).")
c-after-change-mark-abnormal-strings
c-restore-<>-properties
c-change-expand-fl-region)
pike '(c-depropertize-new-text
c-after-change-escape-NL-in-string
c-after-change-unmark-ml-strings
c-after-change-mark-abnormal-strings
c-change-expand-fl-region)
awk '(c-depropertize-new-text
c-awk-extend-and-syntax-tablify-region))
(c-lang-defvar c-before-font-lock-functions
@ -620,6 +627,176 @@ Note that to set up a language to use this, additionally:
'(?\")))
(c-lang-defvar c-string-delims (c-lang-const c-string-delims))
;; The next section of the code defines multi-line ("ml") strings for each
;; language. By default, there are no ml strings in a language. To configure
;; them, set each needed lang const in the section. See further details in
;; cc-engine.el (search for "Handling of CC Mode multi-line strings.").
(c-lang-defconst c-ml-string-backslash-escapes
;; N.B. if `c-ml-string-backslash-escapes' is non-nil, you probably need a
;; `c-ml-string-any-closer-re' that scans backslashed characters, etc.
"If non-nil, a \\ character escapes the next character in a ml string.
Otherwise such a \\ will be marked to be handled as any other character."
t nil
pike t
)
(c-lang-defconst c-ml-string-non-punc-skip-chars
;; A `skip-chars-forward' argument which skips over all ml string characters
;; which don't need to be marked with punctuation ('(1)) syntax.
t (if (c-lang-const c-ml-string-backslash-escapes)
"^\""
"^\"\\"))
(c-lang-defvar c-ml-string-non-punc-skip-chars
(c-lang-const c-ml-string-non-punc-skip-chars))
(c-lang-defconst c-ml-string-opener-re
"If non-nil, a regexp that matches a multi-line string opener.
It may also match context.
Such an opener must be at least 2 characters long, and must
contain a \" character. (match-string 1) matches the actual
delimiter and (match-string 2) matches the actual \". If a
delimiter contains several \"s, it is recommended to configure
the first of them as \"the\" \"."
t nil
pike "\\(#\\(\"\\)\\)"
c++ "\\(R\\(\"\\)[^ ()\\\n\r\t]\\{0,16\\}(\\)")
(c-lang-defvar c-ml-string-opener-re (c-lang-const c-ml-string-opener-re))
(c-lang-defconst c-ml-string-max-opener-len
"If non-nil, the maximum length of a multi-line string opener."
t nil
pike 2
c++ 19)
(c-lang-defvar c-ml-string-max-opener-len
(c-lang-const c-ml-string-max-opener-len))
(c-lang-defconst c-ml-string-any-closer-re
"If non-nil, a regexp that matches any multi-line string closer.
It may also match context.
A search for this regexp starting at the end of the corresponding
opener must find the first closer as the first match.
Such a closer must include a \" character. (match-string 1)
matches the actual delimiter and and (match-string 2) matches the
actual \". If a delimiter contains several \"s, it is
recommended to regard the last of them as \"the\" \"."
t nil
pike "\\(?:\\=\\|[^\\\"]\\)\\(?:\\\\.\\)*\\(\\(\"\\)\\)"
c++ "\\()[^ ()\\n\r\t]\\{0,16\\}\\(\"\\)\\)")
;; csharp "\\(?:\\=\\|[^\"]\\)\\(?:\"\"\\)*\\(\\(\"\\)\\)\\(?:[^\"]\\|\\'\\)"
(c-lang-defvar c-ml-string-any-closer-re
(c-lang-const c-ml-string-any-closer-re))
(c-lang-defconst c-ml-string-max-closer-len
"If non-nil, the maximum length of a multi-line string closer.
This must include the length of any \"context trailer\" following
the actual closer and any \"context leader\" preceding it. This
variable is ignored when `c-ml-string-back-closer-re' is non-nil."
t nil
c++ 18)
(c-lang-defvar c-ml-string-max-closer-len
(c-lang-const c-ml-string-max-closer-len))
(c-lang-defconst c-ml-string-max-closer-len-no-leader
"If non-nil, the maximum length of a ml string closer without its leader.
By \"leader\" is meant the context bytes preceding the actual
multi-line string closer, that part of
`c-ml-string-any-closer-re''s match preceding (match-beginning 1)."
t nil
pike 1
;; 2
;; 3
c++ 18)
(c-lang-defvar c-ml-string-max-closer-len-no-leader
(c-lang-const c-ml-string-max-closer-len-no-leader))
(c-lang-defconst c-ml-string-back-closer-re
"A regexp to move back out of a putative ml closer point is in.
This variable need only be non-nil for languages with multi-line
string closers that can contain an indefinite length \"leader\"
preceding the actual closer. It was designed for formats where
an unbounded number of \\s or \"s might precede the closer
proper, for example in Pike Mode or csharp-mode.
If point is in a putative multi-line string closer, a backward
regexp search with `c-ml-string-back-closer-re' will leave point
in a \"safe place\", from where a forward regexp search with
`c-ml-string-any-closer-re' can test whether the original
position was inside an actual closer.
When non-nil, this variable should end in \"\\\\\\==\". Note that
such a backward search will match a minimal string, so a
\"context character\" is probably needed at the start of the
regexp. The value for csharp-mode would be something like
\"\\\\(:?\\\\`\\\\|[^\\\"]\\\\)\\\"*\\\\\\==\"."
t nil
pike "\\(:?\\`\\|[^\\\"]\\)\\(:?\\\\.\\)*\\="
;;pike ;; 2
;; "\\(:?\\`\\|[^\"]\\)\"*\\="
)
(c-lang-defvar c-ml-string-back-closer-re
(c-lang-const c-ml-string-back-closer-re))
(c-lang-defconst c-make-ml-string-closer-re-function
"If non-nil, a function which creates a closer regexp matching an opener.
Such a function is given one argument, a multi-line opener (a
string), and returns a regexp which will match the corresponding
closer. When this regexp matches, (match-string 1) should be the
actual closing delimiter, and (match-string 2) the \"active\" \"
it contains.
A forward regexp search for this regexp starting at the end of
the opener must find the closer as its first match."
t (if (c-lang-const c-ml-string-any-closer-re)
'c-ml-string-make-closer-re)
c++ 'c-c++-make-ml-string-closer-re)
(c-lang-defvar c-make-ml-string-closer-re-function
(c-lang-const c-make-ml-string-closer-re-function))
(c-lang-defconst c-make-ml-string-opener-re-function
"If non-nil, a function which creates an opener regexp matching a closer.
Such a function is given one argument, a multi-line closer (a
string), and returns a regexp which will match the corresponding
opener. When this regexp matches, (match-string 1) should be the
actual opening delimiter, and (match-string 2) the \"active\" \"
it contains.
A backward regexp search for this regexp starting at the start of
the closer might not find the opener as its first match, should
there be copies of the opener contained in the multi-line string."
t (if (c-lang-const c-ml-string-opener-re)
'c-ml-string-make-opener-re)
c++ 'c-c++-make-ml-string-opener-re)
(c-lang-defvar c-make-ml-string-opener-re-function
(c-lang-const c-make-ml-string-opener-re-function))
(c-lang-defconst c-ml-string-cpp-or-opener-re
;; A regexp which matches either a macro or a multi-line string opener.
t (concat "\\("
(or (c-lang-const c-anchored-cpp-prefix) "\\`a\\`")
"\\)\\|\\("
(or (c-lang-const c-ml-string-opener-re) "\\`a\\`")
"\\)"))
(c-lang-defvar c-ml-string-cpp-or-opener-re
(c-lang-const c-ml-string-cpp-or-opener-re))
(c-lang-defconst c-cpp-or-ml-match-offset
;; The offset to be added onto match numbers for a multi-line string in
;; matches for `c-cpp-or-ml-string-opener-re'.
t (if (c-lang-const c-anchored-cpp-prefix)
(+ 2 (regexp-opt-depth (c-lang-const c-anchored-cpp-prefix)))
2))
(c-lang-defvar c-cpp-or-ml-match-offset
(c-lang-const c-cpp-or-ml-match-offset))
;; End of ml string section.
(c-lang-defconst c-has-quoted-numbers
"Whether the language has numbers quoted like 4'294'967'295."
t nil
@ -860,9 +1037,15 @@ literals."
"Set if the language supports multiline string literals without escaped
newlines. If t, all string literals are multiline. If a character,
only literals where the open quote is immediately preceded by that
literal are multiline."
t nil
pike ?#)
literal are multiline.
Note that from CC Mode 5.36, this character use is obsolete,
having been superseded by the \"multi-line string\" mechanism.
If both mechanisms are set for a language, the newer one prevails
over the old `c-multiline-string-start-char'. See the variables
in the page containing `c-ml-string-opener-re' in cc-langs.el for
further directions."
t nil)
(c-lang-defvar c-multiline-string-start-char
(c-lang-const c-multiline-string-start-char))

View file

@ -1003,8 +1003,8 @@ 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)
(when (c-major-mode-is 'c++-mode)
(save-excursion (c-depropertize-raw-strings-in-region m-beg (point))))
(when c-ml-string-opener-re
(save-excursion (c-depropertize-ml-strings-in-region m-beg (point))))
(c-clear-char-property-with-value m-beg (point) 'syntax-table '(1)))
(while (and (< (point) end)
@ -1014,8 +1014,8 @@ Note that the style variables are always made local to the buffer."
(setq m-beg (point))
(c-end-of-macro))
(when (and ss-found (> (point) end))
(when (c-major-mode-is 'c++-mode)
(save-excursion (c-depropertize-raw-strings-in-region m-beg (point))))
(when c-ml-string-opener-re
(save-excursion (c-depropertize-ml-strings-in-region m-beg (point))))
(c-clear-char-property-with-value m-beg (point) 'syntax-table '(1)))
(while (and (< (point) c-new-END)
@ -1023,8 +1023,8 @@ 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)
(when (c-major-mode-is 'c++-mode)
(save-excursion (c-depropertize-raw-strings-in-region m-beg (point))))
(when c-ml-string-opener-re
(save-excursion (c-depropertize-ml-strings-in-region m-beg (point))))
(c-clear-char-property-with-value
m-beg (point) 'syntax-table '(1)))))
@ -1174,12 +1174,15 @@ Note that the style variables are always made local to the buffer."
)))))
(defun c-unescaped-nls-in-string-p (&optional quote-pos)
;; Return whether unescaped newlines can be inside strings.
;; Return whether unescaped newlines can be inside strings. If the current
;; language handles multi-line strings, the value of this function is always
;; nil.
;;
;; QUOTE-POS, if present, is the position of the opening quote of a string.
;; Depending on the language, there might be a special character before it
;; signifying the validity of such NLs.
(cond
(c-ml-string-opener-re nil)
((null c-multiline-string-start-char) nil)
((c-characterp c-multiline-string-start-char)
(and quote-pos
@ -1323,13 +1326,13 @@ Note that the style variables are always made local to the buffer."
(setq pos (c-min-property-position pos c-max-syn-tab-mkr
'c-fl-syn-tab))
(when (< pos c-max-syn-tab-mkr)
(goto-char pos))
(when (and (save-match-data
(c-search-backward-char-property-with-value-on-char
'c-fl-syn-tab '(15) ?\"
(max (- (point) 500) (point-min))))
(not (equal (c-get-char-property (point) 'syntax-table) '(1))))
(setq pos (1+ pos)))
(goto-char pos)
(when (and (save-match-data
(c-search-backward-char-property-with-value-on-char
'c-fl-syn-tab '(15) ?\"
(max (- (point) 500) (point-min))))
(not (equal (c-get-char-property (point) 'syntax-table) '(1))))
(setq pos (1+ pos))))
(while (< pos c-max-syn-tab-mkr)
(setq pos
(c-min-property-position pos c-max-syn-tab-mkr 'c-fl-syn-tab))
@ -1435,7 +1438,8 @@ Note that the style variables are always made local to the buffer."
;; quotes up until the next unescaped EOL. Also guard against the change
;; being the insertion of \ before an EOL, escaping it.
(cond
((c-characterp c-multiline-string-start-char)
((and (not c-ml-string-opener-re)
(c-characterp c-multiline-string-start-char))
;; The text about to be inserted might contain a multiline string
;; opener. Set c-new-END after anything which might be affected.
;; Go to the end of the putative multiline string.
@ -1461,7 +1465,8 @@ Note that the style variables are always made local to the buffer."
(< (point) (point-max))))))
(setq c-new-END (max (point) c-new-END)))
(c-multiline-string-start-char
((and (not c-ml-string-opener-re)
c-multiline-string-start-char)
(setq c-bc-changed-stringiness
(not (eq (eq end-literal-type 'string)
(eq beg-literal-type 'string))))
@ -1506,7 +1511,7 @@ Note that the style variables are always made local to the buffer."
;; Opening " at EOB.
(c-clear-syn-tab (1- (point))))
(when (and (c-search-backward-char-property 'syntax-table '(15) c-new-BEG)
(memq (char-after) c-string-delims)) ; Ignore an unterminated raw string's (.
(memq (char-after) c-string-delims)) ; Ignore an unterminated ml string's (.
;; Opening " on last line of text (without EOL).
(c-remove-string-fences)
(setq c-new-BEG (min c-new-BEG (point))))))
@ -1520,13 +1525,15 @@ Note that the style variables are always made local to the buffer."
(unless
(or (and
;; Don't set c-new-BEG/END if we're in a raw string.
;; Don't set c-new-BEG/END if we're in an ml string.
(eq beg-literal-type 'string)
(c-at-c++-raw-string-opener (car beg-limits)))
(c-ml-string-opener-at-or-around-point (car beg-limits)))
(and c-multiline-string-start-char
(not c-ml-string-opener-re)
(not (c-characterp c-multiline-string-start-char))))
(when (and (eq end-literal-type 'string)
(not (eq (char-before (cdr end-limits)) ?\())
(or (memq (char-before (cdr end-limits)) c-string-delims)
(memq (char-before (cdr end-limits)) '(?\n ?\r)))
(memq (char-after (car end-limits)) c-string-delims))
(setq c-new-END (max c-new-END (cdr end-limits)))
(when (equal (c-get-char-property (car end-limits) 'syntax-table)
@ -1549,6 +1556,7 @@ Note that the style variables are always made local to the buffer."
;; This function is called exclusively as an after-change function via
;; `c-before-font-lock-functions'.
(if (and c-multiline-string-start-char
(not c-ml-string-opener-re)
(not (c-characterp c-multiline-string-start-char)))
;; Only the last " might need to be marked.
(c-save-buffer-state
@ -1591,6 +1599,7 @@ Note that the style variables are always made local to the buffer."
((and (null beg-literal-type)
(goto-char beg)
(and (not (bobp))
(not c-ml-string-opener-re)
(eq (char-before) c-multiline-string-start-char))
(memq (char-after) c-string-delims))
(cons (point)
@ -1615,6 +1624,7 @@ Note that the style variables are always made local to the buffer."
(point))
c-new-END))
s)
(goto-char
(cond ((null beg-literal-type)
c-new-BEG)
@ -1638,8 +1648,9 @@ Note that the style variables are always made local to the buffer."
(and (memq (char-before) c-string-delims)
(not (nth 4 s))))) ; Check we're actually out of the
; comment. not stuck at EOB
(unless (and (c-major-mode-is 'c++-mode)
(c-maybe-re-mark-raw-string))
(unless
(and c-ml-string-opener-re
(c-maybe-re-mark-ml-string))
(if (c-unescaped-nls-in-string-p (1- (point)))
(looking-at "\\(\\\\\\(.\\|\n\\)\\|[^\"]\\)*")
(looking-at (cdr (assq (char-before) c-string-innards-re-alist))))
@ -1678,21 +1689,15 @@ Note that the style variables are always made local to the buffer."
(progn (goto-char end)
(setq lit-start (c-literal-start)))
(memq (char-after lit-start) c-string-delims)
(or (not (c-major-mode-is 'c++-mode))
(or (not c-ml-string-opener-re)
(progn
(goto-char lit-start)
(and (not (and (eq (char-before) ?R)
(looking-at c-c++-raw-string-opener-1-re)))
(not (and (eq (char-after) ?\()
(equal (c-get-char-property
(point) 'syntax-table)
'(15))))))
(not (c-ml-string-opener-at-or-around-point)))
(save-excursion
(c-beginning-of-macro))))
(goto-char (1+ end)) ; After the \
;; Search forward for EOLL
(setq lim (re-search-forward "\\(?:\\\\\\(?:.\\|\n\\)\\|[^\\\n\r]\\)*"
nil t))
;; Search forward for EOLL.
(setq lim (c-point 'eoll))
(goto-char (1+ end))
(when (c-search-forward-char-property-with-value-on-char
'syntax-table '(15) ?\" lim)