[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Tree-sitter api
From: |
Stefan Monnier |
Subject: |
Re: Tree-sitter api |
Date: |
Tue, 24 Aug 2021 20:21:39 -0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) |
> Okay, here is the (ad-hoc) infrastructure I came up with:
It's more than what I proposed, but it looks fairly good.
See patch below which is the "side effect" of reading your code.
You'll see that I removed the "-function" from the function name (this
suffix is used for variables holding functions rather than for the
function themselves) and I split that function into two, the outer one
(tree-sitter-indent) implementing basically what I suggested and the
inner one (tree-sitter-simple-indent) implementing the extra structure
you added to it, mediated by a new var `tree-sitter-indent-function`
which modes can set if they want to use another algorithm than the one
you implemented in `tree-sitter-simple-indent`.
The reason why I divided it this way is that my experience with
indentation code is that it can be useful occasionally to call
recursively the indentation code to know where a node *would* be
indented. This comes in handy when you want to be able to provide
indentation styles like:
let myvariable = if (foo) {
bar
} else {
baz
}
where the body of the `if` branches needs to be indented relative to the
position where the `if` itself would be indented if it were on its own line.
Stefan
PS: The patch also adds some space before open-paren-in-column-0-in-strings
to circumvent some problems with outline-minor-mode incorrectly thinking
those open-parens correspond to actual top-level definitions :-(
diff --git a/lisp/tree-sitter.el b/lisp/tree-sitter.el
index 83aa2d0d123..2c5d103c42d 100644
--- a/lisp/tree-sitter.el
+++ b/lisp/tree-sitter.el
@@ -52,6 +52,8 @@ tree-sitter-should-enable-p
;;; Parser API supplement
+(defvar tree-sitter-parser-list)
+
(defun tree-sitter-get-parser (language)
"Find the first parser using LANGUAGE in `tree-sitter-parser-list'."
(catch 'found
@@ -196,7 +198,7 @@ tree-sitter-simple-indent-rules
"A list of indent rule settings.
Each indent rule setting should be (LANGUAGE . RULES),
where LANGUAGE is a language symbol, and RULES is a list of
-(MATCHER ANCHOR OFFSET).
+ (MATCHER ANCHOR OFFSET).
MATCHER determines whether this rule applies, ANCHOR and OFFSET
together determines which column to indent to.
@@ -289,7 +291,7 @@ tree-sitter-simple-indent-presets
MATCHER:
-(match NODE-TYPE PARENT-TYPE NODE-FIELD NODE-INDEX-MIN NODE-INDEX-MAX)
+ (match NODE-TYPE PARENT-TYPE NODE-FIELD NODE-INDEX-MIN NODE-INDEX-MAX)
NODE-TYPE checks for node's type, PARENT-TYPE check for
parent's type, NODE-FIELD checks for the filed name of node
@@ -304,25 +306,25 @@ tree-sitter-simple-indent-presets
that starts at point. This is the case when indenting an
empty line.
-(node-at-point TYPE NAMED)
+ (node-at-point TYPE NAMED)
Check that the node at point -- not the largest node at
point, has type TYPE. If NAMED non-nil, check the named node
at point.
-(parent-is TYPE)
+ (parent-is TYPE)
Check that the parent has type TYPE.
-(node-is TYPE)
+ (node-is TYPE)
Checks that the node has type TYPE.
-(parent-match PATTERN)
+ (parent-match PATTERN)
Checks that the parent matches PATTERN, a query pattern.
-(node-match PATTERN)
+ (node-match PATTERN)
Checks that the node matches PATTERN, a query pattern.
@@ -356,7 +358,7 @@ tree-sitter--simple-apply
If FN is a key in `tree-sitter-simple-indent-presets', use the
corresponding value as the function."
- (cond ((consp fn)
+ (cond ((consp fn) ;FIXME: This will mis-match for non-compiled lambdas!
(apply (tree-sitter--simple-apply (car fn) (cdr fn))
args))
((and (symbolp fn)
@@ -366,21 +368,46 @@ tree-sitter--simple-apply
((functionp fn) (apply fn args))
(t (error "Couldn't find appropriate function for FN"))))
-(defun tree-sitter-simple-indent-function ()
+(defvar tree-sitter-indent-function #'tree-sitter-simple-indent
+ "Document.")
+
+(defun tree-sitter-indent ()
"Indent according to `tree-sitter-simple-indent-rules'."
- (let* ((orig-pos (point))
- (bol (save-excursion
+ (pcase-let*
+ ((orig-pos (point))
+ (bol (save-excursion
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (point)))
+ (node (tree-sitter-parent-while
+ (cl-loop for parser in tree-sitter-parser-list
+ for node = (tree-sitter-node-at
+ bol nil parser)
+ if node return node)
+ (lambda (node)
+ (eq bol (tree-sitter-node-start node)))))
+ (parent (tree-sitter-node-parent node))
+ (`(,anchor . ,offset)
+ (funcall tree-sitter-indent-function node parent)))
+ (let ((col (+ (save-excursion
+ (goto-char anchor)
+ (current-column))
+ offset)))
+ (if (< bol orig-pos)
+ (save-excursion
+ (indent-line-to col))
+ (indent-line-to col))
+ (when tree-sitter--indent-verbose
+ (message "indent to %S (%S position + %S)"
+ col anchor offset)))))
+
+(defun tree-sitter-simple-indent (node parent)
+ (let* ((bol (save-excursion
(beginning-of-line)
(skip-chars-forward " \t")
(point)))
- (node (tree-sitter-parent-while
- (cl-loop for parser in tree-sitter-parser-list
- for node = (tree-sitter-node-at
- bol nil parser)
- if node return node)
- (lambda (node)
- (eq bol (tree-sitter-node-start node)))))
- (parent (tree-sitter-node-parent node))
+ ;; FIXME: Can't we get the language from `node' rather than
+ ;; from `point'?
(language (tree-sitter-language-at (point)))
(rules (alist-get language tree-sitter-simple-indent-rules)))
(cl-loop for rule in rules
@@ -388,20 +415,9 @@ tree-sitter-simple-indent-function
for anchor = (nth 1 rule)
for offset = (nth 2 rule)
if (tree-sitter--simple-apply pred (list node parent bol))
- do (let ((col (+ (save-excursion
- (goto-char
- (tree-sitter--simple-apply
- anchor (list node parent bol)))
- (current-column))
- offset)))
- (if (< bol orig-pos)
- (save-excursion
- (indent-line-to col))
- (indent-line-to col))
- (when tree-sitter--indent-verbose
- (message "matched %S\nindent to %s"
- pred col)))
- and return nil)))
+ do `(,(tree-sitter--simple-apply
+ anchor (list node parent bol))
+ . ,offset))))
;;; Lab
@@ -435,7 +451,7 @@ ts-c-mode
(ignore t nil nil nil)
indent-line-function
- #'tree-sitter-simple-indent-function
+ #'tree-sitter-indent
tree-sitter-simple-indent-rules
ts-c-tree-sitter-indent-rules)
- Re: Tree-sitter api, (continued)
- Re: Tree-sitter api, Yuan Fu, 2021/08/23
- Re: [SPAM UNSURE] Re: Tree-sitter api, Stephen Leake, 2021/08/24
- Re: [SPAM UNSURE] Tree-sitter api, Yuan Fu, 2021/08/27
- Re: Tree-sitter api, Stefan Monnier, 2021/08/24
- Re: Tree-sitter api, Yuan Fu, 2021/08/21
- Re: Tree-sitter api, Yuan Fu, 2021/08/21
- Re: Tree-sitter api, Eli Zaretskii, 2021/08/22
- Re: Tree-sitter api, Eli Zaretskii, 2021/08/22
- Re: Tree-sitter api,
Stefan Monnier <=
- Re: Tree-sitter api, Yuan Fu, 2021/08/27
- Re: Tree-sitter api, Yuan Fu, 2021/08/08
- Re: Tree-sitter api, Stefan Monnier, 2021/08/08
- Re: Tree-sitter api, Yuan Fu, 2021/08/08