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) -> (Vec<Child<T>>, EndingComments) {103 let mut iter = node.children_with_tokens().peekable();104 while iter.peek() != start {105 iter.next();106 }107 iter.next();108 children(109 iter.take_while(|i| Some(i) != end),110 start.is_none() || end.is_none(),111 )112}113114pub fn should_start_with_newline(prev_inline: Option<&ChildTrivia>, tt: &ChildTrivia) -> bool {115 count_newlines_before(tt)116 + prev_inline117 .map(count_newlines_after)118 .unwrap_or_default()119120 121 >= 2122}123124fn count_newlines_before(tt: &ChildTrivia) -> usize {125 let mut nl_count = 0;126 for t in tt {127 match t {128 Ok(t) => match t.kind() {129 TriviaKind::Whitespace => {130 nl_count += t.text().bytes().filter(|b| *b == b'\n').count();131 }132 _ => break,133 },134 Err(_) => {135 nl_count += 1;136 }137 }138 }139 nl_count140}141fn count_newlines_after(tt: &ChildTrivia) -> usize {142 let mut nl_count = 0;143 for t in tt.iter().rev() {144 match t {145 Ok(t) => match t.kind() {146 TriviaKind::Whitespace => {147 nl_count += t.text().bytes().filter(|b| *b == b'\n').count();148 }149 TriviaKind::SingleLineHashComment => {150 nl_count += 1;151 break;152 }153 TriviaKind::SingleLineSlashComment => {154 nl_count += 1;155 break;156 }157 _ => {}158 },159 Err(_) => nl_count += 1,160 }161 }162 nl_count163}164165pub fn children<T: AstNode + Debug>(166 items: impl Iterator<Item = SyntaxElement>,167 loose: bool,168) -> (Vec<Child<T>>, EndingComments) {169 let mut out = Vec::new();170 let mut current_child = None::<Child<T>>;171 let mut next = ChildTrivia::new();172 173 let mut started_next = false;174 let mut had_some = false;175176 for item in items {177 if let Some(value) = item.as_node().cloned().and_then(T::cast) {178 let before_trivia = mem::take(&mut next);179 let last_child = current_child.replace(Child {180 181 should_start_with_newline: had_some182 && should_start_with_newline(183 current_child.as_ref().map(|c| &c.inline_trivia),184 &before_trivia,185 ),186 before_trivia,187 value,188 inline_trivia: Vec::new(),189 });190 if let Some(last_child) = last_child {191 out.push(last_child)192 }193 had_some = true;194 started_next = false;195 } else if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {196 let is_single_line_comment = trivia.kind() == TriviaKind::SingleLineHashComment197 || trivia.kind() == TriviaKind::SingleLineSlashComment;198 if started_next199 || current_child.is_none()200 || trivia.text().contains('\n') && !is_single_line_comment201 {202 next.push(Ok(trivia.clone()));203 started_next = true;204 } else {205 let cur = current_child.as_mut().expect("checked not none");206 cur.inline_trivia.push(Ok(trivia));207 if is_single_line_comment {208 started_next = true;209 }210 }211 had_some = true;212 } else if CustomError::can_cast(item.kind()) {213 next.push(Err(item.to_string()))214 } else if loose {215 if had_some {216 break;217 }218 started_next = true;219 } else {220 assert!(221 TS![, ;].contains(item.kind()),222 "silently eaten token: {:?}",223 item.kind()224 )225 }226 }227228 let ending_comments = EndingComments {229 should_start_with_newline: should_start_with_newline(230 current_child.as_ref().map(|c| &c.inline_trivia),231 &next,232 ),233 trivia: next,234 };235236 if let Some(current_child) = current_child {237 out.push(current_child);238 }239240 (out, ending_comments)241}242243#[derive(Debug)]244pub struct Child<T> {245 246 pub should_start_with_newline: bool,247 248 249 250 251 252 253 pub before_trivia: ChildTrivia,254 pub value: T,255 256 257 258 259 260 261 262 pub inline_trivia: ChildTrivia,263}264265pub struct EndingComments {266 267 pub should_start_with_newline: bool,268 pub trivia: ChildTrivia,269}270impl EndingComments {271 pub fn is_empty(&self) -> bool {272 !self.should_start_with_newline && self.trivia.is_empty()273 }274}