Indentation of asssignment comments between lhs and rhs#5501
Conversation
| /// 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.
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.
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.
| 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.
can we enumerate what the other conditions are in the comment
There was a problem hiding this comment.
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.
| 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.
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.
... 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.
ytmimi
left a comment
There was a problem hiding this comment.
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. |
|
@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 |
|
☔ The latest upstream changes (possibly #6823) made this pull request unmergeable. Please resolve the merge conflicts. |
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::Localdone by this commit.light_rewrite_comment()which were backported from R2, as the test cases require these changes for proper formatting.