emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Slow fontification in C mode buffers


From: Alan Mackenzie
Subject: Re: Slow fontification in C mode buffers
Date: Sun, 15 Jan 2012 21:12:40 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

Hello, Kanru!

On Sun, Dec 18, 2011 at 12:06:00AM +0800, Kan-Ru Chen wrote:
> Alan Mackenzie <address@hidden> writes:

> Please forgive me for using the other files, it is closer to the real
> case. You can get the file from

> https://hg.mozilla.org/mozilla-central/raw-file/tip/dom/base/nsDOMClassInfo.cpp

Ah yes, this wonderful file!

Here's another patch which contains more optimisations than my last
patch.  Could you apply it _instead_ of the previous patch, and let me
know how it goes, please.  The more serious editing you can do with it,
particularly on C++ files, the better.

Anyhow, here's the patch:


*** orig/cc-engine.el   2011-12-15 09:06:28.000000000 +0000
--- cc-engine.el        2012-01-15 19:20:01.000000000 +0000
***************
*** 2075,2081 ****
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; We maintain a simple cache of positions which aren't in a literal, so as to
  ;; speed up testing for non-literality.
! (defconst c-state-nonlit-pos-interval 10000)
  ;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
  
  (defvar c-state-nonlit-pos-cache nil)
--- 2075,2081 ----
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; We maintain a simple cache of positions which aren't in a literal, so as to
  ;; speed up testing for non-literality.
! (defconst c-state-nonlit-pos-interval 3000)
  ;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
  
  (defvar c-state-nonlit-pos-cache nil)
