///|
priv type TSQueryCursor
///|
struct QueryCursor {
cursor : TSQueryCursor
mut query : Query
mut tree : Tree
}
///|
extern "c" fn ts_query_cursor_new() -> TSQueryCursor = "moonbit_ts_query_cursor_new"
///|
/// Create a new cursor for executing a given query.
///
/// The cursor stores the state that is needed to iteratively search
/// for matches. To use the query cursor, first call QueryCursor::exec
/// to start running a given query on a given syntax node. Then, there are
/// two options for consuming the results of the query:
/// 1. Repeatedly call QueryCursor::next_match to iterate over all of the
/// *matches* in the order that they were found. Each match contains the
/// index of the pattern that matched, and an array of captures. Because
/// multiple patterns can match the same set of nodes, one match may contain
/// captures that appear *before* some of the captures from a previous match.
/// 2. Repeatedly call QueryCursor::next_capture to iterate over all of the
/// individual *captures* in the order that they appear. This is useful if
/// don't care about which pattern matched, and just want a single ordered
/// sequence of captures.
///
/// If you don't care about consuming all of the results, you can stop calling
/// QueryCursor::next_match or QueryCursor::next_capture at any point.
/// You can then start executing another query on another node by calling
/// QueryCursor::exec again.
pub fn QueryCursor::new() -> QueryCursor {
let cursor = ts_query_cursor_new()
let cursor = QueryCursor::{
cursor,
query: Query::null(),
tree: ts_tree_null(),
}
cursor
}
///|
#borrow(self, query, node, tree)
extern "c" fn ts_query_cursor_exec(
self : TSQueryCursor,
query : Query,
node : TSNode,
tree : Tree
) = "moonbit_ts_query_cursor_exec"
///|
// @move progress_callback
#borrow(self, query, node, tree)
extern "c" fn ts_query_cursor_exec_with_options(
self : TSQueryCursor,
query : Query,
node : TSNode,
tree : Tree,
progress_callback : (UInt) -> Unit
) = "moonbit_ts_query_cursor_exec_with_options"
///|
pub struct QueryCursorState {
current_byte_offset : Int
}
///|
pub(all) struct QueryCursorOptions {
progress_callback : (QueryCursorState) -> Unit
}
///|
/// Start running a given query on a given node, with optional options.
pub fn QueryCursor::exec(
self : QueryCursor,
query : Query,
node : Node,
options? : QueryCursorOptions
) -> Unit {
match options {
None => ts_query_cursor_exec(self.cursor, query, node.node, node.tree)
Some(options) =>
ts_query_cursor_exec_with_options(
self.cursor,
query,
node.node,
node.tree,
fn(current_byte_offset) {
let current_byte_offset = uint_to_int(current_byte_offset)
(options.progress_callback)(QueryCursorState::{ current_byte_offset, })
},
)
}
self.query = query
self.tree = node.tree
}
///|
#borrow(self)
extern "c" fn ts_query_cursor_did_exceed_match_limit(
self : TSQueryCursor
) -> Bool = "moonbit_ts_query_cursor_did_exceed_match_limit"
///|
/// Check if the query cursor exceeded its match limit.
///
/// Query cursors have an optional maximum capacity for storing lists of
/// in-progress captures. If this capacity is exceeded, then the
/// earliest-starting match will silently be dropped to make room for further
/// matches. This maximum capacity is optional — by default, query cursors allow
/// any number of pending matches, dynamically allocating new space for them as
/// needed as the query is executed.
pub fn QueryCursor::did_exceed_match_limit(self : QueryCursor) -> Bool {
ts_query_cursor_did_exceed_match_limit(self.cursor)
}
///|
#borrow(self)
extern "c" fn ts_query_cursor_match_limit(self : TSQueryCursor) -> UInt = "moonbit_ts_query_cursor_match_limit"
///|
/// Get the maximum number of in-progress matches allowed by this query cursor.
///
/// See `QueryCursor::did_exceed_match_limit`.
pub fn QueryCursor::match_limit(self : QueryCursor) -> Int {
ts_query_cursor_match_limit(self.cursor) |> uint_to_int()
}
///|
#borrow(self)
extern "c" fn ts_query_cursor_set_match_limit(
self : TSQueryCursor,
limit : UInt
) = "moonbit_ts_query_cursor_set_match_limit"
///|
/// Set the maximum number of in-progress matches allowed by this query cursor.
///
/// See `QueryCursor::did_exceed_match_limit`.
pub fn QueryCursor::set_match_limit(self : QueryCursor, limit : Int) -> Unit {
ts_query_cursor_set_match_limit(self.cursor, int_to_uint(limit))
}
///|
#borrow(self)
extern "c" fn ts_query_cursor_set_byte_range(
self : TSQueryCursor,
start_byte : UInt,
end_byte : UInt
) = "moonbit_ts_query_cursor_set_byte_range"
///|
/// Set the range of bytes in which the query will be executed.
///
/// The query cursor will return matches that intersect with the given byte range.
/// This means that a match may be returned even if some of its captures fall
/// outside the specified range, as long as at least part of the match
/// overlaps with the range.
pub fn QueryCursor::set_byte_range(
self : QueryCursor,
start_byte : Int,
end_byte : Int
) -> Unit {
ts_query_cursor_set_byte_range(
self.cursor,
int_to_uint(start_byte),
int_to_uint(end_byte),
)
}
///|
#borrow(self, start_point, end_point)
extern "c" fn ts_query_cursor_set_point_range(
self : TSQueryCursor,
start_point : Point,
end_point : Point
) = "moonbit_ts_query_cursor_set_point_range"
///|
/// Set the range of (row, column) positions in which the query will be executed.
///
/// The query cursor will return matches that intersect with the given point range.
/// This means that a match may be returned even if some of its captures fall
/// outside the specified range, as long as at least part of the match
/// overlaps with the range.
pub fn QueryCursor::set_point_range(
self : QueryCursor,
start_point : Point,
end_point : Point
) -> Unit {
ts_query_cursor_set_point_range(self.cursor, start_point, end_point)
}
///|
#visibility(change_to="abstract", "Please use accessor functions instead")
pub struct QueryCapture {
node : Node
index : Int
} derive(Show, ToJson)
///|
pub fn QueryCapture::node(self : QueryCapture) -> Node {
self.node
}
///|
pub fn QueryCapture::index(self : QueryCapture) -> Int {
self.index
}
///|
#visibility(change_to="abstract", "Please use accessor functions instead")
pub struct QueryMatch {
id : Int
pattern_index : Int
captures : FixedArray[QueryCapture]
} derive(Show, ToJson)
///|
pub fn QueryMatch::id(self : QueryMatch) -> Int {
self.id
}
///|
pub fn QueryMatch::pattern_index(self : QueryMatch) -> Int {
self.pattern_index
}
///|
pub fn QueryMatch::captures(self : QueryMatch) -> Iter[QueryCapture] {
self.captures.iter()
}
///|
priv type TSQueryMatch
///|
#borrow(self)
extern "c" fn ts_query_match_is_null(self : TSQueryMatch) -> Bool = "moonbit_c_is_null"
///|
impl Nullable for TSQueryMatch with is_null(self : TSQueryMatch) -> Bool {
return ts_query_match_is_null(self)
}
///|
#borrow(self)
extern "c" fn ts_query_match_id(self : TSQueryMatch) -> UInt = "moonbit_ts_query_match_id"
///|
#borrow(self)
extern "c" fn ts_query_match_pattern_index(self : TSQueryMatch) -> UInt = "moonbit_ts_query_match_pattern_index"
///|
#borrow(self)
extern "c" fn ts_query_match_capture_count(self : TSQueryMatch) -> UInt16 = "moonbit_ts_query_match_capture_count"
///|
#borrow(self)
extern "c" fn ts_query_match_captures_get_node(
self : TSQueryMatch,
index : UInt
) -> TSNode = "moonbit_ts_query_match_captures_get_node"
///|
#borrow(self)
extern "c" fn ts_query_match_captures_get_index(
self : TSQueryMatch,
index : UInt
) -> UInt = "moonbit_ts_query_match_captures_get_index"
///|
#borrow(self, query, tree)
extern "c" fn ts_query_cursor_next_match(
self : TSQueryCursor,
query : Query,
tree : Tree
) -> TSQueryMatch = "moonbit_ts_query_cursor_next_match"
///|
/// Advance to the next match of the currently running query.
///
/// If there is a match, returns Some(match).
/// Otherwise, returns None.
pub fn QueryCursor::next_match(self : QueryCursor) -> QueryMatch? {
let ts_match = ts_query_cursor_next_match(self.cursor, self.query, self.tree).to_option()
guard ts_match is Some(ts_match) else { return None }
let capture_count = ts_query_match_capture_count(ts_match)
let captures = FixedArray::makei(capture_count.to_int(), fn(i) {
let i = i.reinterpret_as_uint()
let node = ts_query_match_captures_get_node(ts_match, i)
let index = ts_query_match_captures_get_index(ts_match, i)
let index = uint_to_int(index)
QueryCapture::{ node: { node, tree: self.tree }, index }
})
let id = uint_to_int(ts_query_match_id(ts_match))
let pattern_index = uint_to_int(ts_query_match_pattern_index(ts_match))
Some(QueryMatch::{ id, pattern_index, captures })
}
///|
#borrow(self, query, tree)
extern "c" fn ts_query_cursor_remove_match(
self : TSQueryCursor,
query : Query,
tree : Tree,
match_id : UInt
) = "moonbit_ts_query_cursor_remove_match"
///|
/// Remove a match from the query cursor's results.
pub fn QueryCursor::remove_match(self : QueryCursor, match_id : Int) -> Unit {
ts_query_cursor_remove_match(
self.cursor,
self.query,
self.tree,
int_to_uint(match_id),
)
}
///|
#borrow(self, query, tree, match_id)
extern "c" fn ts_query_cursor_next_capture(
self : TSQueryCursor,
query : Query,
tree : Tree,
match_id : FixedArray[UInt]
) -> @c.Nullable[TSQueryMatch] = "moonbit_ts_query_cursor_next_capture"
///|
/// Advance to the next capture of the currently running query.
///
/// If there is a capture, returns Some(capture).
/// Otherwise, returns None.
pub fn QueryCursor::next_capture(self : QueryCursor) -> QueryCapture? {
let match_id = FixedArray::make(1, 0U)
let ts_match = ts_query_cursor_next_capture(
self.cursor,
self.query,
self.tree,
match_id,
).to()
guard ts_match is Some(ts_match) else { return None }
let node = ts_query_match_captures_get_node(ts_match, 0)
let index = ts_query_match_captures_get_index(ts_match, 0)
let index = uint_to_int(index)
Some(QueryCapture::{ node: { node, tree: self.tree }, index })
}
///|
#borrow(self)
extern "c" fn ts_query_cursor_set_max_start_depth(
self : TSQueryCursor,
max_start_depth : UInt
) = "moonbit_ts_query_cursor_set_max_start_depth"
///|
/// Set the maximum start depth for a query cursor.
///
/// This prevents cursors from exploring children nodes at a certain depth.
/// Note if a pattern includes many children, then they will still be checked.
///
/// The zero max start depth value can be used as a special behavior and
/// it helps to destructure a subtree by staying on a node and using captures
/// for interested parts. Note that the zero max start depth only limit a search
/// depth for a pattern's root node but other nodes that are parts of the pattern
/// may be searched at any depth what defined by the pattern structure.
///
/// Set to `@uint.max_value` to remove the maximum start depth.
pub fn QueryCursor::set_max_start_depth(
self : QueryCursor,
max_start_depth : Int
) -> Unit {
ts_query_cursor_set_max_start_depth(self.cursor, int_to_uint(max_start_depth))
}