-
Notifications
You must be signed in to change notification settings - Fork 926
Indentation of asssignment comments between lhs and rhs #5501
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
src/comment.rs
Outdated
/// that end on that line. | ||
fn is_first_comment_ends_on_first_line(s: &str) -> bool { | ||
if s.starts_with("/*") { | ||
s.lines().next().map_or(false, |l| l.contains("*/")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we use ends_with
instead of contains
?
s.lines().next().map_or(false, |l| l.contains("*/")) | |
s.lines().next().map_or(false, |l| l.ends_with("*/")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed (although I am not sure whether the comment was deleted).
The main benefit of the change is that line that ends with /* comment 1*/ /* comment 2
is now properly handled. Therefore I also changed the function name and its description.
While evaluating the suggested change I found two issues that are worth noting:
- The following code is not handled properly and therefore is not formatted:
var= /* Block comment 1*/ // Line comment 2
value;
Fixing this is quite complex. Since it is not expected to be used much in practice, I assume that for this PR it is o.k. not to handle this case, but I did add FIXME
comment for it.
- the following code (now added to the test cases):
var = /* Block comment */
value;
Is formatted into one line:
var = /* Block comment */ value;
However:
var = /* Block comment single line 1 */
/* Block comment single line 2*/ value;
is formatted as:
var = /* Block comment single line 1 */
/* Block comment single line 2*/
value;
I believe this is o.k., but I note that in case the formatted value
in the first example should be in the next line.
src/comment.rs
Outdated
@@ -225,7 +237,13 @@ pub(crate) fn combine_strs_with_missing_comments( | |||
Cow::from("") | |||
} else { | |||
let one_line_width = last_line_width(prev_str) + first_line_width(&missing_comment) + 1; | |||
if prefer_same_line && one_line_width <= shape.width { | |||
// First comment of a comments block can be in same line if ends in the first line | |||
// (and meets other conditions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we enumerate what the other conditions are in the comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed - removed the "(and meets other conditions)" as it was redundant. Adding the additional details could just be confusing as the "other conditions" are clear from the code.
src/items.rs
Outdated
let base_span = if let Some(ref ty) = self.ty { | ||
mk_sp(ty.span.hi(), self.span.hi()) | ||
} else { | ||
mk_sp(self.pat.span.hi(), self.span.hi()) | ||
}; | ||
|
||
let offset = context.snippet(base_span).find_uncommented("=")?; | ||
let base_span_lo = base_span.lo(); | ||
|
||
let assign_lo = base_span_lo + BytePos(offset as u32); | ||
let comment_start_pos = if let Some(ref ty) = self.ty { | ||
ty.span.hi() | ||
} else { | ||
self.pat.span.hi() | ||
}; | ||
let comment_before_assign = context.snippet(mk_sp(comment_start_pos, assign_lo)).trim(); | ||
|
||
let assign_hi = base_span_lo + BytePos((offset + 1) as u32); | ||
let rhs_span_lo = init.span.lo(); | ||
let comment_end_pos = if init.attrs.is_empty() { | ||
rhs_span_lo | ||
} else { | ||
let attr_span_lo = init.attrs.first().unwrap().span.lo(); | ||
// for the case using block | ||
// ex. let x = { #![my_attr]do_something(); } | ||
if rhs_span_lo < attr_span_lo { | ||
rhs_span_lo | ||
} else { | ||
attr_span_lo | ||
} | ||
}; | ||
|
||
if !comment_before_assign.is_empty() { | ||
let new_indent_str = &pat_shape | ||
.block_indent(0) | ||
.to_string_with_newline(context.config); | ||
result = format!("{}{}{}", comment_before_assign, new_indent_str, result); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took some time to look into this code. It seems like a lot of what's going on here is to recover comments before the =
, e.g. let pat: ty /*comment*/ =
or let pat /*comment*/ =
. However, this PR and all the test cases you've outlined below only test for comments that come after the =
e.g. let pat: ty = /*comment*/ expr
.
For that reason I think we should only worry about the post =
comments in this PR.
I also propose renaming init
to expr
since I think it's a little clearer that it's an ast::Expr
node, and using init()
instead of init_else_opt()
since we don't use the _else
and currently don't support ast::LocalKind::InitElse(..)
variants.
if let Some(expr) = self.kind.init() {
// Adjust the span after the `pat` and `ty` before searching for the `=`
let base_span = if let Some(ref ty) = self.ty {
mk_sp(ty.span.hi(), self.span.hi())
} else {
mk_sp(self.pat.span.hi(), self.span.hi())
};
let comment_lo = context.snippet_provider.span_after(base_span, "=");
let comment_span = mk_sp(comment_lo, expr.span.lo());
let nested_shape = shape.sub_width(1)?;
result = rewrite_assign_rhs_with_comments(
context,
result,
expr,
nested_shape,
&RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comment_span,
true,
)?;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... a lot of what's going on here is to recover comments before the
=
I somehow missed that when I copied the R2 commit changes =
comments. I therefore assume that maybe that commit was tested properly.
Changed the code per suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for applying all the feedback, and for helping to backport those PRs! I think we're good to go here!
I haven't had a chance to review this in detail, but from a cursory glance through the discussion and test cases my inclination is that this probably is the direction we want to go in long term. However, it's got too big a risk of having a high blast radius for me to want to release it in the immediate future. I'd like to see this tested against some larger codebases, both to test/confirm that hypothesis/concern and see how it shakes out against a broader set of code. Ultimately I think we'd need to version gate this no matter what, especially given the increased rigor around formatting stability given the pivot to style guide editions as the evolution mechanism |
c0c3b3e
to
d1da537
Compare
Added version gating. |
tests/source/lhs-to-rhs-between-comments/assignment-multi-line-comments.rs
Show resolved
Hide resolved
@davidBar-On thanks for making the requested changes. when you have a chance can you rebase your feature branch on master |
1aa6ae0
to
81849b9
Compare
Rebase done. |
@calebcartwright I just ran the |
Backport of suggested R2 changes for handling indentation of comments between assignment rhs and lhs, taken from different R2 PRs/commits. Not all changes were merged into R2, so this is why I didn't add "Backport" to the title.
Test cases are backport of PR #4734 test cases (which are enhancement of PR #4661 test cases).
The PR is based on:
Rewrite for ast::Local
done by this commit.light_rewrite_comment()
which were backported from R2, as the test cases require these changes for proper formatting.