[Top][All Lists]
[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).