NAME

Text::Treesitter::Query - represents a set of tree-sitter query patterns

SYNOPSIS

Usually accessed indirectly, via Text::Treesitter.

use Text::Treesitter;

my $ts = Text::Treesitter->new(
   lang_name => "perl",
);

my $query = $ts->load_query_string( "path/to/query.scm" );

...

DESCRIPTION

Instances of this class represent a set of query patterns that can be performed against a node tree. Each pattern describes a shape of nodes in the tree by their type, and assigns certain nodes within that subtree to named captures. This is somewhat analogous to named captures in regexp matches.

Typically an application will load just one of these for the lifetime of its operation; or at least, just one per type of language being parsed and query being performed against it.

Queries are specified in a the form of a string containing a list of patterns expressed in S-expressions. The full format is described in the tree-sitter documentation at https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries

CONSTRUCTOR

new

$query = Text::Treesitter::Query->new( $lang, $src );

Returns a new query instance associated with the given Text::Treesitter::Language instance, by reading query specifications from the given source string.

METHODS

pattern_count

$count = $query->pattern_count;

Returns the number of query patterns defined by the query source.

capture_count

$count = $query->capture_count;

Returns the number of capture names.

string_count

$count = $query->string_count;

Returns the number of string values.

capture_name_for_id

$name = $query->capture_name_for_id( $id );

Returns the name of the capture at the given capture index.

string_value_for_id

$value = $query->string_value_for_id( $id );

Returns the value of a string at the given string index.

predicates_for_pattern

@predicates = $query->predicates_for_pattern( $id );

Returns a list representing the predicates in the query pattern at the given index. Each predicate test will be represented by one arrayref in the returned list. The array will start with a string giving the predicate's name, followed by its arguments. String arguments are stored as strings. Capture arguments are stored as references to integers, giving the capture index.

For example, a query containing the predicate

(#match? @name "[A-Z]+")

Will be represented by a list of one arrayref:

[ "match?", \123, "[A-Z]+" ]

where, in this case, the @name capture had the capture index 123.

test_predicates_for_match

$ok = $query->test_predicates_for_match( $match );

An older form is also accepted:

$ok = $query->test_predicates_for_match( $tree, $match );

The $tree argument is ignored if it is undef or a Text::Treesitter::Tree instance.

Returns true if all the predicate tests in the given query match instance are successful (or if there are no predicates). Returns false if any predicate rejected it.

This method needs the list of captures from the match instance. As it is likely that the caller will need this too, an optional additional arrayref argument can be passed containing it, for efficient reuse and avoiding creating a second copy of the list.

my @captures = $match->captures;
my $ok = $query->test_predicates_for_match( $match, \@captures );

The following predicate functions are recognised. Each also has an inverted variant whose name is preceeded by not- to invert the logic.

eq? / not-eq?

(#eq? @capture "string")
(#eq? @capture1 @capture2)

Accepts if the arguments are exactly the same string.

match? / not-match?

(#match? @capture "RE-PATTERN")

Accepts if the first argument matches the regexp given by the second. Note that the regexp is not anchored and could match anywhere within the capture. To match only the entire capture make sure to use the ^ and $ anchors.

(#match? @name "[A-Z]+")   ; matches any name that contains a capital letter
(#match? @name "^[A-Z]+$") ; matches any name entirely composed of capitals

When writing a query file, remember that although this implementation will use Perl regexps, other highlighters will use their own engine for it. Try not to use any fancy features that are not commonly available (such as look arounds, etc..)

contains? / not-contains?

(#contains? @capture "some" "values")

Accepts if the first argument contains (by an index() test) any of the string values given in the subsequent arguments.

(This predicate is inspired by nvim.)

any-of? / not-any-of?

(#any-of? @capture "some" "values")

Accepts if the first argument is exactly the same as any of the subsequent string values.

(This predicate is inspired by nvim.)

has-parent?

(#has-parent? @capture type names)

Accepts if the immediate parent of first argument (which must be a node capture) has a type that is any of the subsequent type names.

(This predicate is inspired by nvim.)

has-ancestor?

(#has-ancestor? @capture type names)

Accepts if any ancestor of the first argument (which mus be a node capture) has a type that is any of the subsequent type names.

(This predicate is inspired by nvim.)

capture_quantifier_for_id

$quant = $query->capture_quantifier_for_id( $pattern_id, $capture_id );

Since version 0.09.

Returns the quantifier associated with the given capture of the given pattern. This will match one of the following TSQuantifier* constants

TSQuantifierZero
TSQuantifierZeroOrOne
TSQuantifierZeroOrMore
TSQuantifierOne
TSQuantifierOneOrMore

TODO

The following C library functions are currently unhandled:

ts_query_start_byte_for_pattern
ts_query_is_pattern_rooted
ts_query_is_pattern_guaranteed_at_step
ts_query_disable_capture
ts_query_disable_pattern

AUTHOR

Paul Evans <leonerd@leonerd.org.uk>