git.delta.rocks / jrsonnet / refs/commits / 016538aa1e6d

difftreelog

feat(fmt) preserve comments at root of source code

Yaroslav Bolyukin2022-06-22parent: #014057b.patch.diff
in: master

3 files changed

modifiedcmds/jrsonnet-fmt/src/children.rsdiffbeforeafterboth
before · cmds/jrsonnet-fmt/src/children.rs
1use std::{fmt::Debug, marker::PhantomData, mem};23use jrsonnet_rowan_parser::{4	nodes::{Trivia, TriviaKind},5	AstNode, AstToken, SyntaxElement,6	SyntaxKind::*,7	SyntaxNode, TS,8};910pub type ChildTrivia = Vec<Trivia>;1112pub struct ChildIterator<I, T> {13	inner: I,14	_marker: PhantomData<T>,15}1617pub fn children_between<T: AstNode + Debug>(18	node: SyntaxNode,19	start: Option<&SyntaxElement>,20	end: Option<&SyntaxElement>,21) -> (Vec<Child<T>>, ChildTrivia) {22	let mut iter = node.children_with_tokens().peekable();23	while iter.peek() == start {24		iter.next();25	}26	children(27		iter.take_while(|i| Some(i) != end),28		start.is_none() || end.is_none(),29	)30}3132pub fn should_start_with_newline(tt: &ChildTrivia) -> bool {33	// First for previous item end34	count_newlines_before(&tt) >= 235}3637fn count_newlines_before(tt: &ChildTrivia) -> usize {38	let mut nl_count = 0;39	for t in tt {40		match t.kind() {41			TriviaKind::Whitespace => {42				nl_count += t.text().bytes().filter(|b| *b == b'\n').count();43			}44			_ => break,45		}46	}47	nl_count48}49fn count_newlines_after(tt: &ChildTrivia) -> usize {50	let mut nl_count = 0;51	for t in tt.iter().rev() {52		match t.kind() {53			TriviaKind::Whitespace => {54				nl_count += t.text().bytes().filter(|b| *b == b'\n').count();55			}56			TriviaKind::SingleLineHashComment => {57				nl_count += 1;58				break;59			}60			TriviaKind::SingleLineSlashComment => {61				nl_count += 1;62				break;63			}64			_ => {}65		}66	}67	nl_count68}6970pub fn children<'a, T: AstNode + Debug>(71	items: impl Iterator<Item = SyntaxElement>,72	loose: bool,73) -> (Vec<Child<T>>, ChildTrivia) {74	let mut out = Vec::new();75	let mut current_child = None::<Child<T>>;76	let mut next = ChildTrivia::new();77	// Previous element ended, do not add more inline comments78	let mut started_next = false;79	let mut had_some = false;8081	for item in items {82		if let Some(value) = item.as_node().cloned().and_then(T::cast) {83			let before_trivia = mem::take(&mut next);84			let last_child = current_child.replace(Child {85				newlines_above: if had_some {86					count_newlines_before(&before_trivia)87						+ current_child88							.as_ref()89							.map(|c| count_newlines_after(&c.inline_trivia))90							.unwrap_or_default()91				} else {92					093				},94				before_trivia,95				value,96				inline_trivia: Vec::new(),97			});98			if let Some(last_child) = last_child {99				out.push(last_child)100			}101			had_some = true;102			started_next = false;103		} else if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {104			let is_single_line_comment = trivia.kind() == TriviaKind::SingleLineHashComment105				|| trivia.kind() == TriviaKind::SingleLineSlashComment;106			if started_next107				|| current_child.is_none()108				|| trivia.text().contains('\n') && !is_single_line_comment109			{110				next.push(trivia.clone());111				started_next = true;112			} else {113				let cur = current_child.as_mut().expect("checked not none");114				cur.inline_trivia.push(trivia);115				if is_single_line_comment {116					started_next = true;117				}118			}119			had_some = true;120		} else if loose {121			if had_some {122				break;123			}124			started_next = true;125		} else {126			assert!(127				TS![, ;].contains(item.kind()) || item.kind() == ERROR,128				"silently eaten token: {:?}",129				item.kind()130			)131		}132	}133134	if let Some(current_child) = current_child {135		out.push(current_child);136	}137138	(out, next)139}140141#[derive(Debug)]142pub struct Child<T> {143	newlines_above: usize,144	/// Comment before item, i.e145	///146	/// ```ignore147	/// // Comment148	/// item149	/// ```150	pub before_trivia: ChildTrivia,151	pub value: T,152	/// Comment after line, but located at same line153	///154	/// ```ignore155	/// item1, // Inline comment156	/// // Not inline comment157	/// item2,158	/// ```159	pub inline_trivia: ChildTrivia,160}161162impl<T> Child<T> {163	/// If this child has two newlines above in source code, so it needs to have it in output164	pub fn needs_newline_above(&self) -> bool {165		// First line for end of previous item166		self.newlines_above >= 2167	}168}
modifiedcmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/src/main.rs
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -1,6 +1,6 @@
 use std::any::type_name;
 
-use children::children_between;
+use children::{children_between, trivia_before};
 use dprint_core::formatting::{PrintItems, PrintOptions};
 use jrsonnet_rowan_parser::{
 	nodes::{
@@ -13,7 +13,7 @@
 };
 
 use crate::{
-	children::should_start_with_newline,
+	children::{should_start_with_newline, trivia_after},
 	comments::{format_comments, CommentLocation},
 };
 
@@ -463,8 +463,25 @@
 
 impl Printable for SourceFile {
 	fn print(&self) -> PrintItems {
-		assert!(self.expr().is_some());
-		self.expr().print()
+		let mut pi = p!(new:);
+		let before = trivia_before(
+			self.syntax().clone(),
+			self.expr()
+				.map(|e| e.syntax().clone())
+				.map(Into::into)
+				.as_ref(),
+		);
+		let after = trivia_after(
+			self.syntax().clone(),
+			self.expr()
+				.map(|e| e.syntax().clone())
+				.map(Into::into)
+				.as_ref(),
+		);
+		p!(pi: items(format_comments(&before, CommentLocation::AboveItem)));
+		p!(pi: {self.expr()} nl);
+		p!(pi: items(format_comments(&after, CommentLocation::EndOfItems)));
+		pi
 	}
 }
 
@@ -574,6 +591,7 @@
 		} + Template
 
 
+		// Comment after everything
 "#,
 	);
 
modifiedcrates/jrsonnet-rowan-parser/src/event.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/event.rs
+++ b/crates/jrsonnet-rowan-parser/src/event.rs
@@ -117,6 +117,9 @@
 					eat_start_whitespace = false;
 				}
 				Event::Finish { wrapper } => {
+					if depth == 1 {
+						self.skip_whitespace();
+					}
 					self.builder.finish_node();
 					depth -= 1;
 					let mut idx = idx;
@@ -126,6 +129,9 @@
 						wrapper = if let Event::Finish { wrapper } =
 							mem::replace(&mut self.events[idx], Event::Noop)
 						{
+							if depth == 1 {
+								self.skip_whitespace();
+							}
 							self.builder.finish_node();
 							depth -= 1;
 							wrapper