@@ -662,49 +662,51 @@ impl TsQuery {
662
662
}
663
663
664
664
/// Run the query on `contents` and collect all captures as (capture_name, node) pairs
665
- pub ( crate ) fn all_captures < ' tree > (
666
- & mut self ,
665
+ pub ( crate ) fn all_captures < ' tree , ' query > (
666
+ & ' query mut self ,
667
667
node : tree_sitter:: Node < ' tree > ,
668
- contents : & [ u8 ] ,
669
- ) -> Vec < ( String , tree_sitter:: Node < ' tree > ) > {
670
- self . cursor
671
- . matches ( & self . query , node, contents)
672
- . flat_map ( |m| {
673
- m. captures . iter ( ) . map ( |cap| {
674
- let cap_name = self . query . capture_names ( ) [ cap. index as usize ] . to_string ( ) ;
675
- ( cap_name, cap. node )
676
- } )
677
- } )
678
- . collect ( )
668
+ contents : & ' query [ u8 ] ,
669
+ ) -> AllCaptures < ' tree , ' query >
670
+ where
671
+ ' tree : ' query ,
672
+ {
673
+ let matches_iter = self . cursor . matches ( & self . query , node, contents) ;
674
+ AllCaptures :: new ( & self . query , matches_iter)
679
675
}
680
676
681
677
/// Run the query on `contents` and filter captures that match `capture_name`
682
- pub ( crate ) fn captures_for < ' tree > (
683
- & mut self ,
678
+ pub ( crate ) fn captures_for < ' tree , ' query > (
679
+ & ' query mut self ,
684
680
node : tree_sitter:: Node < ' tree > ,
685
681
capture_name : & str ,
686
- contents : & [ u8 ] ,
687
- ) -> Vec < tree_sitter:: Node < ' tree > > {
682
+ contents : & ' query [ u8 ] ,
683
+ ) -> impl Iterator < Item = tree_sitter:: Node < ' tree > > + ' query
684
+ where
685
+ // The tree must outlive query
686
+ ' tree : ' query ,
687
+ {
688
+ let capture_name = capture_name. to_string ( ) ;
688
689
self . all_captures ( node, contents)
689
- . into_iter ( )
690
- . filter_map ( |( name, node) | {
690
+ . filter_map ( move |( name, node) | {
691
691
if name == capture_name {
692
692
Some ( node)
693
693
} else {
694
694
None
695
695
}
696
696
} )
697
- . collect ( )
698
697
}
699
698
700
699
/// Run the query on `contents` and filter captures that match `capture_names`.
701
700
/// They are returned in a hashmap keyed by capture name.
702
- pub ( crate ) fn captures_by < ' tree > (
703
- & mut self ,
701
+ pub ( crate ) fn captures_by < ' tree , ' query > (
702
+ & ' query mut self ,
704
703
node : tree_sitter:: Node < ' tree > ,
705
704
capture_names : & [ & str ] ,
706
- contents : & [ u8 ] ,
707
- ) -> HashMap < String , Vec < tree_sitter:: Node < ' tree > > > {
705
+ contents : & ' query [ u8 ] ,
706
+ ) -> HashMap < String , Vec < tree_sitter:: Node < ' tree > > >
707
+ where
708
+ ' tree : ' query ,
709
+ {
708
710
let mut result: HashMap < String , Vec < tree_sitter:: Node < ' tree > > > = HashMap :: new ( ) ;
709
711
710
712
for & name in capture_names {
@@ -721,6 +723,57 @@ impl TsQuery {
721
723
}
722
724
}
723
725
726
+ pub ( crate ) struct AllCaptures < ' tree , ' query > {
727
+ query : & ' query tree_sitter:: Query ,
728
+ matches_iter : tree_sitter:: QueryMatches < ' query , ' tree , & ' query [ u8 ] , & ' query [ u8 ] > ,
729
+ current_captures_iter : Option < std:: slice:: Iter < ' query , tree_sitter:: QueryCapture < ' tree > > > ,
730
+ }
731
+
732
+ impl < ' tree , ' query > AllCaptures < ' tree , ' query > {
733
+ pub ( crate ) fn new (
734
+ query : & ' query tree_sitter:: Query ,
735
+ matches_iter : tree_sitter:: QueryMatches < ' query , ' tree , & ' query [ u8 ] , & ' query [ u8 ] > ,
736
+ ) -> Self {
737
+ Self {
738
+ query,
739
+ matches_iter,
740
+ current_captures_iter : None ,
741
+ }
742
+ }
743
+ }
744
+
745
+ impl < ' tree , ' query > Iterator for AllCaptures < ' tree , ' query > {
746
+ type Item = ( String , tree_sitter:: Node < ' tree > ) ;
747
+
748
+ // The iterator yields `(capture_name, node)` pairs by walking through all query matches.
749
+ // For each match, it iterates through its captures before advancing to the next match.
750
+ fn next ( & mut self ) -> Option < Self :: Item > {
751
+ loop {
752
+ if let Some ( captures_iter) = & mut self . current_captures_iter {
753
+ // We have an active iterator over captures of a match, iterate over it until exhausted
754
+ if let Some ( capture) = captures_iter. next ( ) {
755
+ let cap_name = self . query . capture_names ( ) [ capture. index as usize ] . to_string ( ) ;
756
+ return Some ( ( cap_name, capture. node ) ) ;
757
+ }
758
+ }
759
+
760
+ // We either haven't started iterating over matches yet, or the
761
+ // current captures iterator for a match is exhausted. Let's check
762
+ // if there are remaining matches.
763
+ match self . matches_iter . next ( ) {
764
+ Some ( query_match) => {
765
+ // Set the iterator over the captures of this match as current
766
+ self . current_captures_iter = Some ( query_match. captures . iter ( ) ) ;
767
+ } ,
768
+ None => {
769
+ // No more captures and no more matches
770
+ return None ;
771
+ } ,
772
+ }
773
+ }
774
+ }
775
+ }
776
+
724
777
#[ cfg( test) ]
725
778
mod tests {
726
779
use ropey:: Rope ;
0 commit comments