***************
*** 2130,2136 ****
      (widen)
      (save-excursion
        (let ((c c-state-nonlit-pos-cache)
!           pos npos lit)
        ;; Trim the cache to take account of buffer changes.
        (while (and c (> (car c) c-state-nonlit-pos-cache-limit))
          (setq c (cdr c)))
--- 2130,2136 ----
      (widen)
      (save-excursion
        (let ((c c-state-nonlit-pos-cache)
!           pos npos lit macro-beg)
        ;; Trim the cache to take account of buffer changes.
        (while (and c (> (car c) c-state-nonlit-pos-cache-limit))
          (setq c (cdr c)))
***************
*** 2140,2160 ****
          (setq c (cdr c)))
        (setq pos (or (car c) (point-min)))
  
!       (while (<= (setq npos (+ pos c-state-nonlit-pos-interval))
!                  here)
!         (setq lit (car (cddr (c-state-pp-to-literal pos npos))))
!         (setq pos (or (cdr lit) npos)) ; end of literal containing npos.
          (goto-char pos)
          (when (and (c-beginning-of-macro) (/= (point) pos))
!           (c-syntactic-end-of-macro)
!           (or (eobp) (forward-char))
!           (setq pos (point)))
!         (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
  
        (if (> pos c-state-nonlit-pos-cache-limit)
            (setq c-state-nonlit-pos-cache-limit pos))
        pos))))
!       
  (defun c-state-literal-at (here)
    ;; If position HERE is inside a literal, return (START . END), the
    ;; boundaries of the literal (which may be outside the accessible bit of the
--- 2140,2177 ----
          (setq c (cdr c)))
        (setq pos (or (car c) (point-min)))
  
!       (while
!           ;; Add an element to `c-state-nonlit-pos-cache' each iteration.
!           (and
!            (<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
!            (progn
!              (setq lit (car (cddr (c-state-pp-to-literal pos npos))))
!              (cond
!               ((null lit)
!                (setq pos npos)
!                t)
!               ((<= (cdr lit) here)
!                (setq pos (cdr lit))
!                t)
!               (t
!                (setq pos (car lit))
!                nil))))
! 
          (goto-char pos)
          (when (and (c-beginning-of-macro) (/= (point) pos))
!             (setq macro-beg (point))
!             (c-syntactic-end-of-macro)
!             (or (eobp) (forward-char))
!             (setq pos (if (<= (point) here)
!                           (point)
!                         macro-beg)))
!           (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
  
        (if (> pos c-state-nonlit-pos-cache-limit)
            (setq c-state-nonlit-pos-cache-limit pos))
        pos))))
! ;;;; END OF NEW STOUGH, 2012-01-14
! 
  (defun c-state-literal-at (here)
    ;; If position HERE is inside a literal, return (START . END), the
    ;; boundaries of the literal (which may be outside the accessible bit of the
***************
*** 4362,4367 ****
--- 4379,4456 ----
              (t 'c)))                  ; Assuming the range is valid.
      range))
  
+ (defsubst c-determine-limit-get-base (start try-size)
+   ;; Get a "safe place" approximately TRY-SIZE characters before START.
+   ;; This doesn't preserve point.
+   (let* ((pos (max (- start try-size) (point-min)))
+        (base (c-state-safe-place pos))
+        (s (parse-partial-sexp base pos)))
+     (if (or (nth 4 s) (nth 3 s))      ; comment or string
+       (nth 8 s)
+       (point))))
+ 
+ (defun c-determine-limit (how-far-back &optional start try-size)
+   ;; Return a buffer position HOW-FAR-BACK non-literal characters from START
+   ;; (default point).  This is done by going back further in the buffer then
+   ;; searching forward for literals.  The position found won't be in a
+   ;; literal.  We start searching for the sought position TRY-SIZE (default
+   ;; twice HOW-FAR-BACK) bytes back from START.  This function must be fast.
+   ;; :-)
+   (save-excursion
+     (let* ((start (or start (point)))
+          (try-size (or try-size (* 2 how-far-back)))
+          (base (c-determine-limit-get-base start try-size))
+          (pos base)
+ 
+          (s (parse-partial-sexp pos pos)) ; null state.
+          stack elt size
+          (count 0))
+       (while (< pos start)
+       ;; Move forward one literal each time round this loop.
+       ;; Move forward to the start of a comment or string.
+       (setq s (parse-partial-sexp
+                pos
+                start
+                nil                    ; target-depth
+                nil                    ; stop-before
+                s                      ; state
+                'syntax-table))        ; stop-comment
+ 
+       ;; Gather details of the non-literal-bit - starting pos and size.
+       (setq size (- (if (or (nth 4 s) (nth 3 s))
+                         (nth 8 s)
+                       (point))
+                     pos))
+       (if (> size 0)
+           (setq stack (cons (cons pos size) stack)))
+ 
+       ;; Move forward to the end of the comment/string.
+       (if (or (nth 4 s) (nth 3 s))
+           (setq s (parse-partial-sexp
+                    (point)
+                    start
+                    nil                ; target-depth
+                    nil                ; stop-before
+                    s                  ; state
+                    'syntax-table)))   ; stop-comment
+       (setq pos (point)))
+     
+       ;; Now try and find enough non-literal characters recorded on the stack.
+       ;; Go back one recorded literal each time round this loop.
+       (while (and (< count how-far-back)
+                 stack)
+       (setq elt (car stack)
+             stack (cdr stack))
+       (setq count (+ count (cdr elt))))
+ 
+       ;; Have we found enough yet?
+       (cond
+        ((>= count how-far-back)
+       (+ (car elt) (- count how-far-back)))
+        ((eq base (point-min))
+       (point-min))
+        (t
+       (c-determine-limit (- how-far-back count) base try-size))))))
  
  ;; `c-find-decl-spots' and accompanying stuff.
  
***************
*** 4498,4510 ****
    ;; Call CFD-FUN for each possible spot for a declaration, cast or
    ;; label from the point to CFD-LIMIT.
    ;;
!   ;; CFD-FUN is called with point at the start of the spot.  It's
!   ;; passed two arguments: The first is the end position of the token
!   ;; preceding the spot, or 0 for the implicit match at bob.  The
!   ;; second is a flag that is t when the match is inside a macro.  If
!   ;; CFD-FUN adds `c-decl-end' properties somewhere below the current
!   ;; spot, it should return non-nil to ensure that the next search
!   ;; will find them.
    ;;
    ;; Such a spot is:
    ;; o        The first token after bob.
--- 4587,4600 ----
    ;; Call CFD-FUN for each possible spot for a declaration, cast or
    ;; label from the point to CFD-LIMIT.
    ;;
!   ;; CFD-FUN is called with point at the start of the spot.  It's passed two
!   ;; arguments: The first is the end position of the token preceding the spot,
!   ;; or 0 for the implicit match at bob.  The second is a flag that is t when
!   ;; the match is inside a macro.  Point should be moved forward by at least
!   ;; one token.
!   ;;
!   ;; If CFD-FUN adds `c-decl-end' properties somewhere below the current spot,
!   ;; it should return non-nil to ensure that the next search will find them.
    ;;
    ;; Such a spot is:
    ;; o        The first token after bob.
***************
*** 4903,4909 ****
        (goto-char cfd-continue-pos)
        (if (= cfd-continue-pos cfd-limit)
          (setq cfd-match-pos cfd-limit)
!       (c-find-decl-prefix-search)))))
  
  
  ;; A cache for found types.
