[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/indent-bars 77aec85ad0 124/431: Merge branch 'treesit'
From: |
ELPA Syncer |
Subject: |
[elpa] externals/indent-bars 77aec85ad0 124/431: Merge branch 'treesit' into dev |
Date: |
Mon, 16 Sep 2024 12:59:20 -0400 (EDT) |
branch: externals/indent-bars
commit 77aec85ad0f056a65fa940dd3c7625417e62d803
Merge: 568ec43b0e 44d7d633fc
Author: JD Smith <93749+jdtsmith@users.noreply.github.com>
Commit: JD Smith <93749+jdtsmith@users.noreply.github.com>
Merge branch 'treesit' into dev
---
README.md | 26 ++++++++++
indent-bars.el | 156 +++++++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 160 insertions(+), 22 deletions(-)
diff --git a/README.md b/README.md
index 66a864b489..cac39b74a1 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ This package provides vertical indentation _guide bars_, with
the following feat
- Properly handles font size changes.
- Optional zero-cost current-depth bar highlighting, permitting bar color
and/or appearance changes.
- Optional support for drawing bars on blank lines.
+- Optional tree-sitter support, for context-aware bar depth.
# FAQ's
@@ -46,6 +47,21 @@ To clone with `use-package` and `straight`:
:hook ((python-mode yaml-mode) . indent-bars-mode)) ; or whichever modes you
prefer
```
+## With tree-sitter support
+
+```elisp
+(use-package indent-bars
+ :load-path "~/code/emacs/indent-bars"
+ :custom
+
+ (indent-bars-treesit-support t)
+ (indent-bars-treesit-wrap '((python argument_list parameters
+ list list_comprehension
+ dictionary dictionary_comprehension
+ parenthesized_expression subscript)))
+ :hook ((python-base-mode yaml-mode) . indent-bars-mode))
+```
+
## Compatibility
For `indent-bars` to display fancy guide bars, your port and version of emacs
must correctly display the `:stipple` face attribute. **Most do.** It can
also be used *without stipples*, drawing a simple vertical character (like `│`)
instead. It automatically does this in non-graphical displays (terminals), but
can optionally be configured to always do so; see [Non-stipple
Display](#non-stipple-display).
@@ -83,6 +99,10 @@ The main customization variables:
- `indent-bars-prefer-character`: Use *characters* to display the vertical bar
instead of stipples. This occurs automatically on non-graphical displays
(terminals), but this variable can be used to always prefer character-based
display.
- `indent-bars-no-stipple-char`: The character to use when stipples are
unavailable or disabled. Defaults to the vertical box character `│`. Other
good options include `┃`, `┋`, and `║`.
- `indent-bars-unspecified-bg|fg-color`: Colors to use for the frame
background and default foreground when unspecified (e.g. in terminals). If you
intend to use `indent-bars` in the terminal, set to the terminal
background/foreground colors you use.
+- `indent-bars-treesit-support`: Whether to use tree-sitter (if available) to
help determine appropriate bar depth.
+- `indent-bars-treesit-wrap`: A mapping of language and wrap types, to avoid
adding extra bars (e.g. in wrapped function arguments).
+- `indent-bars-treesit-ignore-blank-lines-types`: A list of tree-sitter node
types to inhibit styling blank lines, like "module".
+- `indent-bars-no-descend-string`: Whether to inhibit increasing depth inside
of (tree-sitter determined) strings.
See the documentation of each variable for more details.
@@ -98,6 +118,12 @@ The heaviest operation (though still fairly efficient) is
**blank-line highlight
`indent-bars` only works with space-based indentation, i.e.
`indent-tabs-mode=nil`. Note that many modes enable this by default.
+## Tree-sitter
+
+`indent-bars` can optionally use tree-sitter when configured in supported
files to improve the calculation of bar depth. For example, many modes wrap
function definitions to align parameters with the opening `(`. With the help
of tree-sitter, `indent-bars` can avoid adding unwanted additional bars there.
It also can be used to identify strings, and to tweak the behavior of blank
line display. See options above.
+
+**Note**: This requires Emacs 29 built with tree-sitter support, and the
appropriate tree-sitter grammars installed for languages of interest.
+
## Display
### Stipples
diff --git a/indent-bars.el b/indent-bars.el
index 7e150e638c..907d5c3940 100644
--- a/indent-bars.el
+++ b/indent-bars.el
@@ -42,6 +42,7 @@
(require 'outline)
(require 'font-lock)
(require 'compat)
+(require 'treesit nil t)
;;;; Customization
(defgroup indent-bars nil
@@ -343,6 +344,45 @@ 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 t
+ "Configure bar behavior inside strings.
+If non-nil, bars will go no deeper than their starting line
+inside multi-line strings. Strings are identified with
+tree-sitter; see `indent-bars-ts-string-type'."
+ :type 'boolean
+ :group 'indent-bars)
+
;;;; Colors
(defvar indent-bars--main-color nil)
(defvar indent-bars--depth-palette nil)
@@ -685,11 +725,58 @@ returned."
(defun indent-bars--display ()
"Display indentation bars based on line contents."
(save-excursion
- (goto-char (match-beginning 1))
- (indent-bars--draw (+ (line-beginning-position) indent-bars-spacing)
(match-end 1) nil nil
- (or (not (display-graphic-p))
indent-bars-prefer-character)))
+ (goto-char (match-end 1))
+ (let ((d (indent-bars--current-indentation-depth))
+ (b (match-beginning 1)))
+ (if (> d 0)
+ (indent-bars--draw (+ b indent-bars-spacing)
+ (+ b (* d indent-bars-spacing)) nil nil
+ (or (not (display-graphic-p))
indent-bars-prefer-character)))))
nil)
+;;;; Tree-sitter
+(defvar-local indent-bars-ts-string-type 'string)
+
+(defvar-local indent-bars--ts-parser nil)
+(defvar-local indent-bars--ts-query nil)
+(defvar-local indent-bars--ts-string-query nil)
+
+(defsubst indent-bars--ts-node-query (node query)
+ "Capture node(s) spanning NODE matching QUERY.
+QUERY is a compiled treesit query."
+ (treesit-query-capture
+ indent-bars--ts-parser query
+ (treesit-node-start node) (treesit-node-end node) t))
+
+(defsubst indent-bars--indent-at-node (node)
+ "Return the current indentation at the start of NODE.
+Moves point."
+ (goto-char (treesit-node-start node))
+ (current-indentation))
+
+(defun indent-bars--current-indentation-depth ()
+ "Calculate current indentation depth.
+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. May move
+point."
+ (let* ((d (/ (current-indentation) indent-bars-spacing))
+ (p (point)))
+ (or
+ (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))
+ (min d (1+ (/ (indent-bars--indent-at-node node)
indent-bars-spacing)))
+ (when-let ((ctx (indent-bars--ts-node-query node
indent-bars--ts-query)))
+ (min d (1+ (/ (indent-bars--indent-at-node (car ctx))
indent-bars-spacing))))))
+ d)))
+
;;;; No stipple (e.g. terminal)
(defvar indent-bars--no-stipple-chars nil)
;; (defvar indent-bars--no-stipple-current-depth-char nil)
@@ -758,30 +845,40 @@ display on each line, and applies a string display
property on
the final newline if necessary to display the needed bars.
Note: blank lines at the beginning or end of the buffer are not
-indicated, even if otherwise they would be."
+indicated, even if otherwise they would be. If
+`indent-bars-treesit-ignore-blank-lines-types' is configured,
+ignore blank lines whose starting positions are spanned by nodes
+of those types (e.g. module)."
(let* ((beg (match-beginning 0))
(end (match-end 0))
(no-stipple (or indent-bars-prefer-character (not
(display-graphic-p))))
ctxbars)
(when (and (/= end (point-max)) (/= beg (point-min)))
(save-excursion
- (goto-char (1- beg)) ;beg is always bol
- (when (> (setq ctxbars
- (1- (max (/ (current-indentation) indent-bars-spacing)
- (progn
- (goto-char (1+ end)) ; end is always eol
- (/ (current-indentation)
indent-bars-spacing)))))
- 0)
+ (goto-char (1- beg))
+ (beginning-of-line 1)
+ (when (and
+ (not
+ (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)))))
+ (> (setq ctxbars
+ (1- (max (indent-bars--current-indentation-depth)
+ (progn
+ (goto-char (1+ end)) ; end is always eol
+ (indent-bars--current-indentation-depth)))))
+ 0))
(goto-char beg)
- (while (<= (point) (1- end)) ;note: end extends 1 char beyond blank
line range
+ (while (<= (point) (1- end)) ;note: end extends 1 char beyond blank
line range
(let* ((bp (line-beginning-position))
(ep (line-end-position))
(len (- ep bp))
(nbars (/ (max 0 (1- len)) indent-bars-spacing)))
- ;; Draw "real" bars in existing blank
+ ;; Draw "real" bars in existing blank text
(if (> nbars 0) (indent-bars--draw (+ bp indent-bars-spacing)
ep nil nil no-stipple))
- ;; Add fake bars via display
+ ;; Add fake bars, via display
(when (> ctxbars nbars)
(let* ((off (- (* (1+ nbars) indent-bars-spacing) len))
(s (if no-stipple
@@ -822,8 +919,8 @@ ROT are as in `indent-bars--stipple', and have similar
default values."
(defun indent-bars--highlight-current-depth ()
"Refresh current indentation depth highlight.
Works by remapping the appropriate indent-bars-N face."
- (let ((depth (/ (current-indentation) indent-bars-spacing)))
- (when (not (= depth indent-bars--current-depth))
+ (let ((depth (save-excursion (indent-bars--current-indentation-depth))))
+ (when (and depth (not (= depth indent-bars--current-depth)))
(if indent-bars--remap-face ; out with the old
(face-remap-remove-relative indent-bars--remap-face))
(setq indent-bars--current-depth depth)
@@ -960,17 +1057,31 @@ Adapted from `highlight-indentation-mode'."
;; Window state: selection/size
(add-hook 'window-state-change-functions #'indent-bars--window-change nil t)
- ;; Font-lock
- (indent-bars--setup-font-lock)
- (font-lock-flush)
-
+ ;; 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
+ (setq indent-bars--ts-string-query
+ (treesit-query-compile lang `([(,indent-bars-ts-string-type)]
@s)))))
+
;; Current depth highlight
(when indent-bars-highlight-current-depth
(indent-bars--set-current-bg-color)
(indent-bars--set-current-depth-stipple)
(add-hook 'post-command-hook #'indent-bars--highlight-current-depth nil t)
(setq indent-bars--current-depth 0)
- (indent-bars--highlight-current-depth)))
+ (indent-bars--highlight-current-depth))
+
+ ;; Font-lock
+ (indent-bars--setup-font-lock)
+ (font-lock-flush))
(defun indent-bars-teardown ()
"Tears down indent-bars."
@@ -991,7 +1102,8 @@ Adapted from `highlight-indentation-mode'."
indent-bars--current-depth-stipple nil
indent-bars--no-stipple-chars nil
indent-bars--current-bg-color nil
- indent-bars--current-depth 0)
+ indent-bars--current-depth 0
+ indent-bars--ts-query nil)
(remove-hook 'text-scale-mode-hook #'indent-bars--resize-stipple t)
(remove-hook 'post-command-hook #'indent-bars--highlight-current-depth t)
(remove-hook 'font-lock-extend-region-functions
- [elpa] externals/indent-bars 169b85f092 068/431: README: update stipple test, (continued)
- [elpa] externals/indent-bars 169b85f092 068/431: README: update stipple test, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 759a80e5cf 082/431: Bump version, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 9935c0f9a2 105/431: teardown no-stipple-chars, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 01583822ab 095/431: New example image, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 6f0f2bf5ce 092/431: Update README.md, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 55d8ef1711 096/431: Update README.md, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 180b6ab95c 053/431: Mention stipple compatibility, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 5eb33cc94f 085/431: Update README.md, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 7da1a4a2a4 107/431: Update examples.md, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 54d15a437d 122/431: customize and var name tweaks, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 77aec85ad0 124/431: Merge branch 'treesit' into dev,
ELPA Syncer <=
- [elpa] externals/indent-bars a7bfe31d59 131/431: display-line: offset start if no tabs, invent with correct bar count, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars f1404b31fe 151/431: Added what's new, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 3a9ffd9176 142/431: Add cobol-mode support, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 327ace5493 162/431: ts-node-query: add FIRST-SPANNING flag to insist top node encloses, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 858de2c124 184/431: Update README.md, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 8a4ea0ab83 187/431: Update README.md, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 3cebc7d7fb 177/431: Resize iamge, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars beaaf4d359 003/431: Improve docstrings, comments, custom messages, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 6d98c4597f 004/431: re-organize and cleanup, ELPA Syncer, 2024/09/16
- [elpa] externals/indent-bars 6f054692ef 008/431: Generalize to stipple "pad" and "rot", ELPA Syncer, 2024/09/16