From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.bugs Subject: bug#15212: 24.3.50; c++-mode doesn't support raw string literals Date: Mon, 6 Jun 2016 16:32:03 +0000 Message-ID: <20160606163203.GA19322__7012.11844939298$1465230889$gmane$org@acm.fritz.box> References: <8C5AB533-B326-424B-9612-0B4858BC80BF@gmail.com> <20160403183638.GE3537@acm.fritz.box> <20160528144045.GB2950@acm.fritz.box> <20160529213616.GC3367@acm.fritz.box> <20160531222135.GC20373@acm.fritz.box> <20160602160741.GC4067@acm.fritz.box> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="u3/rZRmxL6MmkK24" X-Trace: ger.gmane.org 1465230889 14303 80.91.229.3 (6 Jun 2016 16:34:49 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Mon, 6 Jun 2016 16:34:49 +0000 (UTC) Cc: 15212@debbugs.gnu.org To: Ivan Andrus Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Mon Jun 06 18:34:38 2016 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1b9xU4-0002yH-Am for geb-bug-gnu-emacs@m.gmane.org; Mon, 06 Jun 2016 18:34:36 +0200 Original-Received: from localhost ([::1]:43663 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b9xU3-0002V2-IH for geb-bug-gnu-emacs@m.gmane.org; Mon, 06 Jun 2016 12:34:35 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:45335) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b9xRh-0000dj-Na for bug-gnu-emacs@gnu.org; Mon, 06 Jun 2016 12:32:12 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1b9xRe-00025z-Pe for bug-gnu-emacs@gnu.org; Mon, 06 Jun 2016 12:32:09 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:44615) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b9xRa-00025W-Ie; Mon, 06 Jun 2016 12:32:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1b9xRa-00028b-BT; Mon, 06 Jun 2016 12:32:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Mon, 06 Jun 2016 16:32:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 15212 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: Original-Received: via spool by 15212-submit@debbugs.gnu.org id=B15212.14652307208210 (code B ref 15212); Mon, 06 Jun 2016 16:32:02 +0000 Original-Received: (at 15212) by debbugs.gnu.org; 6 Jun 2016 16:32:00 +0000 Original-Received: from localhost ([127.0.0.1]:56952 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1b9xRY-00028K-1b for submit@debbugs.gnu.org; Mon, 06 Jun 2016 12:32:00 -0400 Original-Received: from mail.muc.de ([193.149.48.3]:36842) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1b9xRW-00028A-AU for 15212@debbugs.gnu.org; Mon, 06 Jun 2016 12:31:59 -0400 Original-Received: (qmail 47766 invoked by uid 3782); 6 Jun 2016 16:31:55 -0000 Original-Received: from acm.muc.de (p4FC46CBB.dip0.t-ipconnect.de [79.196.108.187]) by colin.muc.de (tmda-ofmipd) with ESMTP; Mon, 06 Jun 2016 18:31:54 +0200 Original-Received: (qmail 19395 invoked by uid 1000); 6 Jun 2016 16:32:03 -0000 Content-Disposition: inline In-Reply-To: <20160602160741.GC4067@acm.fritz.box> User-Agent: Mutt/1.5.24 (2015-08-30) X-Delivery-Agent: TMDA/1.1.12 (Macallan) X-Primary-Address: acm@muc.de X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:119160 Archived-At: --u3/rZRmxL6MmkK24 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello again, Ivan. On Thu, Jun 02, 2016 at 04:07:41PM +0000, Alan Mackenzie wrote: [ .... ] > It is not yet a workable patch, since it fails to take proper account of > macros and comments. Indeed, the fontification fails when the raw string > is inside a macro. CC Mode has become somewhat unwieldy in this area, > and I'll be working on it in the next few days. > Until then ..... In this Email is a patch which does support macros, and (at least to some extent) comments. If there is an unbalanced raw string opener inside a macro, the rest of the macro gets string face, but the text after the macro should be unaffected by it. The patch should be quite close to release condition. As always, it should apply cleanly to the savannah master branch. Again, as always, after applying the patch, please recompile (at least) cc-langs.el, cc-fonts.el, cc-engine.el, and cc-mode.el Could you try it in your real code, please, and if you have time, try and break it. I'm enclosing the current edition of my test file again. I look forward to hearing back from you. diff -r d83a74c6ec31 cc-engine.el --- a/cc-engine.el Sun May 29 11:59:26 2016 +0000 +++ b/cc-engine.el Mon Jun 06 16:15:05 2016 +0000 @@ -85,8 +85,9 @@ ;; ;; 'syntax-table ;; Used to modify the syntax of some characters. It is used to -;; mark the "<" and ">" of angle bracket parens with paren syntax, and -;; to "hide" obtrusive characters in preprocessor lines. +;; mark the "<" and ">" of angle bracket parens with paren syntax, to +;; "hide" obtrusive characters in preprocessor lines, and to mark C++ +;; raw strings to enable their fontification. ;; ;; This property is used on single characters and is therefore ;; always treated as front and rear nonsticky (or start and end open @@ -2295,7 +2296,8 @@ ;; (STATE TYPE (BEG . END)) if TO is in a literal; or ;; (STATE) otherwise, ;; where STATE is the parsing state at TO, TYPE is the type of the literal - ;; (one of 'c, 'c++, 'string) and (BEG . END) is the boundaries of the literal. + ;; (one of 'c, 'c++, 'string) and (BEG . END) is the boundaries of the literal, + ;; including the delimiters. ;; ;; Unless NOT-IN-DELIMITER is non-nil, when TO is inside a two-character ;; comment opener, this is recognized as being in a comment literal. @@ -5673,6 +5675,9 @@ ;; 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) (defun c-before-change-check-<>-operators (beg end) ;; Unmark certain pairs of "< .... >" which are currently marked as @@ -5793,6 +5798,329 @@ 'c-decl-arg-start))))))) (or (c-forward-<>-arglist nil) (forward-char))))) + + +;; Functions to handle C++ raw strings. +;; +;; 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. +;; +;; CC Mode handles C++ raw strings by the use of `syntax-table' text +;; properties as follows: +;; +;; (i) On a validly terminated raw string, no `syntax-table' text properties +;; are applied to the opening and closing delimiters, but any " in the +;; 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) +;; 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)'). +;; +;; `c-font-lock-c++-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. +;; +;; (iii) Inside a macro, a valid raw string is handled as in (i). An +;; unmatched opening delimiter is handled slightly differently. In addition +;; to the "punctuation" and "string fence" properties on the delimiter, +;; another "string fence" `syntax-table' property is applied to the last +;; possible character of the macro before the terminating linefeed (if there +;; is such a character after the "("). This "last possible" character is +;; never a backslash escaping the end of line. If the character preceding +;; this "last possible" character is itself a backslash, this preceding +;; character gets a "punctuation" `syntax-table' value. If the "(" is +;; already at the end of the macro, it gets the "punctuaion" 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. + + +(defun c-raw-string-pos () + ;; Get POINT's relationship to any containing raw string. + ;; If point isn't in a raw string, return nil. + ;; Otherwise, return the following list: + ;; + ;; (POS B\" B\( E\) E\") + ;; + ;; , where POS is the symbol `open-delim' if point is in the opening + ;; delimiter, the symbol `close-delim' if it's in the closing delimiter, and + ;; nil if it's in the string body. B\", B\(, E\), E\" are the positions of + ;; the opening and closing quotes and parentheses of a correctly terminated + ;; raw string. (N.B.: E\) and E\" are NOT on the "outside" of these + ;; 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 + ;; properties being set. + (let* ((safe (c-state-semi-safe-place (point))) + (state (c-state-pp-to-literal safe (point))) + open-quote-pos open-paren-pos close-paren-pos close-quote-pos id) + (save-excursion + (when + (and + (cond + ((null (cadr state)) + (or (eq (char-after) ?\") + (search-backward "\"" (max (- (point) 17) (point-min)) t))) + ((and (eq (cadr state) 'string) + (goto-char (car (nth 2 state))) + (or (eq (char-after) ?\") + (search-backward "\"" (max (- (point) 17) (point-min)) t)) + (not (bobp))))) + (eq (char-before) ?R) + (looking-at "\"\\([^ ()\\\n\r\t]\\{,16\\}\\)(")) + (setq open-quote-pos (point) + open-paren-pos (match-end 1) + id (match-string-no-properties 1)) + (goto-char (1+ open-paren-pos)) + (when (and (not (c-get-char-property open-paren-pos 'syntax-table)) + (search-forward (concat ")" id "\"") nil t)) + (setq close-paren-pos (match-beginning 0) + close-quote-pos (1- (point)))))) + (and open-quote-pos + (list + (cond + ((<= (point) open-paren-pos) + 'open-delim) + ((and close-paren-pos + (> (point) close-paren-pos)) + 'close-delim) + (t nil)) + open-quote-pos open-paren-pos close-paren-pos close-quote-pos)))) + +(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 its + ;; unmatched) or the raw string. + ;; + ;; 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. + (let ((open-paren-prop (c-get-char-property open-paren 'syntax-table))) + (cond + ((null open-paren-prop) + ;; A terminated raw string + (if (search-forward (concat ")" id "\"") nil t) + (c-clear-char-property-with-value + (1+ open-paren) (match-beginning 0) 'syntax-table '(1)))) + ((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 + ;; the open parenthesis right up against the end of macro + (c-clear-char-property open-quote 'syntax-table) + (c-clear-char-property open-paren 'syntax-table)) + (t + ;; An unterminated string in a macro, with at least one char after the + ;; open paren + (c-clear-char-property open-quote 'syntax-table) + (c-clear-char-property open-paren 'syntax-table) + (let ((string-fence-pos + (save-excursion + (goto-char (1+ open-paren)) + (c-search-forward-char-property 'syntax-table '(15) bound)))) + (when string-fence-pos + (c-clear-char-property string-fence-pos 'syntax-table))) + )))) + +(defun c-depropertize-raw-strings-in-region (start finish) + ;; Remove any `syntax-table' text properties associated with C++ raw strings + ;; contained in the region (START FINISH). Point is undefined at entry and + ;; exit, and the return value has no significance. + (goto-char start) + (while (and (< (point) finish) + (re-search-forward + (concat "\\(" ; 1 + c-anchored-cpp-prefix ; 2 + "\\)\\|\\(" ; 3 + "R\"\\([^ ()\\\n\r\t]\\{,16\\}\\)(" ; 4 + "\\)") + finish 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 + (c-depropertize-raw-string + (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]\\{,16\\}\\)(" eom t)) + (c-depropertize-raw-string + (match-string-no-properties 1) ; id + (1+ (match-beginning 0)) ; open quote + (match-end 1) ; open paren + eom))))))) ; bound. + +(defun c-before-change-check-c++-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. + ;; + ;; 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'. + (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!!! + ; 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))) + +(defun c-propertize-raw-string-opener (id open-quote open-paren bound) + ;; Point is immediately after a raw string opening delimiter. Apply any + ;; pertinent `syntax-table' text properties to the delimiter and also the + ;; raw string, should there be a valid matching closing delimiter. + ;; + ;; 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 + (forward-char)) + (goto-char after-quote)) + (c-put-char-property open-quote 'syntax-table '(1)) ; punctuation + (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 + (concat "\\(" ; 1 + "\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)*" ; 2-4 + "\\(\\\\.\\)" ; 5 + "\\|" + "\\(\\`\\|[^\\]\\|\\(\\`[^\\]?\\|[^\\][^\\]\\)\\(\\\\\\(.\\|\n\\)\\)+\\)" ; 6-9 + "\\([^\\]\\)" ; 10 + "\\)" + "\\(\\\\\n\\)*\\=")) ; 11 + (1+ open-paren) t)) + (if (match-beginning 10) + (c-put-char-property (match-beginning 10) 'syntax-table '(15)) + (c-put-char-property (match-beginning 5) 'syntax-table '(1)) + (c-put-char-property (1+ (match-beginning 5)) 'syntax-table '(15))) + (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. + ;; + ;; 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 + ;; 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))) + (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]\\{,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. + (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]\\{,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 + ;; Handling of small scale constructs like types and names. diff -r d83a74c6ec31 cc-fonts.el --- a/cc-fonts.el Sun May 29 11:59:26 2016 +0000 +++ b/cc-fonts.el Mon Jun 06 16:15:05 2016 +0000 @@ -717,6 +717,10 @@ (concat ".\\(" c-string-limit-regexp "\\)") '((c-font-lock-invalid-string))) + ;; Fontify C++ raw strings. + ,@(when (c-major-mode-is 'c++-mode) + '(c-font-lock-c++-raw-strings)) + ;; Fontify keyword constants. ,@(when (c-lang-const c-constant-kwds) (let ((re (c-make-keywords-re nil (c-lang-const c-constant-kwds)))) @@ -1572,6 +1576,44 @@ (c-forward-syntactic-ws) (c-font-lock-declarators limit t in-typedef))))))) +(defun c-font-lock-c++-raw-strings (limit) + ;; Fontify C++ raw 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 + ;; font-lock-keyword-face. It always returns NIL to inhibit this and + ;; prevent a repeat invocation. See elisp/lispref page "Search-based + ;; Fontification". + (while (search-forward-regexp + "R\\(\"\\)\\([^ ()\\\n\r\t]\\{,16\\}\\)(" limit t) + (when ;; (eq (c-get-char-property (1- (point)) 'face) + ;; 'font-lock-string-face) + (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)))) + (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-put-font-lock-face (match-beginning 1) (match-end 2) 'default) + (when (search-forward-regexp + (concat ")\\(" (regexp-quote (match-string-no-properties 2)) + "\\)\"") + limit t) + (c-put-font-lock-face (match-beginning 1) (point) + 'default)))))) + nil) + (c-lang-defconst c-simple-decl-matchers "Simple font lock matchers for types and declarations. These are used on level 2 only and so aren't combined with `c-complex-decl-matchers'." diff -r d83a74c6ec31 cc-langs.el --- a/cc-langs.el Sun May 29 11:59:26 2016 +0000 +++ b/cc-langs.el Mon Jun 06 16:15:05 2016 +0000 @@ -457,9 +457,12 @@ ;; The value here may be a list of functions or a single function. t nil c++ '(c-extend-region-for-CPP + c-before-change-check-c++-raw-strings c-before-change-check-<>-operators + c-depropertize-CPP c-invalidate-macro-cache) (c objc) '(c-extend-region-for-CPP + c-depropertize-CPP c-invalidate-macro-cache) ;; java 'c-before-change-check-<>-operators awk 'c-awk-record-region-clear-NL) @@ -493,6 +496,7 @@ c-neutralize-syntax-in-and-mark-CPP c-change-expand-fl-region) c++ '(c-extend-font-lock-region-for-macros + c-after-change-re-mark-raw-strings c-neutralize-syntax-in-and-mark-CPP c-restore-<>-properties c-change-expand-fl-region) diff -r d83a74c6ec31 cc-mode.el --- a/cc-mode.el Sun May 29 11:59:26 2016 +0000 +++ b/cc-mode.el Mon Jun 06 16:15:05 2016 +0000 @@ -649,6 +649,14 @@ (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) (defun c-common-init (&optional mode) "Common initialization for all CC Mode modes. @@ -859,6 +867,31 @@ (memq (cadr (backtrace-frame 3)) '(put-text-property remove-list-of-text-properties))) +(defun c-depropertize-CPP (beg end) + ;; Remove the punctuation syntax-table text property from the CPP parts of + ;; (c-new-BEG c-new-END). + ;; + ;; This function is in the C/C++/ObjC values of + ;; `c-get-state-before-change-functions' and is called exclusively as a + ;; before change function. + (goto-char c-new-BEG) + (while (and (< (point) beg) + (search-forward-regexp c-anchored-cpp-prefix beg t)) + (goto-char (match-beginning 1)) + (let ((m-beg (point))) + (c-end-of-macro) + (c-clear-char-property-with-value + m-beg (min (point) beg) 'syntax-table '(1)))) + + (goto-char end) + (while (and (< (point) c-new-END) + (search-forward-regexp c-anchored-cpp-prefix c-new-END t)) + (goto-char (match-beginning 1)) + (let ((m-beg (point))) + (c-end-of-macro) + (c-clear-char-property-with-value + m-beg (min (point) c-new-END) 'syntax-table '(1))))) + (defun c-extend-region-for-CPP (beg end) ;; Adjust `c-new-BEG', `c-new-END' respectively to the beginning and end of ;; any preprocessor construct they may be in. @@ -949,9 +982,9 @@ ;; Note: SPEED _MATTERS_ IN THIS FUNCTION!!! ;; ;; This function might make hidden buffer changes. - (c-save-buffer-state (limits ) + (c-save-buffer-state (limits) ;; Clear 'syntax-table properties "punctuation": - (c-clear-char-property-with-value c-new-BEG c-new-END 'syntax-table '(1)) + ;; (c-clear-char-property-with-value c-new-BEG c-new-END 'syntax-table '(1)) ;; CPP "comment" markers: (if (memq 'category-properties c-emacs-features) ; GNU Emacs. @@ -1101,8 +1134,8 @@ ;; (c-new-BEG c-new-END) will be the region to fontify. It may become ;; larger than (beg end). - ;; (setq c-new-BEG beg c-new-END 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) > > -Ivan -- Alan Mackenzie (Nuremberg, Germany). --u3/rZRmxL6MmkK24 Content-Type: text/x-c; charset=us-ascii Content-Disposition: attachment; filename="raw-string.cc" char foo [] = R"(foo)"; char bar [] = // R"foo(bar)foo"; R"foo(bar)foo"; char empty [] = R"()"; char quote1 [] = R"34(")34"; char quote2 [] = R"34(fooo"bar)34"; char sixteen [] = R"0123456789abcdef(sixteen)0123456789abcdef"; char seventeen [] = R"0123456789abcdefg(seventeen)0123456789abcdefg"; char multi_line [] = R"(First line. #error: This should fontify as a CPP construct. Second line. Third line.)"; char brackets [] = R"0x22[(foobar)0x22["; #define FOO(bar) char bar [] = R"bar(abcd"efgh)bar" R"baz(ij"kl)baz" #define MULTILINE(bar) char bar [] = R"bar(\ \ )bar" \ )bar #define BROKEN(bar) char bar [] = R"foobar(a\n\ char baz [] = R"baz(baz)baz"; char bar [] = R"foo(bar)foo"; char empty [] = R"()"; char baz [] = R"baz(baz)foo"; --u3/rZRmxL6MmkK24--