difftreelog
feat(fmt) preserve newline above last comment
in: master
3 files changed
cmds/jrsonnet-fmt/src/children.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/children.rs
+++ b/cmds/jrsonnet-fmt/src/children.rs
@@ -1,6 +1,6 @@
// TODO: Return errors as trivia
-use std::{fmt::Debug, marker::PhantomData, mem};
+use std::{fmt::Debug, mem};
use jrsonnet_rowan_parser::{
nodes::{Trivia, TriviaKind},
@@ -62,7 +62,7 @@
node: SyntaxNode,
start: Option<&SyntaxElement>,
end: Option<&SyntaxElement>,
-) -> ChildTrivia {
+) -> EndingComments {
let mut iter = node.children_with_tokens().peekable();
while iter.peek() != start {
iter.next();
@@ -85,14 +85,17 @@
)
}
}
- out
+ EndingComments {
+ should_start_with_newline: should_start_with_newline(None, &out),
+ trivia: out,
+ }
}
pub fn children_between<T: AstNode + Debug>(
node: SyntaxNode,
start: Option<&SyntaxElement>,
end: Option<&SyntaxElement>,
-) -> (Vec<Child<T>>, ChildTrivia) {
+) -> (Vec<Child<T>>, EndingComments) {
let mut iter = node.children_with_tokens().peekable();
while iter.peek() != start {
iter.next();
@@ -104,9 +107,14 @@
)
}
-pub fn should_start_with_newline(tt: &ChildTrivia) -> bool {
- // First for previous item end
- count_newlines_before(tt) >= 2
+pub fn should_start_with_newline(prev_inline: Option<&ChildTrivia>, tt: &ChildTrivia) -> bool {
+ count_newlines_before(tt)
+ + prev_inline
+ .map(count_newlines_after)
+ .unwrap_or_default()
+
+ // First for previous item end, second for current item
+ >= 2
}
fn count_newlines_before(tt: &ChildTrivia) -> usize {
@@ -142,10 +150,10 @@
nl_count
}
-pub fn children<'a, T: AstNode + Debug>(
+pub fn children<T: AstNode + Debug>(
items: impl Iterator<Item = SyntaxElement>,
loose: bool,
-) -> (Vec<Child<T>>, ChildTrivia) {
+) -> (Vec<Child<T>>, EndingComments) {
let mut out = Vec::new();
let mut current_child = None::<Child<T>>;
let mut next = ChildTrivia::new();
@@ -157,15 +165,12 @@
if let Some(value) = item.as_node().cloned().and_then(T::cast) {
let before_trivia = mem::take(&mut next);
let last_child = current_child.replace(Child {
- newlines_above: if had_some {
- count_newlines_before(&before_trivia)
- + current_child
- .as_ref()
- .map(|c| count_newlines_after(&c.inline_trivia))
- .unwrap_or_default()
- } else {
- 0
- },
+ // First item should not start with newline
+ should_start_with_newline: had_some
+ && should_start_with_newline(
+ current_child.as_ref().map(|c| &c.inline_trivia),
+ &before_trivia,
+ ),
before_trivia,
value,
inline_trivia: Vec::new(),
@@ -206,16 +211,25 @@
}
}
+ let ending_comments = EndingComments {
+ should_start_with_newline: should_start_with_newline(
+ current_child.as_ref().map(|c| &c.inline_trivia),
+ &next,
+ ),
+ trivia: next,
+ };
+
if let Some(current_child) = current_child {
out.push(current_child);
}
- (out, next)
+ (out, ending_comments)
}
#[derive(Debug)]
pub struct Child<T> {
- newlines_above: usize,
+ /// If this child has two newlines above in source code, so it needs to have it in the output
+ pub should_start_with_newline: bool,
/// Comment before item, i.e
///
/// ```ignore
@@ -234,10 +248,8 @@
pub inline_trivia: ChildTrivia,
}
-impl<T> Child<T> {
- /// If this child has two newlines above in source code, so it needs to have it in output
- pub fn needs_newline_above(&self) -> bool {
- // First line for end of previous item
- self.newlines_above >= 2
- }
+pub struct EndingComments {
+ /// If this child has two newlines above in source code, so it needs to have it in the output
+ pub should_start_with_newline: bool,
+ pub trivia: ChildTrivia,
}
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, trivia_between},
+ children::{trivia_after, trivia_between},
comments::{format_comments, CommentLocation},
};
@@ -294,7 +294,7 @@
l.r_brace_token().map(Into::into).as_ref(),
);
for mem in children.into_iter() {
- if mem.needs_newline_above() {
+ if mem.should_start_with_newline {
p!(pi: nl);
}
p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));
@@ -314,11 +314,10 @@
p!(pi: nl)
}
- // TODO: implement same thing as needs_newline_above, but for end comments
- if should_start_with_newline(&end_comments) {
+ if end_comments.should_start_with_newline {
p!(pi: nl);
}
- p!(pi: items(format_comments(&end_comments, CommentLocation::EndOfItems)));
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
p!(pi: <i str("}"));
pi
}
@@ -450,15 +449,17 @@
} else {
p!(pi: str("local") >i nl);
for bind in binds {
- if bind.needs_newline_above() {
+ if bind.should_start_with_newline {
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)));
+ if end_comments.should_start_with_newline {
+ p!(pi: nl)
+ }
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
p!(pi: <i);
}
p!(pi: str(";") nl);
@@ -471,9 +472,11 @@
.map(Into::into)
.as_ref(),
);
- p!(pi: items(format_comments(&expr_comments, CommentLocation::AboveItem)));
- // TODO: needs_newline_above expr
+ if expr_comments.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&expr_comments.trivia, CommentLocation::AboveItem)));
p!(pi: {l.expr()});
pi
}
cmds/jrsonnet-fmt/src/tests.rsdiffbeforeafterboth20macro_rules! assert_formatted {20macro_rules! assert_formatted {21 ($input:literal, $output:literal) => {21 ($input:literal, $output:literal) => {22 let formatted = reformat(indoc!($input));22 let formatted = reformat(indoc!($input));23 let expected = indoc!($output);23 let mut expected = indoc!($output).to_owned();24 expected.push('\n');24 if formatted != expected {25 if formatted != expected {25 panic!(26 panic!(26 "bad formatting, expected\n```\n{formatted}\n```\nto be equal to\n```\n{expected}\n```",27 "bad formatting, expected\n```\n{formatted}\n```\nto be equal to\n```\n{expected}\n```",49 );50 );50}51}515252// Fails53#[test]53#[test]54fn last_comment_respects_spacing_with_inline_comment_above() {54fn last_comment_respects_spacing_with_inline_comment_above() {55 assert_formatted!(55 assert_formatted!(