unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Alan Mackenzie <acm@muc.de>
To: "Björn Lindqvist" <bjourne@gmail.com>
Cc: acm@muc.de, Eli Zaretskii <eliz@gnu.org>, 74357@debbugs.gnu.org
Subject: bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
Date: Fri, 29 Nov 2024 23:18:02 +0000	[thread overview]
Message-ID: <Z0pLqgsDIdECGj0y@MAC.fritz.box> (raw)
In-Reply-To: <Z0jMlaRLVmatT2vg@MAC.fritz.box>

Hello again, Björn.

On Thu, Nov 28, 2024 at 20:03:33 +0000, Alan Mackenzie wrote:
> On Fri, Nov 15, 2024 at 22:43:45 +0100, Björn Lindqvist wrote:
> > Den fre 15 nov. 2024 kl 15:25 skrev Eli Zaretskii <eliz@gnu.org>:
> > > Can you tell where in real life do you see such deeply-nested braces
> > > in C source files?

> > 50 is perhaps exaggerating it, but in "modern" C++ with multiple
> > namespaces, nested classes, and anonymous functions you can easily get
> > scopes nested over a dozen levels deep.

> In your test file, near the end, holding down the 'y' key as you
> describe, most of the time CC Mode is scanning for brace lists (and not
> finding them).  ("Brace lists" are things like the initialisation forms
> for structs and arrays, not statement blocks.)

> There is a cache mechanism to help reduce this scanning, but with the
> deep nesting in the test file, it seems to be ineffective, with elements
> of that cache continually being overwritten by new elements.  The cache
> currently has just four elements.  Maybe it would be better to increase
> that number.  Maybe there's some other problem with the cache.  I'm
> looking into it.

It turns out that that cache mechanism was almost totally ineffective.
I've put a new cache into c-inside-bracelist-p.  More precisely, I've
reused an existing cache in a new way.

Would you please apply the patch below to your CC Mode, byte compile CC
Mode, and test it a bit to see if it's fast enough.  (If you want any
help applying the patch or byte compiling the result, feel free to send
me private email.)

Thanks!


