feat(rome_rowan): implement DoubleEndedIterator for SyntaxTriviaPiecesIterator
MODIFY
crates/rome_formatter/src/format_element.rs
crates/rome_formatter/src/format_element.rs
@@ -326,7 +326,7 @@ where
.last_trailing_trivia()
.and_then(|prev_token| {
// Newline pieces can only come last in trailing trivias, skip to it directly
- prev_token.pieces().last()?.as_newline()
+ prev_token.pieces().next_back()?.as_newline()
})
.is_some() as usize;

MODIFY
crates/rome_formatter/src/formatter.rs
crates/rome_formatter/src/formatter.rs
@@ -271,16 +271,10 @@ impl Formatter {
}
fn print_leading_trivia(&self, token: &SyntaxToken) -> FormatElement {
- // False positive: the trivias need to be collected in a vector as they
- // are iterated on in reverse order later, but SyntaxTriviaPiecesIterator
- // doesn't implement DoubleEndedIterator (rust-lang/rust-clippy#8132)
- #[allow(clippy::needless_collect)]
- let pieces: Vec<_> = token.leading_trivia().pieces().collect();
-
let mut line_count = 0;
let mut elements = Vec::new();
- for piece in pieces.into_iter().rev() {
+ for piece in token.leading_trivia().pieces().rev() {
if let Some(comment) = piece.as_comments() {
let is_single_line = comment.text().trim_start().starts_with("//");

MODIFY
crates/rome_rowan/src/api.rs
crates/rome_rowan/src/api.rs
@@ -438,6 +438,18 @@ impl<L: Language> Iterator for SyntaxTriviaPiecesIterator<L> {
}
}
+impl<L: Language> DoubleEndedIterator for SyntaxTriviaPiecesIterator<L> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ let (offset, trivia) = self.iter.next_back()?;
+ Some(SyntaxTriviaPiece {
+ raw: self.iter.raw.clone(),
+ offset,
+ trivia,
+ _p: PhantomData,
+ })
+ }
+}
+
impl<L: Language> SyntaxTrivia<L> {
/// Returns all [SyntaxTriviaPiece] of this trivia.
///
@@ -1691,6 +1703,7 @@ mod tests {
&[TriviaPiece::Whitespace(3)],
);
});
+
let pieces: Vec<_> = node.first_leading_trivia().unwrap().pieces().collect();
assert_eq!(2, pieces.len());
@@ -1703,5 +1716,16 @@ mod tests {
assert_eq!(TextSize::from(4), pieces[1].text_len());
assert_eq!(TextRange::new(3.into(), 7.into()), pieces[1].text_range());
assert!(pieces[1].as_comments().is_some());
+
+ let pieces_rev: Vec<_> = node
+ .first_leading_trivia()
+ .unwrap()
+ .pieces()
+ .rev()
+ .collect();
+
+ assert_eq!(2, pieces_rev.len());
+ assert_eq!("/**/", pieces_rev[0].text());
+ assert_eq!("\n\t ", pieces_rev[1].text());
}
}

MODIFY
crates/rome_rowan/src/cursor.rs
crates/rome_rowan/src/cursor.rs
@@ -559,6 +559,8 @@ pub struct SyntaxTriviaPiecesIterator {
pub(crate) raw: SyntaxTrivia,
pub(crate) next_index: usize,
pub(crate) next_offset: TextSize,
+ pub(crate) end_index: usize,
+ pub(crate) end_offset: TextSize,
}
impl Iterator for SyntaxTriviaPiecesIterator {
@@ -575,6 +577,21 @@ impl Iterator for SyntaxTriviaPiecesIterator {
}
}
+impl DoubleEndedIterator for SyntaxTriviaPiecesIterator {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.end_index == self.next_index {
+ return None;
+ }
+
+ self.end_index -= 1;
+
+ let trivia = self.raw.get_piece(self.end_index)?;
+ self.end_offset -= trivia.text_len();
+
+ Some((self.end_offset, trivia))
+ }
+}
+
impl SyntaxTrivia {
pub(crate) fn text(&self) -> &str {
let green_token = self.token.green();
@@ -595,6 +612,16 @@ impl SyntaxTrivia {
}
}
+ /// Get the number of TriviaPiece inside this trivia
+ fn len(&self) -> usize {
+ let green_token = self.token.green();
+ if self.is_leading {
+ green_token.leading_trivia().len()
+ } else {
+ green_token.trailing_trivia().len()
+ }
+ }
+
/// Gets index-th trivia piece when the token associated with this trivia was created.
/// See [SyntaxTriviaPiece].
pub(crate) fn get_piece(&self, index: usize) -> Option<TriviaPiece> {
@@ -614,6 +641,8 @@ impl SyntaxTrivia {
raw: self.clone(),
next_index: 0,
next_offset: self.offset,
+ end_index: self.len(),
+ end_offset: self.text_range().end(),
}
}

MODIFY
crates/rome_rowan/src/green/token.rs
crates/rome_rowan/src/green/token.rs
@@ -40,6 +40,15 @@ impl GreenTokenTrivia {
}
}
+ pub(crate) fn len(&self) -> usize {
+ match self {
+ GreenTokenTrivia::None => 0,
+ GreenTokenTrivia::Whitespace(_) => 1,
+ GreenTokenTrivia::Comment(..) => 1,
+ GreenTokenTrivia::Many(v) => v.len(),
+ }
+ }
+
pub(crate) fn get_piece(&self, index: usize) -> Option<TriviaPiece> {
match self {
GreenTokenTrivia::Whitespace(l) if index == 0 => Some(TriviaPiece::Whitespace(*l)),

feat(rome_rowan): implement DoubleEndedIterator for SyntaxTriviaPiecesIterator (#2016)