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.
This commit is contained in:
Alan Mackenzie 2024-10-25 20:35:32 +00:00
parent 3d508157e0
commit 76268160ba
3 changed files with 84 additions and 22 deletions

View file

@ -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)

View file

@ -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))

View file

@ -2009,6 +2009,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