From edd753716f9c2a3893f53922ef50b5a3b1849e36 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Fri, 25 Oct 2024 20:35:32 +0000 Subject: [PATCH] CC Mode: correct handling of properties on #include <...> In C, Pike, and IDL Modes, deleting and reinserting such a < could create havoc with the category/syntax-table properties on the < and >. Also the contents of <...> should only get paren properties when the #include is present and correct. * lisp/progmodes/cc-fonts.el (c-cpp-matchers): Replace the c-make-font-lock-search-function which put properties on the <...> with a simple matcher. * lisp/progmodes/cc-langs.el (c-get-state-before-change-functions) (c-before-font-lock-functions): Add respectively c-before-change-include-<> and c-after-change-include-<> in the C, Pike and IDL entries of these variables. * lisp/progmodes/cc-mode.el (c-before-change-include-<>) (c-after-change-include-<>): New functions. (cherry picked from commit 76268160ba9262a8479589427b8e783db0242260) --- lisp/progmodes/cc-fonts.el | 32 +++++++------------ lisp/progmodes/cc-langs.el | 10 ++++-- lisp/progmodes/cc-mode.el | 64 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 22 deletions(-) diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index 0f086f8e812..3a87339e38a 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -564,26 +564,18 @@ stuff. Used on level 1 and higher." ;; since `font-lock-fontify-anchored-keywords' terminated ;; its loop at EOL without executing our lambda form at ;; all. - `((,(c-make-font-lock-search-function - (concat noncontinued-line-end - (c-lang-const c-opt-cpp-prefix) - re - (c-lang-const c-syntactic-ws) - "\\(<\\([^>\n\r]*\\)>?\\)") - `(,(+ ncle-depth re-depth sws-depth - (if (featurep 'xemacs) 2 1) - ) - font-lock-string-face t) - `((let ((beg (match-beginning - ,(+ ncle-depth re-depth sws-depth 1))) - (end (1- (match-end ,(+ ncle-depth re-depth - sws-depth 1))))) - (if (eq (char-after end) ?>) - (progn - (c-mark-<-as-paren beg) - (c-mark->-as-paren end)) - (c-unmark-<->-as-paren beg))) - nil)))))) + `((,(concat noncontinued-line-end + "\\(" ; To make the next ^ special. + (c-lang-const c-cpp-include-key) + "\\)" + (c-lang-const c-syntactic-ws) + "\\(<\\([^>\n\r]*\\)>?\\)") + ,(+ ncle-depth 1 + (regexp-opt-depth + (c-lang-const c-cpp-include-key)) + sws-depth + (if (featurep 'xemacs) 2 1)) + font-lock-string-face t)))) ;; #define. ,@(when (c-lang-const c-opt-cpp-macro-define) diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 010b0ed6b04..a256371f850 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -451,7 +451,8 @@ so that all identifiers are recognized as words.") (c-lang-defconst c-get-state-before-change-functions ;; For documentation see the following c-lang-defvar of the same name. ;; The value here may be a list of functions or a single function. - t 'c-before-change-check-unbalanced-strings + t '(c-before-change-include-<> + c-before-change-check-unbalanced-strings) c++ '(c-extend-region-for-CPP c-depropertize-CPP c-before-change-check-ml-strings @@ -463,6 +464,7 @@ so that all identifiers are recognized as words.") c-parse-quotes-before-change c-before-change-fix-comment-escapes) c '(c-extend-region-for-CPP + c-before-change-include-<> c-depropertize-CPP c-truncate-bs-cache c-before-change-check-unbalanced-strings @@ -480,7 +482,8 @@ so that all identifiers are recognized as words.") c-unmark-<>-around-region c-before-change-check-unbalanced-strings c-before-change-check-<>-operators) - pike '(c-before-change-check-ml-strings + pike '(c-before-change-include-<> + 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 @@ -511,6 +514,7 @@ parameters \(point-min) and \(point-max).") t '(c-depropertize-new-text c-after-change-escape-NL-in-string c-after-change-mark-abnormal-strings + c-after-change-include-<> c-change-expand-fl-region) c '(c-depropertize-new-text c-after-change-fix-comment-escapes @@ -518,6 +522,7 @@ parameters \(point-min) and \(point-max).") c-parse-quotes-after-change c-after-change-mark-abnormal-strings c-extend-font-lock-region-for-macros + c-after-change-include-<> c-neutralize-syntax-in-CPP c-change-expand-fl-region) objc '(c-depropertize-new-text @@ -553,6 +558,7 @@ parameters \(point-min) and \(point-max).") c-after-change-escape-NL-in-string c-after-change-unmark-ml-strings c-after-change-mark-abnormal-strings + c-after-change-include-<> c-change-expand-fl-region) awk '(c-depropertize-new-text c-awk-extend-and-syntax-tablify-region)) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 137217d7bef..ebe8b8e45ba 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -1996,6 +1996,70 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") (defvar c-new-id-is-type nil) (make-variable-buffer-local 'c-new-id-is-type) +(defun c-before-change-include-<> (beg end) + "Remove category/syntax-table properties from each #include <..>. +In particular, from the < and > characters which have been marked as parens +using these properties. This is done on every such #include <..> with a +portion between BEG and END. + +This function is used solely as a member of +`c-get-state-before-change-functions' where it should appear early, before +`c-depropertize-CPP'. It should be used only together with +`c-after-change-include-<>'." + (c-save-buffer-state ((search-end (progn (goto-char end) + (c-end-of-macro) + (point))) + hash-pos) + (goto-char beg) + (c-beginning-of-macro) + (while (and (< (point) search-end) + (search-forward-regexp c-cpp-include-key search-end 'bound) + (setq hash-pos (match-beginning 0))) + (save-restriction + (narrow-to-region (point-min) (c-point 'eoll)) + (c-forward-comments)) + (when (and (< (point) search-end) + (looking-at "\\s(") + (looking-at "\\(<\\)[^>\n\r]*\\(>\\)?") + (not (cdr (c-semi-pp-to-literal hash-pos)))) + (c-unmark-<->-as-paren (match-beginning 1)) + (when (< hash-pos c-new-BEG) + (setq c-new-BEG hash-pos)) + (when (match-beginning 2) + (c-unmark-<->-as-paren (match-beginning 2)) + (when (> (match-end 2) c-new-END) + (setq c-new-END (match-end 2)))))))) + +(defun c-after-change-include-<> (beg end _old-len) + "Apply category/syntax-table properties to each #include <..>. +In particular, to the < and > characters to mark them as matching parens +using these properties. This is done on every such #include <..> with a +portion between BEG and END. + +This function is used solely as a member of +`c-before-font-lock-functions' where is should appear late, but before +`c-neutralize-syntax-in-CPP'. It should be used only together with +`c-before-change-include-<>'." + (c-save-buffer-state ((search-end (progn (goto-char end) + (c-end-of-macro) + (point))) + hash-pos) + (goto-char beg) + (c-beginning-of-macro) + (while (and (< (point) search-end) + (search-forward-regexp c-cpp-include-key search-end 'bound) + (setq hash-pos (match-beginning 0))) + (save-restriction + (narrow-to-region (point-min) (c-point 'eoll)) + (c-forward-comments)) + (when (and (< (point) search-end) + (looking-at "\\(<\\)[^>\n\r]*\\(>\\)") + (not (cdr (c-semi-pp-to-literal (match-beginning 0))))) + (c-mark-<-as-paren (match-beginning 1)) + (when (< hash-pos c-new-BEG) (setq c-new-BEG hash-pos)) + (c-mark->-as-paren (match-beginning 2)) + (when (> (match-end 2) c-new-END) (setq c-new-END (match-end 2))))))) + (defun c-before-change-fix-comment-escapes (beg end) "Remove punctuation syntax-table text properties from C/C++ comment markers. This is to handle the rare case of two or more backslashes at an -- 2.39.5