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.rsdiffbeforeafterboth13};13};141415use crate::{15use crate::{16 children::{should_start_with_newline, trivia_after, trivia_between},16 children::{trivia_after, trivia_between},17 comments::{format_comments, CommentLocation},17 comments::{format_comments, CommentLocation},18};18};1919294 l.r_brace_token().map(Into::into).as_ref(),294 l.r_brace_token().map(Into::into).as_ref(),295 );295 );296 for mem in children.into_iter() {296 for mem in children.into_iter() {297 if mem.needs_newline_above() {297 if mem.should_start_with_newline {298 p!(pi: nl);298 p!(pi: nl);299 }299 }300 p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));300 p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));314 p!(pi: nl)314 p!(pi: nl)315 }315 }316316317 // TODO: implement same thing as needs_newline_above, but for end comments318 if should_start_with_newline(&end_comments) {317 if end_comments.should_start_with_newline {319 p!(pi: nl);318 p!(pi: nl);320 }319 }321 p!(pi: items(format_comments(&end_comments, CommentLocation::EndOfItems)));320 p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));322 p!(pi: <i str("}"));321 p!(pi: <i str("}"));323 pi322 pi324 }323 }450 } else {449 } else {451 p!(pi: str("local") >i nl);450 p!(pi: str("local") >i nl);452 for bind in binds {451 for bind in binds {453 if bind.needs_newline_above() {452 if bind.should_start_with_newline {454 p!(pi: nl);453 p!(pi: nl);455 }454 }456 p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));455 p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));457 p!(pi: {bind.value} str(";"));456 p!(pi: {bind.value} str(";"));458 p!(pi: items(format_comments(&bind.inline_trivia, CommentLocation::ItemInline)) nl);457 p!(pi: items(format_comments(&bind.inline_trivia, CommentLocation::ItemInline)) nl);459 }458 }460 // TODO: needs_newline_above end_comments459 if end_comments.should_start_with_newline {460 p!(pi: nl)461 }461 p!(pi: items(format_comments(&end_comments, CommentLocation::EndOfItems)));462 p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));462 p!(pi: <i);463 p!(pi: <i);463 }464 }464 p!(pi: str(";") nl);465 p!(pi: str(";") nl);472 .as_ref(),473 .as_ref(),473 );474 );475476 if expr_comments.should_start_with_newline {477 p!(pi: nl);478 }474 p!(pi: items(format_comments(&expr_comments, CommentLocation::AboveItem)));479 p!(pi: items(format_comments(&expr_comments.trivia, CommentLocation::AboveItem)));475476 // TODO: needs_newline_above expr477 p!(pi: {l.expr()});480 p!(pi: {l.expr()});478 pi481 pi479 }482 }cmds/jrsonnet-fmt/src/tests.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/tests.rs
+++ b/cmds/jrsonnet-fmt/src/tests.rs
@@ -20,7 +20,8 @@
macro_rules! assert_formatted {
($input:literal, $output:literal) => {
let formatted = reformat(indoc!($input));
- let expected = indoc!($output);
+ let mut expected = indoc!($output).to_owned();
+ expected.push('\n');
if formatted != expected {
panic!(
"bad formatting, expected\n```\n{formatted}\n```\nto be equal to\n```\n{expected}\n```",
@@ -49,7 +50,6 @@
);
}
-// Fails
#[test]
fn last_comment_respects_spacing_with_inline_comment_above() {
assert_formatted!(