--- 4993,5000 ----
        (goto-char cfd-continue-pos)
        (if (= cfd-continue-pos cfd-limit)
          (setq cfd-match-pos cfd-limit)
!       (c-find-decl-prefix-search))))) ; Moves point, sets cfd-continue-pos,
!                                       ; cfd-match-pos, etc.
  
  
  ;; A cache for found types.
***************
*** 8073,8078 ****
--- 8164,8186 ----
            next-open-brace (c-pull-open-brace paren-state)))
      open-brace))
  
+ (defun c-cheap-inside-bracelist-p (paren-state)
+   ;; Return the position of the L-brace if point is inside a brace list
+   ;; initialization of an array, etc.  This is an approximate function,
+   ;; designed for speed over accuracy.  It will not find every bracelist, but
+   ;; a non-nil result is reliable.  We simply search for "= {" (naturally with
+   ;; syntactic whitespace allowed).  PAREN-STATE is the normal thing that it
+   ;; is everywhere else.
+   (let (b-pos)
+     (save-excursion
+       (while
+         (and (setq b-pos (c-pull-open-brace paren-state))
+              (progn (goto-char b-pos)
+                     (c-backward-sws)
+                     (c-backward-token-2)
+                     (not (looking-at "=")))))
+       b-pos)))
+ 
  (defun c-inside-bracelist-p (containing-sexp paren-state)
    ;; return the buffer position of the beginning of the brace list
    ;; statement if we're inside a brace list, otherwise return nil.
*** orig/cc-fonts.el    2011-12-15 09:06:28.000000000 +0000
--- cc-fonts.el 2012-01-15 18:41:00.000000000 +0000
***************
*** 407,416 ****
              ;; `parse-sexp-lookup-properties' (when it exists).
              (parse-sexp-lookup-properties
               (cc-eval-when-compile
!                (boundp 'parse-sexp-lookup-properties))))
          (goto-char
           (let ((here (point)))
!            (if (eq (car (c-beginning-of-decl-1)) 'same)
                 (point)
               here)))
          ,(c-make-font-lock-search-form regexp highlights))
--- 407,418 ----
              ;; `parse-sexp-lookup-properties' (when it exists).
              (parse-sexp-lookup-properties
               (cc-eval-when-compile
!                (boundp 'parse-sexp-lookup-properties)))
!             (BOD-limit
!              (c-determine-limit 1000)))
          (goto-char
           (let ((here (point)))
!            (if (eq (car (c-beginning-of-decl-1 BOD-limit)) 'same)
                 (point)
               here)))
          ,(c-make-font-lock-search-form regexp highlights))
***************
*** 1206,1211 ****
--- 1208,1214 ----
          ;; it finds any.  That's necessary so that we later will
          ;; stop inside them to fontify types there.
          (c-parse-and-markup-<>-arglists t)
+         lbrace ; position of some {.
          ;; The font-lock package in Emacs is known to clobber
          ;; `parse-sexp-lookup-properties' (when it exists).
          (parse-sexp-lookup-properties
***************
*** 1317,1323 ****
              (or (looking-at c-typedef-key)
                  (goto-char start-pos)))
  
-           ;; Now analyze the construct.
            ;; In QT, "more" is an irritating keyword that expands to nothing.
            ;; We skip over it to prevent recognition of "more slots: <symbol>"
            ;; as a bitfield declaration.
--- 1320,1325 ----
***************
*** 1326,1331 ****
--- 1328,1335 ----
                        (concat "\\(more\\)\\([^" c-symbol-chars "]\\|$\\)")))
              (goto-char (match-end 1))
              (c-forward-syntactic-ws))
+ 
+           ;; Now analyze the construct.
            (setq decl-or-cast (c-forward-decl-or-cast-1
                                match-pos context last-cast-end))
  
***************
*** 1394,1408 ****
              (c-fontify-recorded-types-and-refs)
              nil)
  
             (t
              ;; Are we at a declarator?  Try to go back to the declaration
              ;; to check this.  If we get there, check whether a "typedef"
              ;; is there, then fontify the declarators accordingly.
!             (let ((decl-search-lim (max (- (point) 50000) (point-min)))
                    paren-state bod-res encl-pos is-typedef 
                    c-recognize-knr-p) ; Strictly speaking, bogus, but it
                                       ; speeds up lisp.h tremendously.
                (save-excursion
                  (setq bod-res (car (c-beginning-of-decl-1 decl-search-lim)))
                  (if (and (eq bod-res 'same)
                           (progn
--- 1398,1449 ----
              (c-fontify-recorded-types-and-refs)
              nil)
  
+            ;; Restore point, since at this point in the code it has been
+            ;; left undefined by c-forward-decl-or-cast-1 above.
+            ((progn (goto-char start-pos) nil))
+ 
+            ;; If point is inside a bracelist, there's no point checking it
+            ;; being at a declarator.
+            ((let ((paren-state (c-parse-state)))
+               (setq lbrace (c-cheap-inside-bracelist-p paren-state)))
+             ;; Move past this bracelist to prevent an endless loop.
+             (goto-char lbrace)
+             (unless (c-safe (progn (forward-list) t))
+               (goto-char start-point)
+               (c-forward-token-2))
+             nil)
+ 
+            ;; If point is just after a ")" which is followed by an
+            ;; identifier which isn't a label, or at the matching "(", we're
+            ;; at either a macro invocation, a cast, or a
+            ;; for/while/etc. statement.  The cast case is handled above.
+            ;; None of these cases can contain a declarator.
+            ((or (and (eq (char-before match-pos) ?\))
+                      (c-on-identifier)
+                      (save-excursion (not (c-forward-label))))
+                 (and (eq (char-after) ?\()
+                      (save-excursion
+                        (and
+                         (progn (c-backward-token-2) (c-on-identifier))
+                         (save-excursion (not (c-forward-label)))
+                         (progn (c-backward-token-2)
+                                (eq (char-after) ?\())))))
+             (c-forward-token-2)       ; Must prevent looping.
+             nil)
+ 
             (t
              ;; Are we at a declarator?  Try to go back to the declaration
              ;; to check this.  If we get there, check whether a "typedef"
              ;; is there, then fontify the declarators accordingly.
!             (let ((decl-search-lim ;; (max (- (point) 50000) (point-min))
!                    (c-determine-limit 1000))
                    paren-state bod-res encl-pos is-typedef 
                    c-recognize-knr-p) ; Strictly speaking, bogus, but it
                                       ; speeds up lisp.h tremendously.
                (save-excursion
+                 (unless (or (eobp)
+                             (looking-at "\\s(\\|\\s)"))
+                   (forward-char))
                  (setq bod-res (car (c-beginning-of-decl-1 decl-search-lim)))
                  (if (and (eq bod-res 'same)
                           (progn
***************
*** 1865,1873 ****
            `((,(c-make-font-lock-BO-decl-search-function
                 (concat "\\<\\("
                         (c-make-keywords-re nil
!                          (append (c-lang-const c-type-list-kwds)
!                                  (c-lang-const c-ref-list-kwds)
!                                  (c-lang-const c-colon-type-list-kwds)))
                         "\\)\\>")
                 '((c-fontify-types-and-refs ((c-promote-possible-types t))
                     (c-forward-keyword-clause 1)
--- 1906,1915 ----
            `((,(c-make-font-lock-BO-decl-search-function
                 (concat "\\<\\("
                         (c-make-keywords-re nil
!                          (append (c-lang-const c-type-list-kwds) ; operator 
(C++).  import, implements, etc. (Java).
!                                  (c-lang-const c-ref-list-kwds)  ; namespace 
(C++).  package (Java).
!                                  (c-lang-const c-colon-type-list-kwds))) ; 
class, struct (C++).  The colon is what
!                                                                          ; 
introduces an inheritance list.
                         "\\)\\>")
                 '((c-fontify-types-and-refs ((c-promote-possible-types t))
                     (c-forward-keyword-clause 1)

> -- 
> Kanru

-- 
Alan Mackenzie (Nuremberg, Germany).



reply via email to

[Prev in Thread] Current Thread [Next in Thread]