diff --git a/lib/binding_rust/bindings.rs b/lib/binding_rust/bindings.rs index 57fbad87..e84ac4fe 100644 --- a/lib/binding_rust/bindings.rs +++ b/lib/binding_rust/bindings.rs @@ -162,6 +162,19 @@ pub const TSQueryErrorCapture: TSQueryError = 4; pub const TSQueryErrorStructure: TSQueryError = 5; pub const TSQueryErrorLanguage: TSQueryError = 6; pub type TSQueryError = ::core::ffi::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TSQueryCursorState { + pub payload: *mut ::core::ffi::c_void, + pub current_byte_offset: u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TSQueryCursorOptions { + pub payload: *mut ::core::ffi::c_void, + pub progress_callback: + ::core::option::Option bool>, +} extern "C" { #[doc = " Create a new parser."] pub fn ts_parser_new() -> *mut TSParser; @@ -662,6 +675,15 @@ extern "C" { #[doc = " Start running a given query on a given node."] pub fn ts_query_cursor_exec(self_: *mut TSQueryCursor, query: *const TSQuery, node: TSNode); } +extern "C" { + #[doc = " Start running a gievn query on a given node, with some options."] + pub fn ts_query_cursor_exec_with_options( + self_: *mut TSQueryCursor, + query: *const TSQuery, + node: TSNode, + options: *const TSQueryCursorOptions, + ); +} extern "C" { #[doc = " Manage the maximum number of in-progress matches allowed by this query\n cursor.\n\n Query cursors have an optional maximum capacity for storing lists of\n in-progress captures. If this capacity is exceeded, then the\n earliest-starting match will silently be dropped to make room for further\n matches. This maximum capacity is optional — by default, query cursors allow\n any number of pending matches, dynamically allocating new space for them as\n needed as the query is executed."] pub fn ts_query_cursor_did_exceed_match_limit(self_: *const TSQueryCursor) -> bool; diff --git a/lib/include/tree_sitter/api.h b/lib/include/tree_sitter/api.h index 5c994136..31a39d46 100644 --- a/lib/include/tree_sitter/api.h +++ b/lib/include/tree_sitter/api.h @@ -161,6 +161,16 @@ typedef enum TSQueryError { TSQueryErrorLanguage, } TSQueryError; +typedef struct TSQueryCursorState { + void *payload; + uint32_t current_byte_offset; +} TSQueryCursorState; + +typedef struct TSQueryCursorOptions { + void *payload; + bool (*progress_callback)(TSQueryCursorState *state); +} TSQueryCursorOptions; + /********************/ /* Section - Parser */ /********************/ @@ -1020,6 +1030,16 @@ void ts_query_cursor_delete(TSQueryCursor *self); */ void ts_query_cursor_exec(TSQueryCursor *self, const TSQuery *query, TSNode node); +/** + * Start running a gievn query on a given node, with some options. + */ +void ts_query_cursor_exec_with_options( + TSQueryCursor *self, + const TSQuery *query, + TSNode node, + const TSQueryCursorOptions *query_options +); + /** * Manage the maximum number of in-progress matches allowed by this query * cursor. @@ -1036,6 +1056,8 @@ uint32_t ts_query_cursor_match_limit(const TSQueryCursor *self); void ts_query_cursor_set_match_limit(TSQueryCursor *self, uint32_t limit); /** + * @deprecated use [`ts_query_cursor_exec_with_options`] and pass in a callback instead, this will be removed in 0.26. + * * Set the maximum duration in microseconds that query execution should be allowed to * take before halting. * @@ -1045,6 +1067,8 @@ void ts_query_cursor_set_match_limit(TSQueryCursor *self, uint32_t limit); void ts_query_cursor_set_timeout_micros(TSQueryCursor *self, uint64_t timeout_micros); /** + * @deprecated use [`ts_query_cursor_exec_with_options`] and pass in a callback instead, this will be removed in 0.26. + * * Get the duration in microseconds that query execution is allowed to take. * * This is set via [`ts_query_cursor_set_timeout_micros`]. diff --git a/lib/src/query.c b/lib/src/query.c index f4efd726..63809f8b 100644 --- a/lib/src/query.c +++ b/lib/src/query.c @@ -315,6 +315,8 @@ struct TSQueryCursor { uint32_t next_state_id; TSClock end_clock; TSDuration timeout_duration; + const TSQueryCursorOptions *query_options; + TSQueryCursorState query_state; unsigned operation_count; bool on_visible_node; bool ascending; @@ -3082,6 +3084,23 @@ void ts_query_cursor_exec( } else { self->end_clock = clock_null(); } + self->query_options = NULL; + self->query_state = (TSQueryCursorState) {0}; +} + +void ts_query_cursor_exec_with_options( + TSQueryCursor *self, + const TSQuery *query, + TSNode node, + const TSQueryCursorOptions *query_options +) { + ts_query_cursor_exec(self, query, node); + if (query_options) { + self->query_options = query_options; + self->query_state = (TSQueryCursorState) { + .payload = query_options->payload + }; + } } void ts_query_cursor_set_byte_range( @@ -3481,12 +3500,19 @@ static inline bool ts_query_cursor__advance( if (++self->operation_count == OP_COUNT_PER_QUERY_TIMEOUT_CHECK) { self->operation_count = 0; } + + if (self->query_options && self->query_options->progress_callback) { + self->query_state.current_byte_offset = ts_node_start_byte(ts_tree_cursor_current_node(&self->cursor)); + } if ( did_match || self->halted || ( self->operation_count == 0 && - !clock_is_null(self->end_clock) && clock_is_gt(clock_now(), self->end_clock) + ( + (!clock_is_null(self->end_clock) && clock_is_gt(clock_now(), self->end_clock)) || + (self->query_options && self->query_options->progress_callback && self->query_options->progress_callback(&self->query_state)) + ) ) ) { return did_match;