From: Alan Mackenzie <acm@muc.de>
To: "Herman Géza" <geza.herman@gmail.com>
Cc: acm@muc.de, Eli Zaretskii <eliz@gnu.org>, 70435@debbugs.gnu.org
Subject: bug#70435: 30.0.50; cc-mode: <> are sometimes not reconized as parentheses
Date: Mon, 29 Apr 2024 15:53:56 +0000 [thread overview]
Message-ID: <Zi_ClIsqXS0fccCd@ACM> (raw)
In-Reply-To: <87y18xifpb.fsf@gmail.com>
Hello, Géza.
On Sun, Apr 28, 2024 at 18:47:47 +0200, Herman, Géza wrote:
> Hello Alan,
> Alan Mackenzie <acm@muc.de> writes:
> > You've been a little less than fully explicit, but I think you're
> > executing these commands in the *scratch* buffer. The first two
> > lines, which are commented out in emacs-lisp-mode, are no longer
> > commented out in C++ Mode. There is a whole line of garbage after
> > the last end of statement marker, the (double) semicolon on line 2.
> > On using ig<TAB> to insert the snippet, it is hardly surprising that
> > CC Mode's syntactic analysis gets confused. If you first comment
> > out those first two lines (put the region around them and do C-c
> > C-c), then the inserted snippet appears to get the correct syntax on
> > its template markers.
> > I don't think there's a bug here. If you could show ig<TAB>
> > producing the effect when typed inside a syntactically correct
> > context, things might be different. Can you reproduce the effect in
> > correct C++ code?
> You're right, it seems that the example I provided wasn't the best
> (this issue happens with me in real code, I tried to create a minimal
> reproducible example).
> If you delete the garbage from the scratch buffer, the bug doesn't
> reproduce indeed. But, if you run (setq font-lock-maximum-decoration
> 2) before switching to c++-mode, the issue reproduces with an empty
> scratch buffer. I use this setting because font-lock runs much faster
> this way, and I rely on the LSP server to do the "full" highlighting.
OK, as already said, I can reproduce the bug this way. Thanks!
> Sorry about the bad example, here are the fixed repro steps:
> Repro:
> - put the yasnippet file (included below) into
> <emacs-config-dir>/snippets/c++-mode/something
> - install yasnippet
> - start emacs, scratch buffer appears
> - delete the contents of the scratch buffer
> - M-: (setq font-lock-maximum-decoration 2)
> - M-x c++-mode
> - M-x yas-minor-mode
> - load snippets with "M-x yas-reload-all"
> - write "ig", then press TAB to "yas-expand" the snippet
> - move the cursor on the opening "<", and execute "M-x
> describe-char"
> - notice that it will say "syntax: . which means: punctuation"
> - if you edit the buffer (like add a space somewhere), and execute
> describe-char again, Emacs will say "syntax: > which means: open,
> matches >", so the syntax class becomes correct.
I have a fix, I think. It is actually a two line fix, removing a test
from the top of a function, but it involves reindenting the entire rest
of the function.
Please apply the patch below, recompile cc-engine.el, then load the
resulting CC Mode into a running Emacs. Please test it on your real C++
code, and let me know if the bug is actually fixed. Thanks!
diff -r 072940aaeb40 cc-engine.el
--- a/cc-engine.el Sun Apr 14 07:59:01 2024 +0000
+++ b/cc-engine.el Mon Apr 29 15:42:05 2024 +0000
@@ -7172,153 +7172,152 @@
;; FIXME!!! This routine ignores the possibility of macros entirely.
;; 2010-01-29.
- (when (> end beg)
- ;; Extend the region (BEG END) to deal with any complicating literals.
- (let* ((lit-search-beg (if (memq (char-before beg) '(?/ ?*))
- (1- beg) beg))
- (lit-search-end (if (memq (char-after end) '(?/ ?*))
- (1+ end) end))
- ;; Note we can't use c-full-pp-to-literal here, since we haven't
- ;; yet applied syntax-table properties to ends of lines, etc.
- (lit-search-beg-s (c-semi-pp-to-literal lit-search-beg))
- (beg-literal-beg (car (cddr lit-search-beg-s)))
- (lit-search-end-s (c-semi-pp-to-literal lit-search-end))
- (end-literal-beg (car (cddr lit-search-end-s)))
- (beg-literal-end (c-end-of-literal lit-search-beg-s lit-search-beg))
- (end-literal-end (c-end-of-literal lit-search-end-s lit-search-end))
- new-beg new-end search-region)
-
- ;; Determine any new end of literal resulting from the insertion/deletion.
- (setq search-region
- (if (and (eq beg-literal-beg end-literal-beg)
- (eq beg-literal-end end-literal-end))
- (if beg-literal-beg
- nil
- (cons beg
- (max end
- (or beg-literal-end (point-min))
- (or end-literal-end (point-min)))))
- (cons (or beg-literal-beg beg)
- (max end
- (or beg-literal-end (point-min))
- (or end-literal-end (point-min))))))
-
- (when search-region
- ;; If we've just inserted text, mask its syntaxes temporarily so that
- ;; they won't interfere with the undoing of the properties on the <s
- ;; and >s.
- (c-save-buffer-state (syn-tab-settings syn-tab-value
- swap-open-string-ends)
- (unwind-protect
- (progn
- (when old-len
- ;; Special case: If a \ has just been inserted into a
- ;; string, escaping or unescaping a LF, temporarily swap
- ;; the LF's syntax-table text property with that of the
- ;; former end of the open string.
- (goto-char end)
- (when (and (eq (cadr lit-search-beg-s) 'string)
- (not (eq beg-literal-end end-literal-end))
- (skip-chars-forward "\\\\")
- (eq (char-after) ?\n)
- (not (zerop (skip-chars-backward "\\\\"))))
- (setq swap-open-string-ends t)
- (if (c-get-char-property (1- beg-literal-end)
- 'syntax-table)
- (progn
- (c-clear-char-property (1- beg-literal-end)
- 'syntax-table)
- (c-put-string-fence (1- end-literal-end)))
- (c-put-string-fence (1- beg-literal-end))
- (c-clear-char-property (1- end-literal-end)
- 'syntax-table)))
-
- ;; Save current settings of the 'syntax-table property in
- ;; (BEG END), then splat these with the punctuation value.
- (goto-char beg)
- (while (setq syn-tab-value
- (c-search-forward-non-nil-char-property
- 'syntax-table end))
- (when (not (c-get-char-property (1- (point)) 'category))
- (push (cons (1- (point)) syn-tab-value)
- syn-tab-settings)))
-
- (c-put-char-properties beg end 'syntax-table '(1))
- ;; If an open string's opener has just been neutralized,
- ;; do the same to the terminating LF.
- (when (and end-literal-end
- (eq (char-before end-literal-end) ?\n)
- (equal (c-get-char-property
- (1- end-literal-end) 'syntax-table)
- '(15)))
- (push (cons (1- end-literal-end) '(15)) syn-tab-settings)
- (c-put-char-property (1- end-literal-end) 'syntax-table
- '(1))))
-
- (let
- ((beg-lit-start (progn (goto-char beg) (c-literal-start)))
- beg-limit end-limit <>-pos)
- ;; Locate the earliest < after the barrier before the
- ;; changed region, which isn't already marked as a paren.
- (goto-char (or beg-lit-start beg))
- (setq beg-limit (c-determine-limit 5000))
-
- ;; Remove the syntax-table/category properties from each pertinent <...>
- ;; pair. Firstly, the ones with the < before beg and > after beg....
- (goto-char (cdr search-region))
- (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit)
- (eq (char-before) ?<))
- (c-backward-token-2)
- (when (eq (char-after) ?<)
- (when (setq <>-pos (c-clear-<-pair-props-if-match-after
- (car search-region)))
- (setq new-end <>-pos))
- (setq new-beg (point))))
-
- ;; ...Then the ones with < before end and > after end.
- (goto-char (car search-region))
- (setq end-limit (c-determine-+ve-limit 5000))
- (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end)
- (eq (char-before) ?>))
- (when (eq (char-before) ?>)
- (if (and (looking-at c->-op-cont-regexp)
- (not (eq (char-after) ?>)))
- (goto-char (match-end 0))
- (when
- (and (setq <>-pos
- (c-clear->-pair-props-if-match-before
- (cdr search-region)
- (1- (point))))
- (or (not new-beg)
- (< <>-pos new-beg)))
- (setq new-beg <>-pos))
- (when (or (not new-end) (> (point) new-end))
- (setq new-end (point))))))))
-
- (when old-len
- (c-clear-char-properties beg end 'syntax-table)
- (dolist (elt syn-tab-settings)
- (if (cdr elt)
- (c-put-char-property (car elt) 'syntax-table (cdr elt)))))
- ;; Swap the '(15) syntax-table property on open string LFs back
- ;; again.
- (when swap-open-string-ends
- (if (c-get-char-property (1- beg-literal-end)
- 'syntax-table)
- (progn
- (c-clear-char-property (1- beg-literal-end)
+ ;; Extend the region (BEG END) to deal with any complicating literals.
+ (let* ((lit-search-beg (if (memq (char-before beg) '(?/ ?*))
+ (1- beg) beg))
+ (lit-search-end (if (memq (char-after end) '(?/ ?*))
+ (1+ end) end))
+ ;; Note we can't use c-full-pp-to-literal here, since we haven't
+ ;; yet applied syntax-table properties to ends of lines, etc.
+ (lit-search-beg-s (c-semi-pp-to-literal lit-search-beg))
+ (beg-literal-beg (car (cddr lit-search-beg-s)))
+ (lit-search-end-s (c-semi-pp-to-literal lit-search-end))
+ (end-literal-beg (car (cddr lit-search-end-s)))
+ (beg-literal-end (c-end-of-literal lit-search-beg-s lit-search-beg))
+ (end-literal-end (c-end-of-literal lit-search-end-s lit-search-end))
+ new-beg new-end search-region)
+
+ ;; Determine any new end of literal resulting from the insertion/deletion.
+ (setq search-region
+ (if (and (eq beg-literal-beg end-literal-beg)
+ (eq beg-literal-end end-literal-end))
+ (if beg-literal-beg
+ nil
+ (cons beg
+ (max end
+ (or beg-literal-end (point-min))
+ (or end-literal-end (point-min)))))
+ (cons (or beg-literal-beg beg)
+ (max end
+ (or beg-literal-end (point-min))
+ (or end-literal-end (point-min))))))
+
+ (when search-region
+ ;; If we've just inserted text, mask its syntaxes temporarily so that
+ ;; they won't interfere with the undoing of the properties on the <s
+ ;; and >s.
+ (c-save-buffer-state (syn-tab-settings syn-tab-value
+ swap-open-string-ends)
+ (unwind-protect
+ (progn
+ (when old-len
+ ;; Special case: If a \ has just been inserted into a
+ ;; string, escaping or unescaping a LF, temporarily swap
+ ;; the LF's syntax-table text property with that of the
+ ;; former end of the open string.
+ (goto-char end)
+ (when (and (eq (cadr lit-search-beg-s) 'string)
+ (not (eq beg-literal-end end-literal-end))
+ (skip-chars-forward "\\\\")
+ (eq (char-after) ?\n)
+ (not (zerop (skip-chars-backward "\\\\"))))
+ (setq swap-open-string-ends t)
+ (if (c-get-char-property (1- beg-literal-end)
'syntax-table)
- (c-put-string-fence (1- end-literal-end)))
- (c-put-string-fence (1- beg-literal-end))
- (c-clear-char-property (1- end-literal-end)
- 'syntax-table)))))
- ;; Extend the fontification region, if needed.
- (and new-beg
- (< new-beg c-new-BEG)
- (setq c-new-BEG new-beg))
- (and new-end
- (> new-end c-new-END)
- (setq c-new-END new-end))))))
+ (progn
+ (c-clear-char-property (1- beg-literal-end)
+ 'syntax-table)
+ (c-put-string-fence (1- end-literal-end)))
+ (c-put-string-fence (1- beg-literal-end))
+ (c-clear-char-property (1- end-literal-end)
+ 'syntax-table)))
+
+ ;; Save current settings of the 'syntax-table property in
+ ;; (BEG END), then splat these with the punctuation value.
+ (goto-char beg)
+ (while (setq syn-tab-value
+ (c-search-forward-non-nil-char-property
+ 'syntax-table end))
+ (when (not (c-get-char-property (1- (point)) 'category))
+ (push (cons (1- (point)) syn-tab-value)
+ syn-tab-settings)))
+
+ (c-put-char-properties beg end 'syntax-table '(1))
+ ;; If an open string's opener has just been neutralized,
+ ;; do the same to the terminating LF.
+ (when (and end-literal-end
+ (eq (char-before end-literal-end) ?\n)
+ (equal (c-get-char-property
+ (1- end-literal-end) 'syntax-table)
+ '(15)))
+ (push (cons (1- end-literal-end) '(15)) syn-tab-settings)
+ (c-put-char-property (1- end-literal-end) 'syntax-table
+ '(1))))
+
+ (let
+ ((beg-lit-start (progn (goto-char beg) (c-literal-start)))
+ beg-limit end-limit <>-pos)
+ ;; Locate the earliest < after the barrier before the
+ ;; changed region, which isn't already marked as a paren.
+ (goto-char (or beg-lit-start beg))
+ (setq beg-limit (c-determine-limit 5000))
+
+ ;; Remove the syntax-table/category properties from each pertinent <...>
+ ;; pair. Firstly, the ones with the < before beg and > after beg....
+ (goto-char (cdr search-region))
+ (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit)
+ (eq (char-before) ?<))
+ (c-backward-token-2)
+ (when (eq (char-after) ?<)
+ (when (setq <>-pos (c-clear-<-pair-props-if-match-after
+ (car search-region)))
+ (setq new-end <>-pos))
+ (setq new-beg (point))))
+
+ ;; ...Then the ones with < before end and > after end.
+ (goto-char (car search-region))
+ (setq end-limit (c-determine-+ve-limit 5000))
+ (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end)
+ (eq (char-before) ?>))
+ (when (eq (char-before) ?>)
+ (if (and (looking-at c->-op-cont-regexp)
+ (not (eq (char-after) ?>)))
+ (goto-char (match-end 0))
+ (when
+ (and (setq <>-pos
+ (c-clear->-pair-props-if-match-before
+ (cdr search-region)
+ (1- (point))))
+ (or (not new-beg)
+ (< <>-pos new-beg)))
+ (setq new-beg <>-pos))
+ (when (or (not new-end) (> (point) new-end))
+ (setq new-end (point))))))))
+
+ (when old-len
+ (c-clear-char-properties beg end 'syntax-table)
+ (dolist (elt syn-tab-settings)
+ (if (cdr elt)
+ (c-put-char-property (car elt) 'syntax-table (cdr elt)))))
+ ;; Swap the '(15) syntax-table property on open string LFs back
+ ;; again.
+ (when swap-open-string-ends
+ (if (c-get-char-property (1- beg-literal-end)
+ 'syntax-table)
+ (progn
+ (c-clear-char-property (1- beg-literal-end)
+ 'syntax-table)
+ (c-put-string-fence (1- end-literal-end)))
+ (c-put-string-fence (1- beg-literal-end))
+ (c-clear-char-property (1- end-literal-end)
+ 'syntax-table)))))
+ ;; Extend the fontification region, if needed.
+ (and new-beg
+ (< new-beg c-new-BEG)
+ (setq c-new-BEG new-beg))
+ (and new-end
+ (> new-end c-new-END)
+ (setq c-new-END new-end)))))
(defun c-before-change-check-<>-operators (beg end)
;; When we're deleting text, unmark certain pairs of "< .... >" which are
> Geza
--
Alan Mackenzie (Nuremberg, Germany).
next prev parent reply other threads:[~2024-04-29 15:53 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-17 10:47 bug#70435: 30.0.50; cc-mode: <> are sometimes not reconized as parentheses Herman, Géza
2024-04-27 8:33 ` Eli Zaretskii
2024-04-27 10:08 ` Alan Mackenzie
2024-04-28 15:44 ` Alan Mackenzie
2024-04-28 16:47 ` Herman, Géza
2024-04-28 20:31 ` Alan Mackenzie
2024-04-29 15:53 ` Alan Mackenzie [this message]
2024-04-29 17:21 ` Herman, Géza
2024-05-02 9:30 ` Eli Zaretskii
2024-05-02 10:24 ` Alan Mackenzie
2024-05-02 12:49 ` Herman, Géza
2024-05-02 13:16 ` bug#70435: 30.0.50; cc-mode: <> are sometimes not recognized " Alan Mackenzie
2024-05-02 19:58 ` Herman, Géza
2024-05-05 11:55 ` Alan Mackenzie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Zi_ClIsqXS0fccCd@ACM \
--to=acm@muc.de \
--cc=70435@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=geza.herman@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).