branch: elpa/highlight-parentheses
commit 3715c2ace6d04909d5aeea8c5a0ac2cd9b4ecabb
Author: Tassilo Horn <[email protected]>
Commit: Tassilo Horn <[email protected]>
Optimize for distant paren pairs where scan-sexps becomes expensive
References: https://todo.sr.ht/~tsdh/highlight-parentheses.el/5
---
highlight-parentheses.el | 73 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 59 insertions(+), 14 deletions(-)
diff --git a/highlight-parentheses.el b/highlight-parentheses.el
index a05c51f698..50fb3ee2d1 100644
--- a/highlight-parentheses.el
+++ b/highlight-parentheses.el
@@ -154,6 +154,12 @@ Color attributes might be overriden by
`highlight-parentheses-colors' and
"The last point for which parentheses were highlighted.
This is used to prevent analyzing the same context over and over.")
+(defvar-local highlight-parentheses--last-pair nil
+ "A cons (OPEN-PAREN-POS . CLOSING-PAREN-POS).
+It describes the position of the last immediately surrounding pair of
+parens and is used to shortcut highlighting if point didn't move so far
+that the immediately surrounding pair changed.")
+
(defvar-local highlight-parentheses--timer nil
"A timer initiating the movement of the `highlight-parentheses--overlays'.")
@@ -170,27 +176,66 @@ If the optional argument OVERLAYS (a list) is non-nil,
delete all
overlays in it instead."
(mapc #'delete-overlay overlays))
+(defun highlight-parentheses--highlight-needed-p ()
+ "Return non-nil when if re-highlighting is needed."
+ (let ((point (point))
+ (last-point highlight-parentheses--last-point))
+ (or
+ ;; A forced refresh.
+ (< last-point 0)
+ ;; Check if point has moved and during the move, it crossed some paren.
+ (and (/= (point) last-point)
+ (catch 'highlight-needed
+ (let ((start (if (< point last-point) point last-point))
+ (end (if (< point last-point) last-point point)))
+ ;; If the move was large, checking if we crossed some paren
+ ;; becomes too expensive, so give up.
+ (when (> (- end start) 5000)
+ (throw 'highlight-needed t))
+ ;; Otherwise check if we crossed some paren.
+ (while (< start end)
+ (when (memq (char-after start) '(?\( ?\{ ?\[ ?\< ?\) ?\} ?\]
?\>))
+ (throw 'highlight-needed t))
+ (cl-incf start))
+ ;; Lets assume we keep moving in the same direction, so update
+ ;; last-point to the current value of point.
+ (setq highlight-parentheses--last-point point)
+ nil))))))
+
(define-obsolete-function-alias 'hl-paren-highlight
'highlight-parentheses--highlight "2.0.0")
(defun highlight-parentheses--highlight ()
"Highlight the parentheses around point."
- (unless (= (point) highlight-parentheses--last-point)
+ (when (highlight-parentheses--highlight-needed-p)
(setq highlight-parentheses--last-point (point))
(let ((overlays highlight-parentheses--overlays)
+ (first-iteration t)
pos1 pos2)
- (save-excursion
- (ignore-errors
- (when highlight-parentheses-highlight-adjacent
- (cond ((memq (preceding-char) '(?\) ?\} ?\] ?\>))
- (backward-char 1))
- ((memq (following-char) '(?\( ?\{ ?\[ ?\<))
- (forward-char 1))))
- (while (and (setq pos1 (cadr (syntax-ppss pos1)))
- (cdr overlays))
- (move-overlay (pop overlays) pos1 (1+ pos1))
- (when (setq pos2 (scan-sexps pos1 1))
- (move-overlay (pop overlays) (1- pos2) pos2)))))
- (highlight-parentheses--delete-overlays overlays))))
+ (catch 'no-change
+ (save-excursion
+ (ignore-errors
+ (when highlight-parentheses-highlight-adjacent
+ (cond ((memq (preceding-char) '(?\) ?\} ?\] ?\>))
+ (backward-char 1))
+ ((memq (following-char) '(?\( ?\{ ?\[ ?\<))
+ (forward-char 1))))
+ (while (and (setq pos1 (cadr (syntax-ppss pos1)))
+ (cdr overlays))
+ (move-overlay (pop overlays) pos1 (1+ pos1))
+ (when (setq pos2 (scan-sexps pos1 1))
+ (move-overlay (pop overlays) (1- pos2) pos2)
+ ;; Check if the immediately surrounding pair of parens is at
the
+ ;; same location as before. If so, we can skip moving the
other
+ ;; overlays since they haven't changed, too.
+ (when (and first-iteration
+ (equal highlight-parentheses--last-pair
+ (cons pos1 (1- pos2))))
+ (throw 'no-change t))
+ (setq first-iteration nil)))))
+ (highlight-parentheses--delete-overlays overlays))
+ (setq highlight-parentheses--last-pair
+ (cons (overlay-start (car highlight-parentheses--overlays))
+ (overlay-start (cadr highlight-parentheses--overlays)))))))
(define-obsolete-function-alias 'hl-paren-initiate-highlight
'highlight-parentheses--initiate-highlight "2.0.0")