git.delta.rocks / jrsonnet / refs/commits / dacee201fa00

difftreelog

feat(fmt) preserve comments in locals

Yaroslav Bolyukin2022-06-22parent: #016538a.patch.diff
in: master

3 files changed

modifiedcmds/jrsonnet-fmt/src/children.rsdiffbeforeafterboth
40 }40 }
41 let mut iter = node.children_with_tokens().peekable();41 let mut iter = node.children_with_tokens().peekable();
42 while iter.peek() != start {42 while iter.peek() != start {
43 // println!("Skipped {}");
44 dbg!(&iter.next());43 iter.next();
45 }44 }
46 dbg!(&iter.next());45 iter.next();
47 let mut out = Vec::new();46 let mut out = Vec::new();
48 for item in iter {47 for item in iter {
49 if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {48 if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
59 out58 out
60}59}
60
61pub fn trivia_between(
62 node: SyntaxNode,
63 start: Option<&SyntaxElement>,
64 end: Option<&SyntaxElement>,
65) -> ChildTrivia {
66 let mut iter = node.children_with_tokens().peekable();
67 while iter.peek() != start {
68 iter.next();
69 }
70 iter.next();
71
72 let loose = start.is_none() || end.is_none();
73
74 let mut out = Vec::new();
75 for item in iter.take_while(|i| Some(i) != end) {
76 if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
77 out.push(trivia);
78 } else if loose {
79 break;
80 } else {
81 assert!(
82 TS![, ;].contains(item.kind()) || item.kind() == ERROR,
83 "silently eaten token: {:?}",
84 item.kind()
85 )
86 }
87 }
88 out
89}
6190
62pub fn children_between<T: AstNode + Debug>(91pub fn children_between<T: AstNode + Debug>(
63 node: SyntaxNode,92 node: SyntaxNode,
modifiedcmds/jrsonnet-fmt/src/comments.rsdiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/src/comments.rs
+++ b/cmds/jrsonnet-fmt/src/comments.rs
@@ -12,6 +12,7 @@
 	EndOfItems,
 }
 
+#[must_use]
 pub fn format_comments(comments: &ChildTrivia, loc: CommentLocation) -> PrintItems {
 	let mut pi = p!(new:);
 
modifiedcmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/src/main.rs
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -13,7 +13,7 @@
 };
 
 use crate::{
-	children::{should_start_with_newline, trivia_after},
+	children::{should_start_with_newline, trivia_after, trivia_between},
 	comments::{format_comments, CommentLocation},
 };
 
@@ -436,11 +436,45 @@
 			}
 			Expr::ExprVar(n) => p!(new: {n.name()}),
 			Expr::ExprLocal(l) => {
-				let mut pi = p!(new: str("local") >i nl);
-				for bind in l.binds() {
-					p!(pi: {bind} str(",") nl);
+				let mut pi = p!(new:);
+				let (binds, end_comments) = children_between::<Bind>(
+					l.syntax().clone(),
+					l.local_kw_token().map(Into::into).as_ref(),
+					l.semi_token().map(Into::into).as_ref(),
+				);
+				if binds.len() == 1 {
+					let bind = &binds[0];
+					p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));
+					p!(pi: str("local ") {bind.value});
+				// TODO: keep end_comments, child.inline_trivia somehow, force multiple locals formatting in case of presence?
+				} else {
+					p!(pi: str("local") >i nl);
+					for bind in binds {
+						if bind.needs_newline_above() {
+							p!(pi: nl);
+						}
+						p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));
+						p!(pi: {bind.value} str(";"));
+						p!(pi: items(format_comments(&bind.inline_trivia, CommentLocation::ItemInline)) nl);
+					}
+					// TODO: needs_newline_above end_comments
+					p!(pi: items(format_comments(&end_comments, CommentLocation::EndOfItems)));
+					p!(pi: <i);
 				}
-				p!(pi: <i str(";") nl {l.expr()});
+				p!(pi: str(";") nl);
+
+				let expr_comments = trivia_between(
+					l.syntax().clone(),
+					l.semi_token().map(Into::into).as_ref(),
+					l.expr()
+						.map(|e| e.syntax().clone())
+						.map(Into::into)
+						.as_ref(),
+				);
+				p!(pi: items(format_comments(&expr_comments, CommentLocation::AboveItem)));
+
+				// TODO: needs_newline_above expr
+				p!(pi: {l.expr()});
 				pi
 			}
 			Expr::ExprIfThenElse(ite) => {
@@ -515,6 +549,25 @@
 
 		local unary = !a;
 
+		local
+			//   I am comment
+			singleLocalWithItemComment = 1,
+		;
+
+		// Comment between local and expression
+
+		local
+			a = 1, //   Inline
+			// Comment above b
+			b = 4,
+
+			// c needs some space
+			c = 5,
+
+			// Comment after everything
+		;
+
+
 		local Template = {z: "foo"};
 
 		{