From 0db75b80e1ce54f3597f7d19468157fd5ec2bd71 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Thu, 9 Nov 2023 20:49:30 -0800 Subject: [PATCH] Add treesit-node-enclosed-p * doc/lispref/parsing.texi (Accessing Node Information): Add manual entry. * lisp/treesit.el (treesit-node-enclosed-p): New function. (treesit): Add shortdoc entry. * test/src/treesit-tests.el (treesit-node-api): Add tests. --- doc/lispref/parsing.texi | 18 +++++++++++++++++- lisp/treesit.el | 40 +++++++++++++++++++++++++++++++++++++-- test/src/treesit-tests.el | 7 +++++++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index bac5a864bf8..df81a805e67 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -705,7 +705,7 @@ This function finds the previous sibling of @var{node}. If To make the syntax tree easier to analyze, many language grammars assign @dfn{field names} to child nodes (@pxref{tree-sitter node field name, field name}). For example, a @code{function_definition} node -could have a @code{declarator} node and a @code{body} node. +could have a @code{declarator} child and a @code{body} child. @defun treesit-node-child-by-field-name node field-name This function finds the child of @var{node} whose field name is @@ -1081,6 +1081,22 @@ This function returns the number of children of @var{node}. If (@pxref{tree-sitter named node, named node}). @end defun +@heading Convenience functions + +@defun treesit-node-enclosed-p smaller larger &optional strict +This function returns non-@code{nil} if @var{smaller} is enclosed in +@var{larger}. @var{smaller} and @var{larger} can be either a cons +@code{(@var{beg} . @var{end})} or a node. + +Return non-@code{nil} if @var{larger}'s start <= @var{smaller}'s start +and @var{larger}'s end <= @var{smaller}'s end. + +If @var{strict} is @code{t}, compare with < rather than <=. + +If @var{strict} is @code{partial}, consider @var{larger} encloses +@var{smaller} when at least one side is strictly enclosing. +@end defun + @node Pattern Matching @section Pattern Matching Tree-sitter Nodes @cindex pattern matching with tree-sitter nodes diff --git a/lisp/treesit.el b/lisp/treesit.el index e1fcf1a8b04..826e719172d 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -439,6 +439,41 @@ unlike in their original functions." (treesit-node-prev-sibling node named))))))) node) +(defun treesit-node-enclosed-p (smaller larger &optional strict) + "Return non-nil if SMALLER is enclosed in LARGER. +SMALLER and LARGER can be either (BEG . END) or a node. + +Return non-nil if LARGER's start <= SMALLER's start and LARGER's +end <= SMALLER's end. + +If STRICT is t, compare with < rather than <=. + +If STRICT is \\='partial, consider LARGER encloses SMALLER when +at least one side is strictly enclosing." + (unless (and (or (consp larger) (treesit-node-p larger)) + (or (consp smaller) (treesit-node-p smaller))) + (signal 'wrong-type-argument '((or cons treesit-node)))) + (let ((larger-start (if (consp larger) + (car larger) + (treesit-node-start larger))) + (larger-end (if (consp larger) + (cdr larger) + (treesit-node-end larger))) + (smaller-start (if (consp smaller) + (car smaller) + (treesit-node-start smaller))) + (smaller-end (if (consp smaller) + (cdr smaller) + (treesit-node-end smaller)))) + (pcase strict + ('t (and (< larger-start smaller-start) + (< smaller-end larger-end))) + ('partial (and (or (not (eq larger-start smaller-start)) + (not (eq larger-end smaller-end))) + (<= larger-start smaller-start + smaller-end larger-end))) + (_ (<= larger-start smaller-start smaller-end larger-end))))) + ;;; Query API supplement (defun treesit-query-string (string query language) @@ -3523,7 +3558,6 @@ function signals an error." (define-short-documentation-group treesit - "Parsers" (treesit-parser-create :no-eval (treesit-parser-create 'c) @@ -3669,7 +3703,9 @@ function signals an error." (treesit-node-check :no-eval (treesit-node-check node 'named) :eg-result t) - + (treesit-node-enclosed-p + :no-eval (treesit-node-enclosed-p node1 node2) + :no-eval (treesit-node-enclosed-p node1 '(12 . 18))) (treesit-node-field-name-for-child :no-eval (treesit-node-field-name-for-child node) diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el index 4308e4048f6..791e902bd0a 100644 --- a/test/src/treesit-tests.el +++ b/test/src/treesit-tests.el @@ -166,6 +166,13 @@ ;; `treesit-node-eq'. (should (treesit-node-eq root-node root-node)) (should (not (treesit-node-eq root-node doc-node))) + ;; `treesit-node-enclosed-p' + (should (treesit-node-enclosed-p '(1 . 3) '(1 . 4))) + (should (treesit-node-enclosed-p '(1 . 3) '(1 . 3))) + (should (not (treesit-node-enclosed-p '(1 . 3) '(1 . 4) t))) + (should (treesit-node-enclosed-p '(1 . 3) '(1 . 4) 'partial)) + (should (treesit-node-enclosed-p '(2 . 3) '(1 . 4) t)) + (should (treesit-node-enclosed-p object-node root-node)) ;; Further test for `treesit-node-check'. (treesit-parser-delete parser) -- 2.39.2