Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rainbow-delimeters can be very slow #34

Closed
vitillo opened this issue Sep 7, 2014 · 5 comments
Closed

rainbow-delimeters can be very slow #34

vitillo opened this issue Sep 7, 2014 · 5 comments

Comments

@vitillo
Copy link

vitillo commented Sep 7, 2014

Rainbow-delimiters-mode slows down significantly the editing of big clojure files to the point that inserting a letter has a noticeable lag. For a concrete example, open this file and try to write something on line 375 for instance.

@Fanael
Copy link
Collaborator

Fanael commented Sep 7, 2014

Confirmed.

Profiling results:

rainbow-delimiters-propertize                         16          1.3593606     0.0849600375
rainbow-delimiters-syntax-ppss                        5392        1.2499861000  0.0002318223
rainbow-delimiters-syntax-ppss-run                    5392        1.2343634000  0.0002289249
rainbow-delimiters-propertize-delimiter               5376        0.0156242     2.90...e-006
rainbow-delimiters-depth-face                         5376        0.0156242     2.90...e-006
rainbow-delimiters-apply-color                        5376        0.0156242     2.90...e-006
rainbow-delimiters-escaped-char-predicate-lisp        5376        0.0           0.0
rainbow-delimiters-char-ineligible-p                  5376        0.0           0.0
rainbow-delimiters-syntax-ppss-flush-cache            16          0.0           0.0
rainbow-delimiters-depth                              16          0.0           0.0

No surprise we spend so much time in parse-partial-sexp. The value of point at the end of line 375 is 16331, which is less than rainbow-delimiters-parse-partial-sexp-cache-max-span, meaning we start parsing from (point-min) every time.

@Fanael
Copy link
Collaborator

Fanael commented Sep 7, 2014

Does this patch fix the issue for you?

 rainbow-delimiters.el | 54 +++++++++++++++++++++++++++------------------------
 1 file changed, 29 insertions(+), 25 deletions(-)

diff --git a/rainbow-delimiters.el b/rainbow-delimiters.el
index b25cf49..54111d5 100644
--- a/rainbow-delimiters.el
+++ b/rainbow-delimiters.el
@@ -380,9 +380,9 @@ The syntax table is constructed by the function
       (modify-syntax-entry ?\) "){" table))
     table))

-(defsubst rainbow-delimiters-depth (loc)
-  "Return # of nested levels of parens, brackets, braces LOC is inside of."
-  (let ((depth (car (rainbow-delimiters-syntax-ppss loc))))
+(defsubst rainbow-delimiters-depth (ppss)
+  "Return # of nested levels of delimiters position at parse state PPSS."
+  (let ((depth (car ppss)))
     (if (>= depth 0)
         depth
       0))) ; Ignore negative depths created by unmatched closing parens.
@@ -492,33 +492,37 @@ Used by font-lock for dynamic highlighting."
   (with-syntax-table rainbow-delimiters-syntax-table
     (let ((inhibit-point-motion-hooks t))
       ;; Point can be anywhere in buffer; determine the nesting depth at point.
-      (let ((depth (rainbow-delimiters-depth (point))))
+      (let* ((last-ppss-pos (point))
+             (ppss (rainbow-delimiters-syntax-ppss last-ppss-pos))
+             (depth (rainbow-delimiters-depth ppss)))
         (while (and (< (point) end)
                     (re-search-forward rainbow-delimiters-delim-regex end t))
           (let ((delim-pos (match-beginning 0)))
-            (let ((ppss (rainbow-delimiters-syntax-ppss delim-pos)))
-              (unless (rainbow-delimiters-char-ineligible-p delim-pos ppss)
-                (let* ((delim (char-after delim-pos))
-                       (opening-delim-info
-                        (assq delim rainbow-delimiters-opening-delim-info)))
-                  (if opening-delim-info
-                      (progn
-                        (setq depth (1+ depth))
-                        (rainbow-delimiters-apply-color (cdr opening-delim-info)
-                                                        depth
-                                                        delim-pos
-                                                        t))
-                    ;; Not an opening delimiter, so it's a closing delimiter.
-                    (let ((closing-delim-info
-                           (assq delim rainbow-delimiters-closing-delim-info))
-                          (matching-opening-delim (char-after (nth 1 ppss))))
-                      (rainbow-delimiters-apply-color (nthcdr 2 closing-delim-info)
+            (setq ppss (save-excursion
+                         (parse-partial-sexp last-ppss-pos delim-pos nil nil ppss)))
+            (setq last-ppss-pos delim-pos)
+            (unless (rainbow-delimiters-char-ineligible-p delim-pos ppss)
+              (let* ((delim (char-after delim-pos))
+                     (opening-delim-info
+                      (assq delim rainbow-delimiters-opening-delim-info)))
+                (if opening-delim-info
+                    (progn
+                      (setq depth (1+ depth))
+                      (rainbow-delimiters-apply-color (cdr opening-delim-info)
                                                       depth
                                                       delim-pos
-                                                      (= (nth 1 closing-delim-info)
-                                                         matching-opening-delim))
-                      (setq depth (or (and (<= depth 0) 0) ; unmatched delim
-                                      (1- depth)))))))))))))
+                                                      t))
+                  ;; Not an opening delimiter, so it's a closing delimiter.
+                  (let ((closing-delim-info
+                         (assq delim rainbow-delimiters-closing-delim-info))
+                        (matching-opening-delim (char-after (nth 1 ppss))))
+                    (rainbow-delimiters-apply-color (nthcdr 2 closing-delim-info)
+                                                    depth
+                                                    delim-pos
+                                                    (= (nth 1 closing-delim-info)
+                                                       matching-opening-delim))
+                    (setq depth (or (and (<= depth 0) 0) ; unmatched delim
+                                    (1- depth))))))))))))
   ;; We already fontified the delimiters, tell font-lock there's nothing more
   ;; to do.
   nil)

@Fanael
Copy link
Collaborator

Fanael commented Sep 7, 2014

Not really related but interesting: this patch cuts the time to execute (progn (font-lock-flush) (font-lock-ensure)) on the current SQLite snapshot in half: without it, that expression needs 125.93s, with it, it's 64.36s. Not only it decreases latency (I hope), it's a nice win in terms of throughput, too.

@Fanael
Copy link
Collaborator

Fanael commented Sep 7, 2014

Committed in 35eace7. Does the issue still occur?

@vitillo
Copy link
Author

vitillo commented Sep 8, 2014

Works fine for me now, thanks!

@vitillo vitillo closed this as completed Sep 8, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants