@@ -50,13 +50,14 @@ pub fn is_separated_list_sorted_by<'a, L: Language + 'a, N: AstNode<Language = L
5050/// Chunks are sorted separately.
5151///
5252/// This sort is stable (i.e., does not reorder equal elements).
53- pub fn sorted_separated_list_by < ' a , L : Language + ' a , List , Node , Key > (
53+ pub fn sorted_separated_list_by < ' a , L , List , Node , Key > (
5454 list : & List ,
5555 get_key : impl Fn ( & Node ) -> Option < Key > ,
5656 make_separator : fn ( ) -> SyntaxToken < L > ,
5757 comparator : impl Fn ( & Key , & Key ) -> Ordering ,
5858) -> Result < List , SyntaxError >
5959where
60+ L : Language + ' a ,
6061 List : AstSeparatedList < Language = L , Node = Node > + AstNode < Language = L > + ' a ,
6162 Node : AstNode < Language = L > + ' a ,
6263{
@@ -117,7 +118,7 @@ where
117118/// It allows you to add missing separators and remove an extra separator.
118119/// Usually, you collect every pair of nodes and separators in a vector and then pass a mutable iterator to `fix_separators`.
119120///
120- /// See [sorted_separated_list_by] as a usage example.
121+ /// See [` sorted_separated_list_by` ] as a usage example.
121122pub fn fix_separators < ' a , L : Language + ' a , N : AstNode < Language = L > + ' a > (
122123 // Mutable iterator of a list of nodes and their optional separators
123124 iter : impl std:: iter:: ExactSizeIterator < Item = ( & ' a mut N , & ' a mut Option < SyntaxToken < L > > ) > ,
@@ -159,6 +160,78 @@ pub fn fix_separators<'a, L: Language + 'a, N: AstNode<Language = L> + 'a>(
159160 }
160161}
161162
163+ /// Splits the list into two new lists according to a partitioning function.
164+ ///
165+ /// Every item of `list` is passed to `partition` that decides if the item is
166+ /// part of the left or the right returned list.
167+ /// The `partition` function can change the passed item before returning it.
168+ /// This allows supporting cases where the passed AST node must be modified.
169+ ///
170+ /// This function returns `None` if it encounters a buggy item or
171+ /// if `partition` returns `None` for at least one item.
172+ ///
173+ /// The trailing separators are moved with their node.
174+ pub fn split_separated_list < ' a , L , List , Node > (
175+ list : & List ,
176+ partition : impl Fn ( Node ) -> Option < either:: Either < Node , Node > > ,
177+ ) -> Option < ( List , List ) >
178+ where
179+ L : Language + ' a ,
180+ List : AstSeparatedList < Language = L , Node = Node > + AstNode < Language = L > + ' a ,
181+ Node : AstNode < Language = L > + ' a ,
182+ {
183+ let mut left_items = Vec :: with_capacity ( list. len ( ) ) ;
184+ let mut left_separators = Vec :: with_capacity ( list. len ( ) ) ;
185+ let mut right_items = Vec :: with_capacity ( list. len ( ) ) ;
186+ let mut right_separators = Vec :: with_capacity ( list. len ( ) ) ;
187+
188+ for AstSeparatedElement {
189+ node,
190+ trailing_separator,
191+ } in list. elements ( )
192+ {
193+ // Abort the split if a node is buggy or if `partition` returns `None`.
194+ let node = node. ok ( ) ?;
195+ let trailing_separator = trailing_separator. ok ( ) ?;
196+ let ( items, separators, node) = match partition ( node) ? {
197+ either:: Either :: Left ( node) => ( & mut left_items, & mut left_separators, node) ,
198+ either:: Either :: Right ( node) => ( & mut right_items, & mut right_separators, node) ,
199+ } ;
200+ items. push ( node) ;
201+ if let Some ( trailing_separator) = trailing_separator {
202+ separators. push ( trailing_separator) ;
203+ }
204+ }
205+
206+ let mut left_items = left_items. into_iter ( ) ;
207+ let mut left_separators = left_separators. into_iter ( ) ;
208+ let left_list = List :: unwrap_cast ( SyntaxNode :: new_detached (
209+ list. syntax ( ) . kind ( ) ,
210+ ( 0 ..left_items. len ( ) + left_separators. len ( ) ) . map ( |index| {
211+ if index % 2 == 0 {
212+ Some ( left_items. next ( ) ?. into_syntax ( ) . into ( ) )
213+ } else {
214+ Some ( left_separators. next ( ) ?. into ( ) )
215+ }
216+ } ) ,
217+ ) ) ;
218+
219+ let mut right_items = right_items. into_iter ( ) ;
220+ let mut right_separators = right_separators. into_iter ( ) ;
221+ let right_list = List :: unwrap_cast ( SyntaxNode :: new_detached (
222+ list. syntax ( ) . kind ( ) ,
223+ ( 0 ..right_items. len ( ) + right_separators. len ( ) ) . map ( |index| {
224+ if index % 2 == 0 {
225+ Some ( right_items. next ( ) ?. into_syntax ( ) . into ( ) )
226+ } else {
227+ Some ( right_separators. next ( ) ?. into ( ) )
228+ }
229+ } ) ,
230+ ) ) ;
231+
232+ Some ( ( left_list, right_list) )
233+ }
234+
162235/// Counts lines in a syntax tree, used by `noExcessiveLinesPerFile`.
163236///
164237/// When `skip_blank_lines` is true, counts tokens with leading newlines (excluding blank lines).
0 commit comments