branch: externals/indent-bars
commit ee36aa78ae4dfba278fa07eb4ec8784d23741f9f
Author: JD Smith <[email protected]>
Commit: JD Smith <[email protected]>

    ts: emphasis scope algorithm added, with struct shorthands
---
 indent-bars-ts.el | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)

diff --git a/indent-bars-ts.el b/indent-bars-ts.el
index b8642f2224..1db299b1cb 100644
--- a/indent-bars-ts.el
+++ b/indent-bars-ts.el
@@ -202,6 +202,100 @@ by nodes of those types (e.g. module)."
   (unless (indent-bars-ts--ignore-blank (match-beginning 0))
     (indent-bars--handle-blank-lines)))
 
+
+;;;; Scope
+(defvar indent-bars-ts-faded-style nil)
+
+(cl-declaim (optimize (safety 0))) ; no need for type check
+(cl-defstruct
+    (indent-bars-ts-scope
+     (:copier nil)
+     (:conc-name ibts/)
+     (:constructor ibts/create))
+  (start (make-marker)) (end (make-marker))
+  (point -1) (tick 0) query)
+
+(defvar-local ibtcs nil  ; N.B. see shorthands at bottom of file
+  "The current `indent-bars-ts-scope' struct.")
+
+(defsubst indent-bars-ts--style (pos)
+  "Return the style to use based on pos.
+Returns the deemphasized style if POS is outside the current
+treesitter scope, nil otherwise"
+  (and ibtcs (or (< pos (ibts/start ibtcs)) (> pos (ibts/end ibtcs)))
+       indent-bars-ts-faded-style))
+
+(defun indent-bars-ts--symdiff (a b)
+    "Return the symmetric difference between ranges A and B.
+A and B ranges of (start . end) conses.  Their symmetric
+difference is a list of ranges, possibly nil, that one (but not
+both) of them cover."
+    (let ((l '()))
+      (if (< (car b) (car a)) (setq b (prog1 a (setq a b))))
+      (if (< (cdr a) (car b))
+          (push a l)
+        (unless (= (car a) (car b))
+          (push (cons (car a) (car b)) l)))
+      (if (> (car b) (cdr a))
+          (push b l)
+        (unless (= (cdr a) (cdr b))
+          (push (if (> (cdr a) (cdr b))
+                    (cons (cdr b) (cdr a))
+                  (cons (cdr a) (cdr b)))
+           l)))
+      l))
+
+(defun indent-bars-ts--update-scope1 ()
+  "Perform the treesitter scope update.
+If the buffer is modified or the point has moved, re-query the
+scope bounds.  If it has changed (beyond normal marker movement),
+refontify the symmetric difference between old and new
+ranges (i.e those ranges covered by either old or new, but not
+both)."
+  (unless (and (= (point) (ibts/point ibtcs))
+              (= (buffer-modified-tick) (ibts/tick ibtcs)))
+    ;; scope may have changed
+    (when-let ((node (treesit-node-on
+                     (max (point-min) (1- (point))) (point)
+                     indent-bars-ts--parser))
+              (scope (indent-bars-ts--node-query
+                      node (ibts/query ibtcs) nil 'innermost)))
+      (let ((bstart (ibts/start ibtcs))
+           (bend (ibts/end ibtcs))
+           (tstart (treesit-node-start scope))
+           (tend (treesit-node-end scope)))
+       (unless (and (= tstart bstart) (= tend bend))
+         (setf (ibts/tick ibtcs) (buffer-modified-tick)
+               (ibts/point ibtcs) (point))
+         (set-marker (ibts/start ibtcs) tstart)
+         (set-marker (ibts/end ibtcs) tend)
+         (cl-loop for (beg . end) in
+                  (indent-bars-ts--symdiff
+                   (cons bstart bend) (cons tstart tend))
+                  do (font-lock-flush beg end)))))))
+
+(defvar indent-bars-ts--scope-timer nil)
+(defun indent-bars-ts--update-scope ()
+  "Update treesit scope when possible."
+  (if-let ((tmr indent-bars--highlight-timer))
+      (progn
+       (timer-set-time
+        tmr (time-add (current-time) indent-bars-ts-update-delay))
+       (unless (memq tmr timer-list) (timer-activate tmr)))
+    (setq indent-bars-ts--scope-timer
+         (run-with-timer indent-bars-ts-update-delay nil
+                         #'indent-bars-ts--update-scope1))))
+
+;;;; Setup
+(defun indent-bars-ts--init-scope ()
+  "Initialize scope style and variables."
+  (unless (get 'indent-bars-ts-setup :init-scope)
+    (indent-bars-ts--add-customs)
+    (setq indent-bars-ts-faded-style (indent-bars--new-style))
+    (let ((indent-bars-current-style indent-bars-ts-faded-style))
+      (indent-bars--initialize-style))
+    (put 'indent-bars-ts-setup :init-scope t)))
+
 ;;;###autoload
 (defun indent-bars-ts-setup ()
   "Setup indent-bars for using with treesiter."
@@ -232,3 +326,18 @@ by nodes of those types (e.g. module)."
           (message "%s. See `indent-bars-no-descend-string'.\n%s"
                    "indent-bars: malformed string query; disabling"
                    err)))))
+
+    ;; Emphasis Scope: use alternate styling outside current scope
+    (when-let ((types (alist-get lang indent-bars-treesit-emphasis-scope)))
+      (indent-bars-ts--init-scope)
+      (setq ibtcs (ibts/create))
+      (setf (ibts/query ibtcs)
+           (treesit-query-compile lang `([,@(mapcar #'list types)] @ctx))))
+    
+    (setq indent-bars--style-function #'indent-bars-ts--style)))
+
+(provide 'indent-bars-ts)
+;;; indent-bars-ts.el ends here
+;; Local Variables:
+;; read-symbol-shorthands: (("ibts/" . "indent-bars-ts-scope-") ("ibtcs" . 
"indent-bars-ts-current-scope"))
+;; End:

Reply via email to