[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/indent-bars ce7fb0641c 189/431: refactoring treesitter
From: |
ELPA Syncer |
Subject: |
[elpa] externals/indent-bars ce7fb0641c 189/431: refactoring treesitter to new file: initial stage |
Date: |
Mon, 16 Sep 2024 12:59:27 -0400 (EDT) |
branch: externals/indent-bars
commit ce7fb0641cf1e5e170cc3d697b1336454276715b
Author: JD Smith <93749+jdtsmith@users.noreply.github.com>
Commit: JD Smith <93749+jdtsmith@users.noreply.github.com>
refactoring treesitter to new file: initial stage
---
indent-bars-ts.el | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
indent-bars.el | 160 +++++++++--------------------------------------------
2 files changed, 189 insertions(+), 134 deletions(-)
diff --git a/indent-bars-ts.el b/indent-bars-ts.el
new file mode 100644
index 0000000000..cb20c3eff4
--- /dev/null
+++ b/indent-bars-ts.el
@@ -0,0 +1,163 @@
+;;; indent-bars-ts.el --- treesitter support for indent-bars -*-
lexical-binding: t; -*-
+;; Copyright (C) 2023 J.D. Smith
+
+;;; Commentary:
+
+;; tree-sitter support for indent-bars:
+
+;; - Optionally uses tree-sitter to fine-tune indentation depth
+;; (avoiding "too many bars" in e.g. argument lists)
+;; - Use treesitter to avoid adding bars to blank lines in strings or
+;; other types.
+;; - Enable alternate styling for bars inside and outside the
+;; treesitter "scope", where scope is defined as the wrapping
+;; elements configured in `indent-bars-ts`.
+
+(require 'seq)
+(require 'treesit nil t) ; treesit is optional
+(require 'indent-bars)
+
+;;;; Customization
+
+
+
+(defcustom indent-bars-treesit-wrap nil
+ "An alist of language and treesitter node type symbols to wrap.
+Inside such wrapping types, indentation bar depth will not be
+increased more than one beyond that of the containing node's
+depth. This is typically done for lists, parameters, function
+arguments, etc., to avoid unwanted \"extra bars\". Types must be
+valid node types for the grammar of the language indicated."
+ :type '(choice (const :tag "No wrap types" nil)
+ (alist :tag "Alist of node types"
+ :key-type (symbol :tag "Language")
+ :value-type (repeat :tag "Types" (symbol :tag
"Type"))))
+ :group 'indent-bars)
+
+(defcustom indent-bars-treesit-shadow-scope nil
+ "An alist of language and treesitter node types to emphasize.
+Bars on text ouside of the matching treesitter nodes will be
+de-emphasized with alternative \"shadow\" style."
+ :type '(choice (const :tag "Scope types" nil)
+ (alist :tag "Alist of node types"
+ :key-type (symbol :tag "Language")
+ :value-type (repeat :tag "Types" (symbol :tag "Type"))))
+ :group 'indent-bars)
+
+(defcustom indent-bars-treesit-ignore-blank-lines-types nil
+ "Do not style blank lines when the type of node at start is in this list.
+Either nil, or a list of node type strings to avoid adding blank
+line styling to. Typically \"top-level\" node types like
+\"module\", \"program\", and \"translation_unit\" would be used
+here, and they need not be valid types for any particular
+grammar. Only applicable if `indent-bars-display-on-blank-lines'
+is set."
+ :type '(choice (const :tag "None" nil)
+ (repeat :tag "Node types" string))
+ :group 'indent-bars)
+
+(defcustom indent-bars-no-descend-string 'string
+ "Configure bar behavior inside treesitter-matched strings.
+If non-nil, set to a symbol naming a tree-sitter string node type
+into which bars will go no deeper than their starting line. If
+this node type is invalid, a message is printed and the feature
+is disabled."
+ :local t
+ :type '(choice (const :tag "Disable" nil) (symbol :tag "Node Type"))
+ :group 'indent-bars)
+
+;;;; Tree-sitter
+(defvar-local indent-bars-ts--parser nil)
+(defvar-local indent-bars-ts--query nil)
+(defvar-local indent-bars-ts--string-query nil)
+
+(defun indent-bars-ts--node-query (node query &optional start-only
first-spanning)
+ "Capture node(s) spanning NODE matching QUERY.
+QUERY is a compiled treesit query. If START-ONLY is non-nil, the
+query searches for matching nodes spanning the start of the node
+at point, otherwise nodes which intersect anywhere with the node
+will be returned. If FIRST-SPANNING is non-nil, return the first
+matching node, but only if it fully spans the full start..end
+range of NODE, otherwise return nil."
+ (let* ((start (treesit-node-start node))
+ (end (if start-only start (treesit-node-end node)))
+ (nodes (treesit-query-capture indent-bars-ts--parser query
+ start end t)))
+ (when (and first-spanning nodes)
+ (let ((n (car nodes)))
+ (setq nodes
+ (and (<= (treesit-node-start n) start)
+ (>= (treesit-node-end n) end)
+ n))))
+ nodes))
+
+(defsubst indent-bars--indent-at-node (node)
+ "Return the current indentation at the start of TS node NODE."
+ (save-excursion
+ (goto-char (treesit-node-start node))
+ (current-indentation)))
+
+(defun indent-bars-ts--update-indentation-depth (d)
+ "Update depth D using tree-sitter-region."
+ (if-let (((not (bobp)))
+ (node (treesit-node-on (1- (point)) (point) indent-bars-ts--parser))
+ (dnew
+ (if (and indent-bars-no-descend-string
+ (indent-bars-ts--node-query
+ node indent-bars-ts--string-query t))
+ ;; A string: do not descend
+ (1+ (indent-bars--depth (indent-bars--indent-at-node node)))
+ ;; Check context
+ (when-let ((ctx (indent-bars-ts--node-query
+ node indent-bars-ts--query nil t)))
+ (1+ (indent-bars--depth
+ (indent-bars--indent-at-node ctx)))))))
+ (min dnew d)
+ d))
+
+
+(defun indent-bars--ignore-blank (beg)
+ "See if blank lines at BEG should be ignored using tree-sitter.
+Blank lines to ignore are those with types in
+`indent-bars-treesit-ignore-blank-lines-types'."
+ (and indent-bars-ts--parser
+ indent-bars-treesit-ignore-blank-lines-types
+ (when-let ((n (treesit-node-on beg beg)))
+ (seq-contains-p indent-bars-treesit-ignore-blank-lines-types
+ (treesit-node-type n)))))
+
+
+(defun indent-bars-ts--handle-blank-lines ()
+ "Wrapper for `indent-bars--handle-blank-lines' that works with treesitter.
+
+If `indent-bars-treesit-ignore-blank-lines-types' is configured,
+ignore blank lines whose starting positions are directly spanned
+by nodes of those types (e.g. module)."
+ (unless (indent-bars--ignore-blank (match-beginning 0))
+ (indent-bars--handle-blank-lines)))
+
+;;;###autoload
+(defun indent-bars-ts-setup ()
+ "Setup indent-bars for using with treesiter."
+ (when-let (((fboundp #'treesit-available-p))
+ ((treesit-available-p))
+ (lang (treesit-language-at (point-min)))
+ (types (alist-get lang indent-bars-treesit-wrap)))
+ (setq indent-bars-ts--parser
+ (cl-find lang (treesit-parser-list) :key #'treesit-parser-language)
+ indent-bars-ts--query
+ (treesit-query-compile lang `([,@(mapcar #'list types)] @ctx)))
+ (when indent-bars-no-descend-string
+ (let ((query `([(,indent-bars-no-descend-string)] @s))
+ (pm (point-min)))
+ (setq indent-bars-ts--string-query (treesit-query-compile lang query))
+ ;; Test it to be sure
+ (condition-case err
+ (treesit-query-capture indent-bars-ts--parser
+ indent-bars-ts--string-query pm pm t)
+ (treesit-query-error
+ (setq indent-bars-no-descend-string nil)
+ (message "indent-bars: malformed string query; disabling. See
indent-bars-no-descend-string.\n%s" err)))))
+ (setq indent-bars--update-depth-function
+ #'indent-bars-ts--update-indentation-depth)
+ ))
diff --git a/indent-bars.el b/indent-bars.el
index 34998dec3a..f16ea493b6 100644
--- a/indent-bars.el
+++ b/indent-bars.el
@@ -43,7 +43,7 @@
(require 'outline)
(require 'font-lock)
(require 'compat)
-(require 'treesit nil t) ; treesit is optional
+
;;;; Customization
(defgroup indent-bars nil
@@ -380,47 +380,11 @@ buffer-local automatically."
:type '(choice integer (const :tag "Discover automatically" :value nil))
:group 'indent-bars)
-;;;;; Treesitter
(defcustom indent-bars-treesit-support nil
"Whether to enable tree-sitter support (if available)."
:type 'boolean
:group 'indent-bars)
-(defcustom indent-bars-treesit-wrap nil
- "An alist of language and treesitter node type symbols to wrap.
-Inside such wrapping types, indentation bar depth will not be
-increased more than one beyond that of the containing node's
-depth. This is typically done for lists, parameters, function
-arguments, etc., to avoid unwanted \"extra bars\". Types must be
-valid node types for the grammar of the language indicated."
- :type '(choice (const :tag "No wrap types" nil)
- (alist :tag "Alist of node types"
- :key-type (symbol :tag "Language")
- :value-type (repeat :tag "Types" (symbol :tag
"Type"))))
- :group 'indent-bars)
-
-(defcustom indent-bars-treesit-ignore-blank-lines-types nil
- "Do not style blank lines when the type of node at start is in this list.
-Either nil, or a list of node type strings to avoid adding blank
-line styling to. Typically \"top-level\" node types like
-\"module\", \"program\", and \"translation_unit\" would be used
-here, and they need not be valid types for any particular
-grammar. Only applicable if `indent-bars-display-on-blank-lines'
-is set."
- :type '(choice (const :tag "None" nil)
- (repeat :tag "Node types" string))
- :group 'indent-bars)
-
-(defcustom indent-bars-no-descend-string 'string
- "Configure bar behavior inside strings.
-If non-nil, set to a symbol naming a tree-sitter string node type
-into which bars will go no deeper than their starting line. If
-this node type is invalid, a message is printed and the feature
-is disabled."
- :local t
- :type '(choice (const :tag "Disable" nil) (symbol :tag "Node Type"))
- :group 'indent-bars)
-
;;;; Colors
(defvar indent-bars--main-color nil)
(defvar indent-bars--depth-palette nil)
@@ -632,6 +596,26 @@ Note that the first bar is expected at
`indent-bars-starting-column'."
((> len 0) 1)
(t 0)))
+(defvar indent-bars--update-depth-function nil)
+(defun indent-bars--current-indentation-depth (&optional on-bar)
+ "Calculate current indentation depth.
+If ON-BAR is non-nil, report a line with content beginning on a
+bar position at that position. If treesit support is enabled,
+searches for parent nodes with types specified in
+`indent-bars-treesit-wrap' for the current buffer's language,
+and, if found, limits the indentation depth to one more than the
+topmost matching parent node's initial line's indentation depth.
+If `indent-bars-no-descend-string' is non-nil, also look for
+enclosing string and mark indent depth no deeper than one more
+than the starting line's depth."
+ (let* ((c (current-indentation))
+ (d (indent-bars--depth c)))
+ (if indent-bars--update-depth-function
+ (setq d (funcall indent-bars--update-depth-function d)))
+ (if (and on-bar (= c (+ indent-bars--offset (* d indent-bars-spacing))))
+ (1+ d) d)))
+
+
(defun indent-bars--blank-string (off nbars bar-from &optional width)
"Return a blank string with bars displayed.
OFF is character offset for the first bar, NBARS is the desired
@@ -848,75 +832,6 @@ see `indent-bars-prefer-character')."
(propertize (string indent-bars-no-stipple-char)
'face (indent-bars--face d))))))))
-;;;; Tree-sitter
-(defvar-local indent-bars--ts-parser nil)
-(defvar-local indent-bars--ts-query nil)
-(defvar-local indent-bars--ts-string-query nil)
-
-(defun indent-bars--ts-node-query (node query &optional start-only
first-spanning)
- "Capture node(s) spanning NODE matching QUERY.
-QUERY is a compiled treesit query. If START-ONLY is non-nil, the
-query searches for matching nodes spanning the start of the node
-at point. If FIRST-SPANNING is non-nil, return the first
-matching node, but only if it fully spans the start and end range
-of NODE."
- (let* ((start (treesit-node-start node))
- (end (if start-only start (treesit-node-end node)))
- (nodes (treesit-query-capture indent-bars--ts-parser query
- start end t)))
- (when (and first-spanning nodes)
- (let ((n (car nodes)))
- (setq nodes
- (and (<= (treesit-node-start n) start)
- (>= (treesit-node-end n) end)
- n))))
- nodes))
-
-(defsubst indent-bars--indent-at-node (node)
- "Return the current indentation at the start of NODE."
- (save-excursion
- (goto-char (treesit-node-start node))
- (current-indentation)))
-
-(defun indent-bars--current-indentation-depth (&optional on-bar)
- "Calculate current indentation depth.
-If ON-BAR is non-nil, report a line with content beginning on a
-bar position at that position. If treesit support is enabled,
-searches for parent nodes with types specified in
-`indent-bars-treesit-wrap' for the current buffer's language,
-and, if found, limits the indentation depth to one more than the
-topmost matching parent node's initial line's indentation depth.
-If `indent-bars-no-descend-string' is non-nil, also look for
-enclosing string and mark indent depth no deeper than one more
-than the starting line's depth."
- (let* ((c (current-indentation))
- (d (indent-bars--depth c))
- (p (point))
- (dnew (when-let ((indent-bars--ts-query)
- ((/= p (point-min)))
- (node (treesit-node-on (1- p) p
indent-bars--ts-parser)))
- (if (and indent-bars-no-descend-string
- (indent-bars--ts-node-query
- node indent-bars--ts-string-query t))
- (1+ (indent-bars--depth (indent-bars--indent-at-node
node)))
- (when-let ((ctx (indent-bars--ts-node-query
- node indent-bars--ts-query nil t)))
- (1+ (indent-bars--depth
- (indent-bars--indent-at-node ctx))))))))
- (if dnew (setq d (min dnew d)))
- (if (and on-bar (= c (+ indent-bars--offset (* d indent-bars-spacing))))
- (1+ d) d)))
-
-(defun indent-bars--ignore-blank (beg)
- "See if blank lines at BEG should be ignored using tree-sitter.
-Blank lines to ignore are those with types in
-`indent-bars-treesit-ignore-blank-lines-types'."
- (and indent-bars--ts-parser
- indent-bars-treesit-ignore-blank-lines-types
- (when-let ((n (treesit-node-on beg beg)))
- (seq-contains-p indent-bars-treesit-ignore-blank-lines-types
- (treesit-node-type n)))))
-
;;;; Font Lock
(defvar-local indent-bars--font-lock-keywords nil)
(defvar indent-bars--font-lock-blank-line-keywords nil)
@@ -948,18 +863,14 @@ the surrounding line indentation to determine additional
bars to
display on each line, using `indent-bars--draw-line'.
Note: blank lines at the very beginning or end of the buffer are
-not indicated, even if otherwise they would be. If
-`indent-bars-treesit-ignore-blank-lines-types' is configured,
-ignore blank lines whose starting positions are directly spanned
-by nodes of those types (e.g. module)."
+not indicated, even if they otherwise would be."
(let* ((beg (match-beginning 0))
(end (match-end 0))
ctxbars)
(save-excursion
(goto-char (1- beg))
(beginning-of-line 1)
- (when (and (not (indent-bars--ignore-blank beg))
- (> (setq ctxbars (indent-bars--context-bars end)) 0))
+ (when (> (setq ctxbars (indent-bars--context-bars end)) 0)
(goto-char beg)
(while (< (point) end) ;note: end extends 1 char beyond blank line range
(let* ((bp (line-beginning-position))
@@ -1176,28 +1087,6 @@ Adapted from `highlight-indentation-mode'."
;; Window state: selection/size
(add-hook 'window-state-change-functions #'indent-bars--window-change nil t)
- ;; Treesitter
- (when-let (((and indent-bars-treesit-support
- (fboundp #'treesit-available-p)
- (treesit-available-p)))
- (lang (treesit-language-at (point-min)))
- (types (alist-get lang indent-bars-treesit-wrap)))
- (setq indent-bars--ts-parser
- (cl-find lang (treesit-parser-list) :key #'treesit-parser-language)
- indent-bars--ts-query
- (treesit-query-compile lang `([,@(mapcar #'list types)] @ctx)))
- (when indent-bars-no-descend-string
- (let ((query `([(,indent-bars-no-descend-string)] @s))
- (pm (point-min)))
- (setq indent-bars--ts-string-query (treesit-query-compile lang query))
- ;; Test it to be sure
- (condition-case err
- (treesit-query-capture indent-bars--ts-parser
- indent-bars--ts-string-query pm pm t)
- (treesit-query-error
- (setq indent-bars-no-descend-string nil)
- (message "indent-bars: malformed string query; disabling. See
indent-bars-no-descend-string.\n%s" err))))))
-
;; Current depth highlight
(when indent-bars-highlight-current-depth
(indent-bars--set-current-bg-color)
@@ -1211,6 +1100,9 @@ Adapted from `highlight-indentation-mode'."
(add-hook 'text-scale-mode-hook #'indent-bars--resize-stipple nil t)
(indent-bars--resize-stipple) ; just in case
+ ;; Treesitter
+ (if indent-bars-treesit-support (indent-bars-ts-setup))
+
;; Font-lock
(indent-bars--setup-font-lock)
(font-lock-flush))
- [elpa] externals/indent-bars 7957d7a2d3 135/431: draw-line: handle 1 bar case correctly, (continued)
- [elpa] externals/indent-bars 7957d7a2d3 135/431: draw-line: handle 1 bar case correctly, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars bb857e344f 126/431: Use starting-column instead of a fixed spacing offset, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 3249aafe0d 152/431: Improve whatsnew, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 0638ba1ace 168/431: Customize the font weight of the no-stipple character, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars b0ba6ba4ba 147/431: handle-blank-lines: simplify, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars aa3d09ceff 173/431: Update README.md, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars e2a0274e8b 164/431: Make no-descend-string a local symbol for configuring string type, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars dca608724d 183/431: README: mention new depth highlight timer and config, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars a618015bb5 145/431: Add treesit before/after images, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 581a51d3ae 150/431: README: improve features list and add blank/string treesit config, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars ce7fb0641c 189/431: refactoring treesitter to new file: initial stage,
ELPA Syncer <=
- [elpa] externals/indent-bars 6df95da4b1 157/431: README.md: Use current defaults for first image, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 2d30dc37cc 206/431: indent-bars-ts: comment improvements, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars d5f393ac4c 207/431: Add PCH for scope update, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 29b7bdc8f9 204/431: Return nil from font-lock face expression functions, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars a282e1bbb8 238/431: use BEG+END for drawing rather than match boundaries, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 85fcf55464 210/431: Merge branch 'main' into treesit-scope, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 2a8cf5a2fa 243/431: Major refactor for STYLE stipple face & support, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 13cebfa12f 229/431: Merge pull request #37 from gekoke/gekoke/nixlang-indentation, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 6116ab7468 263/431: Correctly remove remaps from plists, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 1f575f2404 211/431: Remove unused ts--scope-query, ELPA Syncer, 2024/09/16