123use std::{fmt::Debug, mem};45use jrsonnet_rowan_parser::{6 nodes::{CustomError, Trivia, TriviaKind},7 AstNode, AstToken, SyntaxElement, SyntaxNode, TS,8};910pub type ChildTrivia = Vec<Result<Trivia, String>>;111213pub fn trivia_before(node: SyntaxNode, end: Option<&SyntaxElement>) -> ChildTrivia {14 let mut out = Vec::new();15 for item in node.children_with_tokens() {16 if Some(&item) == end {17 break;18 }1920 if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {21 out.push(Ok(trivia));22 } else if CustomError::can_cast(item.kind()) {23 out.push(Err(item.to_string()));24 } else if end.is_none() {25 break;26 } else {27 assert!(28 TS![, ;].contains(item.kind()),29 "silently eaten token: {:?}",30 item.kind()31 )32 }33 }34 out35}3637pub fn trivia_after(node: SyntaxNode, start: Option<&SyntaxElement>) -> ChildTrivia {38 if start.is_none() {39 return Vec::new();40 }41 let mut iter = node.children_with_tokens().peekable();42 while iter.peek() != start {43 iter.next();44 }45 iter.next();46 let mut out = Vec::new();47 for item in iter {48 if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {49 out.push(Ok(trivia));50 } else if CustomError::can_cast(item.kind()) {51 out.push(Err(item.to_string()))52 } else {53 assert!(54 TS![, ;].contains(item.kind()),55 "silently eaten token: {:?}",56 item.kind()57 )58 }59 }60 out61}6263pub fn trivia_between(64 node: SyntaxNode,65 start: Option<&SyntaxElement>,66 end: Option<&SyntaxElement>,67) -> EndingComments {68 let mut iter = node.children_with_tokens().peekable();69 while iter.peek() != start {70 iter.next();71 }72 iter.next();7374 let loose = start.is_none() || end.is_none();7576 let mut out = Vec::new();77 for item in iter.take_while(|i| Some(i) != end) {78 if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {79 out.push(Ok(trivia));80 } else if CustomError::can_cast(item.kind()) {81 out.push(Err(item.to_string()))82 } else if loose {83 break;84 } else {85 assert!(86 TS![, ;].contains(item.kind()),87 "silently eaten token: {:?}",88 item.kind()89 )90 }91 }92 EndingComments {93 should_start_with_newline: should_start_with_newline(None, &out),94 trivia: out,95 }96}9798pub fn children_between<T: AstNode + Debug>(99 node: SyntaxNode,100 start: Option<&SyntaxElement>,101 end: Option<&SyntaxElement>,102 trailing: Option<ChildTrivia>,103) -> (Vec<Child<T>>, EndingComments) {104 let mut iter = node.children_with_tokens().peekable();105 if start.is_some() {106 while iter.peek() != start {107 iter.next();108 }109 iter.next();110 }111 children(112 iter.take_while(|i| Some(i) != end),113 start.is_none() && end.is_none(),114 trailing,115 )116}117118pub fn should_start_with_newline(prev_inline: Option<&ChildTrivia>, tt: &ChildTrivia) -> bool {119 count_newlines_before(tt)120 + prev_inline121 .map(count_newlines_after)122 .unwrap_or_default()123124 125 >= 2126}127128fn count_newlines_before(tt: &ChildTrivia) -> usize {129 let mut nl_count = 0;130 for t in tt {131 match t {132 Ok(t) => match t.kind() {133 TriviaKind::Whitespace => {134 nl_count += t.text().bytes().filter(|b| *b == b'\n').count();135 }136 _ => break,137 },138 Err(_) => {139 nl_count += 1;140 }141 }142 }143 nl_count144}145fn count_newlines_after(tt: &ChildTrivia) -> usize {146 let mut nl_count = 0;147 for t in tt.iter().rev() {148 match t {149 Ok(t) => match t.kind() {150 TriviaKind::Whitespace => {151 nl_count += t.text().bytes().filter(|b| *b == b'\n').count();152 }153 TriviaKind::SingleLineHashComment => {154 nl_count += 1;155 break;156 }157 TriviaKind::SingleLineSlashComment => {158 nl_count += 1;159 break;160 }161 _ => {}162 },163 Err(_) => nl_count += 1,164 }165 }166 nl_count167}168169pub fn children<T: AstNode + Debug>(170 items: impl Iterator<Item = SyntaxElement>,171 loose: bool,172 mut trailing: Option<ChildTrivia>,173) -> (Vec<Child<T>>, EndingComments) {174 let mut out = Vec::new();175 let mut current_child = None::<Child<T>>;176 let mut next = ChildTrivia::new();177 178 let mut started_next = false;179 let mut had_some = false;180181 for item in items {182 if let Some(value) = item.as_node().cloned().and_then(T::cast) {183 let before_trivia = if let Some(trailing) = trailing.take() {184 assert!(next.is_empty());185 trailing186 } else {187 mem::take(&mut next)188 };189 let last_child = current_child.replace(Child {190 191 should_start_with_newline: had_some192 && should_start_with_newline(193 current_child.as_ref().map(|c| &c.inline_trivia),194 &before_trivia,195 ),196 before_trivia,197 value,198 inline_trivia: Vec::new(),199 });200 if let Some(last_child) = last_child {201 out.push(last_child)202 }203 had_some = true;204 started_next = false;205 } else if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {206 let is_single_line_comment = trivia.kind() == TriviaKind::SingleLineHashComment207 || trivia.kind() == TriviaKind::SingleLineSlashComment;208 if trailing.is_some() {209 210 continue;211 } else if started_next212 || current_child.is_none()213 || trivia.text().contains('\n') && !is_single_line_comment214 {215 next.push(Ok(trivia.clone()));216 started_next = true;217 } else {218 let cur = current_child.as_mut().expect("checked not none");219 cur.inline_trivia.push(Ok(trivia));220 if is_single_line_comment {221 started_next = true;222 }223 }224 had_some = true;225 } else if CustomError::can_cast(item.kind()) {226 next.push(Err(item.to_string()))227 } else if loose {228 if had_some {229 break;230 }231 started_next = true;232 } else {233 assert!(234 TS![, ;].contains(item.kind()),235 "silently eaten token: {:?}",236 item.kind()237 )238 }239 }240241 let ending_comments = EndingComments {242 should_start_with_newline: should_start_with_newline(243 current_child.as_ref().map(|c| &c.inline_trivia),244 &next,245 ),246 trivia: next,247 };248249 if let Some(current_child) = current_child {250 out.push(current_child);251 }252253 (out, ending_comments)254}255256#[derive(Debug)]257pub struct Child<T> {258 259 pub should_start_with_newline: bool,260 261 262 263 264 265 266 pub before_trivia: ChildTrivia,267 pub value: T,268 269 270 271 272 273 274 275 pub inline_trivia: ChildTrivia,276}277278pub struct EndingComments {279 280 pub should_start_with_newline: bool,281 pub trivia: ChildTrivia,282}283impl EndingComments {284 pub fn is_empty(&self) -> bool {285 !self.should_start_with_newline && self.trivia.is_empty()286 }287 pub fn extract_trailing(&mut self) -> ChildTrivia {288 mem::take(&mut self.trivia)289 }290}