difftreelog
feat(fmt) preserve comments in locals
in: master
3 files changed
cmds/jrsonnet-fmt/src/children.rsdiffbeforeafterboth40 }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 out60}59}6061pub 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();7172 let loose = start.is_none() || end.is_none();7374 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 out89}619062pub fn children_between<T: AstNode + Debug>(91pub fn children_between<T: AstNode + Debug>(63 node: SyntaxNode,92 node: SyntaxNode,cmds/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:);
cmds/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"};
{