branch: externals/indent-bars
commit 88010c272443aff6a3fcc0244eabf519cbf74a0b
Author: JD Smith <[email protected]>
Commit: JD Smith <[email protected]>
Initial efforts towards font-lock-free/managing bars
Actually just wraps font-lock-fontify-region-function and only runs it
when "necessary", drawing our bars entirely outside of font-lock (and
after it, if it was necessary).
---
indent-bars-ts.el | 56 ++++++---------
indent-bars.el | 208 ++++++++++++++++++++++++++++++++----------------------
2 files changed, 144 insertions(+), 120 deletions(-)
diff --git a/indent-bars-ts.el b/indent-bars-ts.el
index 1fbe10f832..2a7c2ee0cd 100644
--- a/indent-bars-ts.el
+++ b/indent-bars-ts.el
@@ -312,34 +312,34 @@ recently clipped node ranges in scope."
(let ((beg (match-beginning 0)))
(unless (indent-bars-ts--ignore-blank beg)
(if (indent-bars-ts--out-of-scope beg) ;fully out of scope
- (indent-bars--handle-blank-lines (match-beginning 0) (match-end 0)
+ (indent-bars--display-blank-lines (match-beginning 0) (match-end 0)
(cdr indent-bars-ts-in-out-style))
;; Switch from out of scope to in scope after start-bars
- (indent-bars--handle-blank-lines (match-beginning 0) (match-end 0)
+ (indent-bars--display-blank-lines (match-beginning 0) (match-end 0)
(cdr indent-bars-ts-in-out-style)
(ibts/start-bars ibtcs)
(car indent-bars-ts-in-out-style))))))
-(defun indent-bars-ts--draw-all-bars-between (start end)
- "Search for and draw all bars between START and END.
-The beginning of line at START is used to locate real and (if
-configured) blank-line bars, which are drawn according to the
-appropriate style. This is basically a very tiny, bar-only
-version of what `font-lock-fontify-region-keywords' does."
- (save-excursion
- (goto-char start)
- (forward-line 0)
- (setq start (point))
- (while (and (< (point) end)
- (re-search-forward
- (caar indent-bars--font-lock-keywords) end t))
- (indent-bars-ts--display))
- (when indent-bars-display-on-blank-lines
- (goto-char start)
- (while (and (< (point) end)
- (re-search-forward
- (caar indent-bars--font-lock-blank-line-keywords) end t))
- (indent-bars-ts--handle-blank-lines)))))
+;; (defun indent-bars-ts--draw-all-bars-between (start end)
+;; "Search for and draw all bars between START and END.
+;; The beginning of line at START is used to locate real and (if
+;; configured) blank-line bars, which are drawn according to the
+;; appropriate style. This is basically a very tiny, bar-only
+;; version of what `font-lock-fontify-region-keywords' does."
+;; (save-excursion
+;; (goto-char start)
+;; (forward-line 0)
+;; (setq start (point))
+;; (while (and (< (point) end)
+;; (re-search-forward
+;; (caar indent-bars--font-lock-keywords) end t))
+;; (indent-bars-ts--display))
+;; (when indent-bars-display-on-blank-lines
+;; (goto-char start)
+;; (while (and (< (point) end)
+;; (re-search-forward
+;; (caar indent-bars--font-lock-blank-line-keywords) end t))
+;; (indent-bars-ts--handle-blank-lines)))))
(defmacro indent-bars-ts--order-ranges (a b)
"Order ranges A and B by start position."
@@ -395,17 +395,6 @@ Based loosely on `jit-lock-function' and
`jit-lock-fontify-now'."
;; while (< ve end))))
))
-(defun indent-bars-ts--update-bars-on-scroll (win start)
- "Update bars as needed within the window WIN from START.
-To be added to `window-scroll-functions'. Consults the invalid
-ranges of the current scope."
- (indent-bars-ts--add-bars-in-range (max (point-min) (- start
jit-lock-chunk-size))
- (min (point-max) (+ (or (window-end win)
(+ start jit-lock-chunk-size))
- jit-lock-chunk-size))
- ;; (max (point-min) (- start
jit-lock-chunk-size))
- ;; (min (point-max) (+ end
jit-lock-chunk-size))
- ))
-
(defun indent-bars-ts--update-scope1 (buf)
"Perform the treesitter scope font-lock update in buffer BUF.
Re-query the scope node at point, and if it has moved (beyond
@@ -507,7 +496,6 @@ performed."
(make-local-variable 'font-lock-extra-managed-props)
(cl-pushnew 'indent-bars-invalid font-lock-extra-managed-props)
(add-hook 'post-command-hook #'indent-bars-ts--update-scope nil t)
- (add-hook 'window-scroll-functions #'indent-bars-ts--update-bars-on-scroll
nil t)
(add-hook 'indent-bars--teardown-functions 'indent-bars-ts--teardown)))
(defun indent-bars-ts--teardown ()
diff --git a/indent-bars.el b/indent-bars.el
index 3c7cca2e85..48b1a5bc0e 100644
--- a/indent-bars.el
+++ b/indent-bars.el
@@ -71,6 +71,7 @@
;;;; Variables
(defvar indent-bars-mode)
+(defvar-local indent-bars--regexp nil)
;;;; Customization
(defgroup indent-bars nil
"Highlight indentation bars."
@@ -1020,13 +1021,13 @@ the number of bars actually displayed."
(let* ((nb (min max (/ (- tab-width off -1) indent-bars-spacing)))
(str (apply #'indent-bars--blank-string style off nb
bar-from tab-width r)))
- (put-text-property p (+ p 1) 'display str)
+ (put-text-property p (+ p 1) 'ib-display str)
nb))
(defun indent-bars--draw-line (style nbars start end &optional
invent switch-after style2)
"Draw NBARS bars on the line between positions START and END.
-Bars are drawn in style STYLE, `indent-bars-style' by default
+Bars are drawn in style STYLE, `indent-bars-style' by default.
START is assumed to be on a line beginning position. Drawing
starts at a column determined by `indent-bars-starting-column'.
Tabs at the line beginning have appropriate display properties
@@ -1064,44 +1065,40 @@ needed."
(cl-incf start (+ (mod vp tab-width) (/ vp tab-width))))
(when (<= bar nbars) ; still bars to show
(if indent-bars--no-stipple
- (setq prop 'display fun #'indent-bars--no-stipple-char)
+ (setq prop 'ib-display fun #'indent-bars--no-stipple-char)
(setq prop 'face fun #'indent-bars--face))
(let ((pos (if tabs start (+ start indent-bars--offset))))
(while (and (<= bar nbars) (< pos end))
- (put-text-property pos (1+ pos)
- prop (funcall fun
- (cond ((integerp switch-after)
- (prog1
- (if (> switch-after 0)
style style2)
- (cl-decf switch-after)
- (if (<= switch-after 0)
- (setq switch-after t))))
- ((eq switch-after t) style2)
- (t style))
- bar))
+ (put-text-property
+ pos (1+ pos)
+ prop (funcall fun
+ (cond ((integerp switch-after)
+ (prog1
+ (if (> switch-after 0) style style2)
+ (cl-decf switch-after)
+ (if (<= switch-after 0)
+ (setq switch-after t))))
+ ((eq switch-after t) style2)
+ (t style))
+ bar))
(cl-incf bar)
(cl-incf pos indent-bars-spacing))
;; STILL bars to show: invent them (if requested)
(if (and invent (<= bar nbars))
(put-text-property
- end (1+ end) 'display
+ end (1+ end) 'ib-display
(concat (indent-bars--blank-string
style (- pos end) (- nbars bar -1) bar nil
switch-after style2)
"\n")))))))
-;;;; Font Lock
-(defvar-local indent-bars--font-lock-keywords nil)
-(defvar indent-bars--font-lock-blank-line-keywords nil)
-
-(defvar indent-bars-orig-unfontify-region nil)
-(defun indent-bars--unfontify (beg end)
- "Unfontify region between BEG and END.
-Removes the display properties in addition to the normal managed
-font-lock properties."
- (let ((font-lock-extra-managed-props
- (append '(display) font-lock-extra-managed-props)))
- (funcall indent-bars-orig-unfontify-region beg end)))
+(defsubst indent-bars--context-bars (end)
+ "Maximum number of bars at point and END.
+Moves point."
+ (max (indent-bars--current-indentation-depth)
+ (progn
+ (goto-char (1+ end)) ; end is always eol
+ (indent-bars--current-indentation-depth))))
(defun indent-bars--display (beg end &optional style switch-after style2)
"Draw indentation bars from BEG..END, based on line contents.
@@ -1114,15 +1111,7 @@ passed, uses `indent-bars-style' for drawing."
(when (> n 0) (indent-bars--draw-line style n beg end nil
switch-after style2))))
-(defsubst indent-bars--context-bars (end)
- "Maximum number of bars at point and END.
-Moves point."
- (max (indent-bars--current-indentation-depth)
- (progn
- (goto-char (1+ end)) ; end is always eol
- (indent-bars--current-indentation-depth))))
-
-(defun indent-bars--handle-blank-lines (beg end &optional style switch-after
style2)
+(defun indent-bars--display-blank-lines (beg end &optional style switch-after
style2)
"Display the appropriate bars over the blank-only lines from BEG..END.
Only called if `indent-bars-display-on-blank-lines' is non-nil.
To be called on complete multi-line blank line regions.
@@ -1134,8 +1123,7 @@ line indentation, above and below. Drawing using
in `indent-bars--draw-line'.
Note: blank lines at the very beginning or end of the buffer are
-not indicated, even if they otherwise would be. This function is
-configured by default in `indent-bars--handle-blank-lines-form'."
+not indicated, even if they otherwise would be."
(let ((pm (point-max)) ctxbars)
(save-excursion
(goto-char (1- beg))
@@ -1151,23 +1139,65 @@ configured by default in
`indent-bars--handle-blank-lines-form'."
(beginning-of-line 2)))))
nil))
-(defvar font-lock-beg) (defvar font-lock-end) ; Dynamic font-lock variables!
-(defun indent-bars--extend-blank-line-regions ()
- "Extend the region about to be font-locked to include stretches of blank
lines."
- ;; (message "request to extend: %d->%d" font-lock-beg font-lock-end)
- (let ((changed nil) (chars " \t\n"))
- (goto-char font-lock-beg)
- (when (< (skip-chars-backward chars) 0)
- (unless (bolp) (beginning-of-line 2)) ; spaces at end don't count
- (when (< (point) font-lock-beg)
- (setq changed t font-lock-beg (point))))
- (goto-char font-lock-end)
- (when (> (skip-chars-forward chars) 0)
- (unless (bolp) (beginning-of-line 1))
- (when (> (point) font-lock-end)
- (setq changed t font-lock-end (point))))
- ;; (if changed (message "expanded to %d->%d" font-lock-beg font-lock-end))
- changed))
+;;;; jit-lock
+;; (defvar indent-bars--orig-unfontify-region nil)
+(defvar indent-bars--orig-fontify-region nil)
+
+;; Dynamic jit-lock variables
+(defvar jit-lock-start) (defvar jit-lock-end)
+(defun indent-bars--extend-blank-line-regions (&rest _r)
+ "Eagerly extend the region about to be jit-locked.
+This extends the region to include complete stretches of blank
+lines. Sets the dynamic variables `jit-lock-start' and
+`jit-lock-end'."
+ (save-excursion
+ (let ((chars " \t\n"))
+ (goto-char jit-lock-start)
+ (when (< (skip-chars-backward chars) 0)
+ (unless (bolp) (beginning-of-line 2)) ; spaces at end don't count
+ (when (< (point) jit-lock-start)
+ (setq jit-lock-start (point))))
+ (goto-char jit-lock-end)
+ (when (> (skip-chars-forward chars) 0)
+ (unless (bolp) (beginning-of-line 1))
+ (when (> (point) jit-lock-end)
+ (setq jit-lock-end (point)))))))
+
+(defvar-local indent-bars--display-function 'indent-bars--display)
+(defvar-local indent-bars--display-blank-lines-function
+ 'indent-bars--display-blank-lines)
+(defun indent-bars--draw-all-bars-between (start end)
+ "Search for and draw all bars between START and END.
+The beginning of line at START is used to locate real and (if
+configured) blank-line bars, which are drawn according to the
+appropriate style. This is basically a very tiny, bar-only
+version of what `font-lock-fontify-region-keywords' does."
+ (save-excursion
+ (goto-char start)
+ (forward-line 0)
+ (while (and (< (point) end)
+ (re-search-forward indent-bars--regexp end t))
+ (if (match-beginning 2)
+ (funcall indent-bars--display-blank-lines-function
+ (match-beginning 2) (match-end 2))
+ (funcall indent-bars--display-function
+ (match-beginning 1) (match-end 1))))))
+
+(defun indent-bars--fontify-default (beg end verbose)
+ "Add indent-bars from BEG to END after calling font-lock there.
+VERBOSE is provided by font-lock."
+ ;; First fontify with font-lock (clears then sets 'face)
+ (funcall indent-bars--orig-fontify-region beg end verbose)
+ ;; Then draw bars (which may overwrite 'face in a few places)
+ (remove-text-properties beg end '(ib-display nil))
+ (indent-bars--draw-all-bars-between beg end))
+
+(defvar indent-bars--fontify-function 'indent-bars--fontify-default)
+(defun indent-bars--fontify (beg end verbose)
+ "Fontify the region from BEG to END.
+VERBOSE is provided by font-lock. To be set as the
+`font-lock-fontify-region-function'."
+ (funcall indent-bars--fontify-function beg end verbose))
;;;; Current indentation depth highlighting
(defvar-local indent-bars--current-depth 0)
@@ -1527,31 +1557,35 @@ Adapted from `highlight-indentation-mode'."
((and (boundp 'standard-indent) standard-indent))
(t 4))) ; backup
-(defvar indent-bars--display-form
- '(indent-bars--display (match-beginning 1) (match-end 1)))
-(defvar indent-bars--handle-blank-lines-form
- '(indent-bars--handle-blank-lines (match-beginning 0) (match-end 0)))
+;; (defvar indent-bars--display-form
+;; '(indent-bars--display (match-beginning 1) (match-end 1)))
+;; (defvar indent-bars--handle-blank-lines-form
+;; '(indent-bars--display-blank-lines (match-beginning 0) (match-end 0)))
(defun indent-bars--setup-font-lock ()
- "Setup font lock keywords and functions for indent-bars."
- (unless (eq font-lock-unfontify-region-function #'indent-bars--unfontify)
- (setq indent-bars-orig-unfontify-region
font-lock-unfontify-region-function))
- (setq-local font-lock-unfontify-region-function #'indent-bars--unfontify)
- (setq indent-bars--font-lock-keywords ; basic blank prefix detection
- `((,(rx-to-string `(seq bol
- (group
- ,(if (not indent-tabs-mode)
- `(>= ,(1+ indent-bars--offset) ?\s)
- '(+ (any ?\t ?\s))))
- (not (any ?\t ?\s ?\n))))
- (1 ,indent-bars--display-form))))
- (font-lock-add-keywords nil indent-bars--font-lock-keywords t)
- (if indent-bars-display-on-blank-lines
- (let ((re (rx bol (* (or ?\s ?\t ?\n)) ?\n))) ; multi-line blank regions
- (setq indent-bars--font-lock-blank-line-keywords
- `((,re (0 ,indent-bars--handle-blank-lines-form))))
- (font-lock-add-keywords nil indent-bars--font-lock-blank-line-keywords
t)
- (add-hook 'font-lock-extend-region-functions
- #'indent-bars--extend-blank-line-regions 95 t))))
+ "Wrap the `font-lock-fontify-region-function' to provide bars."
+ ;; Setup to wrap font-lock
+ (unless (eq font-lock-fontify-region-function #'indent-bars--fontify)
+ (setq ;; indent-bars--orig-unfontify-region
font-lock-unfontify-region-function
+ indent-bars--orig-fontify-region font-lock-fontify-region-function)
+ (setq-local ;; font-lock-unfontify-region-function #'indent-bars--unfontify
+ font-lock-fontify-region-function #'indent-bars--fontify))
+ (setq indent-bars--regexp
+ (rx-to-string
+ `(seq bol (or (and
+ ;; group 1: basic blank indent detection
+ (group
+ ,(if (not indent-tabs-mode)
+ `(>= ,(1+ indent-bars--offset) ?\s)
+ '(+ (any ?\t ?\s))))
+ (not (any ?\t ?\s ?\n)))
+ ;; group 2: multi-line blank regions
+ ,@(if indent-bars-display-on-blank-lines
+ '((group (* (or ?\s ?\t ?\n)) ?\n)))))))
+
+ ;; Extend blank line regions maximally when fontifying
+ (when indent-bars-display-on-blank-lines
+ (add-hook 'jit-lock-after-change-extend-region-functions
+ #'indent-bars--extend-blank-line-regions 95 t)))
(declare-function indent-bars-ts-mode "indent-bars-ts")
@@ -1595,7 +1629,8 @@ Adapted from `highlight-indentation-mode'."
(setq indent-bars--current-depth 0)
(indent-bars--highlight-current-depth))
- ;; Font-lock
+ ;;Jit/Font-lock
+ (cl-pushnew 'ib-display (alist-get 'display char-property-alias-alist))
(indent-bars--setup-font-lock)
(font-lock-flush))
@@ -1615,18 +1650,19 @@ Adapted from `highlight-indentation-mode'."
indent-bars--stipple-remaps)
(setq indent-bars--stipple-remaps nil)))
- (font-lock-remove-keywords nil indent-bars--font-lock-keywords)
- (font-lock-remove-keywords nil indent-bars--font-lock-blank-line-keywords)
+ (when indent-bars--orig-fontify-region
+ (setq ;; font-lock-unfontify-region-function
+ ;; indent-bars--orig-unfontify-region
+ font-lock-fontify-region-function
+ indent-bars--orig-fontify-region))
+ (remove-text-properties (point-min) (point-max) '(ib-display nil))
(font-lock-flush)
(font-lock-ensure)
- (when indent-bars-orig-unfontify-region
- (setq font-lock-unfontify-region-function
- indent-bars-orig-unfontify-region))
(setq indent-bars--current-depth 0)
(remove-hook 'text-scale-mode-hook #'indent-bars--update-all-stipples t)
(remove-hook 'post-command-hook #'indent-bars--highlight-current-depth t)
- (remove-hook 'font-lock-extend-region-functions
+ (remove-hook 'jit-lock-after-change-extend-region-functions
#'indent-bars--extend-blank-line-regions t)
(remove-hook 'window-state-change-functions
#'indent-bars--window-change t)