summaryrefslogtreecommitdiff
path: root/lisp/progmodes/cc-mode.el
diff options
context:
space:
mode:
authorAlan Mackenzie <acm@muc.de>2022-06-18 16:41:57 +0000
committerAlan Mackenzie <acm@muc.de>2022-06-18 16:41:57 +0000
commit9b44824620fd500b9e7094bd1a8ca23608cb2e5b (patch)
tree77f38c458cc3c191e08edb30f884c00b4f49f69b /lisp/progmodes/cc-mode.el
parent7e1f84fa3bc7dfd84415813889c91070c0759da2 (diff)
downloademacs-9b44824620fd500b9e7094bd1a8ca23608cb2e5b.tar.gz
CC Mode: Add accurate handling for backslash in C line and block comments
This is needed to handle the idiosyncratic meaning of backslash in comments in the C and C++ standards. * lisp/progmodes/cc-engine.el: Correct a spelling error. * lisp/progmodes/cc-mode.el (c-before-change-fix-comment-escapes) (c-after-change-fix-comment-escapes): New functions. * lisp/progmodes/cc-langs.el (c-get-state-before-change-functions): Add c-before-change-fix-comment-escapes to the C/Objc and C++ values. (c-before-font-lock-functions): Add c-after-change-fix-comment-escapes to the C/Objc and C++ values.
Diffstat (limited to 'lisp/progmodes/cc-mode.el')
-rw-r--r--lisp/progmodes/cc-mode.el82
1 files changed, 81 insertions, 1 deletions
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index ae96cdbd2fe..70fc1cb73a9 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -1979,6 +1979,87 @@ 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-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
+end of line in a // comment or the equally rare case of a
+backslash preceding the terminator of a /* comment, as \\*/.
+
+This function is used solely as a member of
+`c-get-state-before-change-functions', where it should appear
+late in that variable, and it must be used only together with
+`c-after-change-fix-comment-escapes'.
+
+Note that the function currently only handles comments beginning
+with // and /*, not more generic line and block comments."
+ (c-save-buffer-state (end-state)
+ (setq end-state (c-full-pp-to-literal end))
+ (when (memq (cadr end-state) '(c c++))
+ (goto-char (max (- beg 2) (point-min)))
+ (if (eq (cadr end-state) 'c)
+ (when (search-forward "\\*/"
+ (or (cdr (caddr end-state)) (point-max)) t)
+ (c-clear-char-property (match-beginning 0) 'syntax-table)
+ (c-truncate-lit-pos-cache (match-beginning 0)))
+ (while (search-forward "\\\\\n"
+ (or (cdr (caddr end-state)) (point-max)) t)
+ (c-clear-char-property (match-beginning 0) 'syntax-table)
+ (c-truncate-lit-pos-cache (match-beginning 0)))))))
+
+(defun c-after-change-fix-comment-escapes (beg end _old-len)
+ "Apply punctuation syntax-table text properties to C/C++ comment markers.
+This is to handle the rare case of two or more backslashes at an
+end of line in a // comment or the equally rare case of a
+backslash preceding the terminator of a /* comment, as \\*/.
+
+This function is used solely as a member of
+`c-before-font-lock-functions', where it should appear early in
+that variable, and it must be used only together with
+`c-before-change-fix-comment-escapes'.
+
+Note that the function currently only handles comments beginning
+with // and /*, not more generic line and block comments."
+ (c-save-buffer-state (state)
+ ;; We cannot use `c-full-pp-to-literal' in this function, since the
+ ;; `syntax-table' text properties after point are not yet in a consistent
+ ;; state.
+ (setq state (c-semi-pp-to-literal beg))
+ (goto-char (if (memq (cadr state) '(c c++))
+ (caddr state)
+ (max (- beg 2) (point-min))))
+ (while
+ (re-search-forward "\\\\\\(\\(\\\\\n\\)\\|\\(\\*/\\)\\)"
+ (min (+ end 2) (point-max)) t)
+ (setq state (c-semi-pp-to-literal (match-beginning 0)))
+ (when (cond
+ ((eq (cadr state) 'c)
+ (match-beginning 3))
+ ((eq (cadr state) 'c++)
+ (match-beginning 2)))
+ (c-put-char-property (match-beginning 0) 'syntax-table '(1))
+ (c-truncate-lit-pos-cache (match-beginning 0))))
+
+ (goto-char end)
+ (setq state (c-semi-pp-to-literal (point)))
+ (cond
+ ((eq (cadr state) 'c)
+ (when (search-forward "*/" nil t)
+ (when (eq (char-before (match-beginning 0)) ?\\)
+ (c-put-char-property (1- (match-beginning 0)) 'syntax-table '(1))
+ (c-truncate-lit-pos-cache (1- (match-beginning 0))))))
+ ((eq (cadr state) 'c++)
+ (while
+ (progn
+ (end-of-line)
+ (and (eq (char-before) ?\\)
+ (progn
+ (when (eq (char-before (1- (point))) ?\\)
+ (c-put-char-property (- (point) 2) 'syntax-table '(1))
+ (c-truncate-lit-pos-cache (1- (point))))
+ t)
+ (not (eobp))))
+ (forward-char))))))
+
(defun c-update-new-id (end)
;; Note the bounds of any identifier that END is in or just after, in
;; `c-new-id-start' and `c-new-id-end'. Otherwise set these variables to
@@ -1990,7 +2071,6 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".")
c-new-id-end (and id-beg
(progn (c-end-of-current-token) (point)))))))
-
(defun c-post-command ()
;; If point was inside of a new identifier and no longer is, record that
;; fact.