@@ -354,6 +354,26 @@ impl<'a> CapturedNode<'a> {
354
354
}
355
355
}
356
356
357
+ /// The number of matches a TS cursor can at once to avoid performance problems for medium to large files.
358
+ /// Set with `set_match_limit`.
359
+ /// Using such a limit means that we loose valid captures in, so there is fundamentally a tradeoff here.
360
+ ///
361
+ ///
362
+ /// Old tree sitter versions used a limit of 32 by default until this limit was removed in version `0.19.5` (must now best set manually).
363
+ /// However, this causes performance issues for medium to large files.
364
+ /// In helix, this problem caused treesitter motions to take multiple seconds to complete in medium-sized rust files (3k loc).
365
+ /// Neovim also encountered this problem and reintroduced this limit after it was removed upstream
366
+ /// (see <https://github.com/neovim/neovim/issues/14897> and <https://github.com/neovim/neovim/pull/14915>).
367
+ /// The number used here is fundamentally a tradeoff between breaking some obscure edge cases and performance.
368
+ ///
369
+ ///
370
+ /// A value of 64 was chosen because neovim uses that value.
371
+ /// Neovim chose this value somewhat arbitrarily (<https://github.com/neovim/neovim/pull/18397>) adjusting it whenever issues occur in practice.
372
+ /// However this value has been in use for a long time and due to the large userbase of neovim it is probably a good choice.
373
+ /// If this limit causes problems for a grammar in the future, it could be increased.
374
+
375
+ const TREE_SITTER_MATCH_LIMIT : u32 = 64 ;
376
+
357
377
impl TextObjectQuery {
358
378
/// Run the query on the given node and return sub nodes which match given
359
379
/// capture ("function.inside", "class.around", etc).
@@ -394,6 +414,8 @@ impl TextObjectQuery {
394
414
. iter ( )
395
415
. find_map ( |cap| self . query . capture_index_for_name ( cap) ) ?;
396
416
417
+ cursor. set_match_limit ( TREE_SITTER_MATCH_LIMIT ) ;
418
+
397
419
let nodes = cursor
398
420
. captures ( & self . query , node, RopeProvider ( slice) )
399
421
. filter_map ( move |( mat, _) | {
@@ -843,6 +865,7 @@ impl Syntax {
843
865
let mut cursor = ts_parser. cursors . pop ( ) . unwrap_or_else ( QueryCursor :: new) ;
844
866
// TODO: might need to set cursor range
845
867
cursor. set_byte_range ( 0 ..usize:: MAX ) ;
868
+ cursor. set_match_limit ( TREE_SITTER_MATCH_LIMIT ) ;
846
869
847
870
let source_slice = source. slice ( ..) ;
848
871
@@ -1032,6 +1055,7 @@ impl Syntax {
1032
1055
1033
1056
// if reusing cursors & no range this resets to whole range
1034
1057
cursor_ref. set_byte_range ( range. clone ( ) . unwrap_or ( 0 ..usize:: MAX ) ) ;
1058
+ cursor_ref. set_match_limit ( TREE_SITTER_MATCH_LIMIT ) ;
1035
1059
1036
1060
let mut captures = cursor_ref
1037
1061
. captures (
0 commit comments