diff -r 2c1ba136f3f2 cc-engine.el
--- a/cc-engine.el	Mon Oct 28 15:47:50 2024 +0000
+++ b/cc-engine.el	Fri Nov 29 23:12:27 2024 +0000
@@ -13178,7 +13178,7 @@
 	  (setq c-laomib-cache (delq elt c-laomib-cache)))))))
 
 (defun c-looking-at-or-maybe-in-bracelist (&optional containing-sexp lim)
-  ;; Point is at an open brace.  If this starts a brace list, return a list
+  ;; Point is at an open brace.  If this starts a brace list, return a cons
   ;; whose car is the buffer position of the start of the construct which
   ;; introduces the list, and whose cdr is the symbol `in-paren' if the brace
   ;; is directly enclosed in a parenthesis form (i.e. an arglist), t if we
@@ -13411,14 +13411,19 @@
 	   (t t))))			;; The caller can go up one level.
 	))))
 
+;; A list of the form returned by `c-parse-state'.  Each opening brace in it
+;; is not the brace of a brace list.
+(defvar c-no-bracelist-cache nil)
+(make-variable-buffer-local 'c-no-bracelist-cache)
+
 (defun c-inside-bracelist-p (containing-sexp paren-state accept-in-paren)
-  ;; return the buffer position of the beginning of the brace list statement
+  ;; Return the buffer position of the beginning of the brace list statement
   ;; if CONTAINING-SEXP is inside a brace list, otherwise return nil.
   ;;
-  ;; CONTAINING-SEXP is the buffer pos of the innermost containing paren.  NO
-  ;; IT ISN'T!!!  [This function is badly designed, and probably needs
-  ;; reformulating without its first argument, and the critical position being
-  ;; at point.]
+  ;; CONTAINING-SEXP must be at an open brace, and is the buffer pos of the
+  ;; innermost containing brace.  NO IT ISN'T!!!  [This function is badly
+  ;; designed, and probably needs reformulating without its first argument,
+  ;; and the critical position being at point.]
   ;;
   ;; PAREN-STATE is the remainder of the state of enclosing braces.
   ;; ACCEPT-IN-PAREN is non-nil iff we will accept as a brace list a brace
@@ -13432,32 +13437,42 @@
   ;; speed.
   ;;
   ;; This function might do hidden buffer changes.
-  ;; this will pick up array/aggregate init lists, even if they are nested.
-   (save-excursion
-     (let ((bufpos t)
-	    next-containing)
-       (while (and (eq bufpos t)
-		   containing-sexp)
-	 (when paren-state
-	   (setq next-containing (c-pull-open-brace paren-state)))
-
-	 (goto-char containing-sexp)
-	 (if (c-looking-at-inexpr-block next-containing next-containing)
-	     ;; We're in an in-expression block of some kind.  Do not
-	     ;; check nesting.  We deliberately set the limit to the
-	     ;; containing sexp, so that c-looking-at-inexpr-block
-	     ;; doesn't check for an identifier before it.
-	     (setq bufpos nil)
-	   (if (not (eq (char-after) ?{))
-	       (setq bufpos nil)
-	     (when (eq (setq bufpos (c-looking-at-or-maybe-in-bracelist
-					  next-containing next-containing))
-		       t)
-	       (setq containing-sexp next-containing
-		     next-containing nil)))))
-       (and (consp bufpos)
-	    (or accept-in-paren (not (eq (cdr bufpos) 'in-paren)))
-	    (car bufpos)))))
+  ;; It will pick up array/aggregate init lists, even if they are nested.
+  (save-excursion
+    (let ((bufpos t)
+	  next-containing
+	  (whole-paren-state (cons containing-sexp paren-state))
+	  (current-brace containing-sexp))
+      (while (and (eq bufpos t)
+		  current-brace
+		  (not (memq current-brace c-no-bracelist-cache)))
+	(when paren-state
+	  (setq next-containing (c-pull-open-brace paren-state)))
+
+	(goto-char current-brace)
+	(cond
+	 ((c-looking-at-inexpr-block next-containing next-containing)
+	  ;; We're in an in-expression block of some kind.  Do not
+	  ;; check nesting.  We deliberately set the limit to the
+	  ;; containing sexp, so that c-looking-at-inexpr-block
+	  ;; doesn't check for an identifier before it.
+	  (setq bufpos nil))
+	 ((not (eq (char-after) ?{))
+	  (setq bufpos nil))
+	 ((eq (setq bufpos (c-looking-at-or-maybe-in-bracelist
+			    next-containing next-containing))
+	      t)
+	  (setq current-brace
+		next-containing
+		next-containing nil))))
+      (cond
+       ((and (consp bufpos)
+	     (or accept-in-paren (not (eq (cdr bufpos) 'in-paren))))
+	(car bufpos))
+       ((not (memq containing-sexp c-no-bracelist-cache))
+	;; Update `c-no-bracelist-cache'
+	(setq c-no-bracelist-cache (copy-tree whole-paren-state))
+	nil)))))
 
 (defun c-looking-at-special-brace-list ()
   ;; If we're looking at the start of a pike-style list, i.e., `({ })',
diff -r 2c1ba136f3f2 cc-mode.el
--- a/cc-mode.el	Mon Oct 28 15:47:50 2024 +0000
+++ b/cc-mode.el	Fri Nov 29 23:12:27 2024 +0000
@@ -2313,7 +2313,9 @@
      ;; The following must happen after the previous, which likely alters
      ;; the macro cache.
      (when c-opt-cpp-symbol
-       (c-invalidate-macro-cache beg end)))))
+       (c-invalidate-macro-cache beg end))
+     (setq c-no-bracelist-cache
+	   (c-whack-state-after beg c-no-bracelist-cache)))))
 
 (defvar c-in-after-change-fontification nil)
 (make-variable-buffer-local 'c-in-after-change-fontification)


> > -- 
> > mvh/best regards Björn Lindqvist

-- 
Alan Mackenzie (Nuremberg, Germany).





  reply	other threads:[~2024-11-29 23:18 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-14 20:39 bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag Björn Lindqvist
2024-11-15  7:40 ` Eli Zaretskii
2024-11-15 14:08   ` Björn Lindqvist
2024-11-15 14:25     ` Eli Zaretskii
2024-11-15 14:45       ` Alan Mackenzie
2024-11-15 21:43       ` Björn Lindqvist
2024-11-16 11:00         ` Eli Zaretskii
2024-11-28 20:03         ` Alan Mackenzie
2024-11-29 23:18           ` Alan Mackenzie [this message]
2024-11-30 18:04             ` Björn Lindqvist
2024-11-30 18:33               ` Alan Mackenzie
2024-11-30 20:07                 ` Björn Lindqvist
2024-12-01 17:49                   ` 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=Z0pLqgsDIdECGj0y@MAC.fritz.box \
    --to=acm@muc.de \
    --cc=74357@debbugs.gnu.org \
    --cc=bjourne@gmail.com \
    --cc=eliz@gnu.org \
    /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).