-
Notifications
You must be signed in to change notification settings - Fork 908
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
update chain handling of long lines and block-like parents #3884
Conversation
(Some(orig_rhs), _) => Some(format!(" {}", orig_rhs)), | ||
(Some(orig_rhs), _) => { | ||
let prefix = if orig_rhs.starts_with('\n') { "" } else { " " }; | ||
Some(format!("{}{}", prefix, orig_rhs)) |
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.
While working on this I tried a few different things to get the formatting to look right (especially for chains with long elements when using the Visual
indent style). This change was added to handle some of those approaches that started with a newline in order to prevent the error[internal]: left behind trailing whitespace
error from occurring.
The ultimate approach I went with does not need this, so I can remove this check if folks would prefer (though I do wonder if it may help with some other/unrelated trailing whitespace errors)
d8506f6
to
c115af7
Compare
afaca31
to
159756d
Compare
8ec76e5
to
79452d5
Compare
6c8a10c
to
0a8b110
Compare
d58732c
to
065dbaf
Compare
b65c769
to
62846f4
Compare
62846f4
to
d4cae1f
Compare
I think this is probably finally ready for review whenever folks get a chance, apologies it took so long! |
@@ -389,6 +389,255 @@ fn example() { | |||
} | |||
``` | |||
|
|||
## `chains_block_parent_indent_children` |
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.
I always have such a hard time coming up with config names 😄 If this approach seems viable for handling the scenario in #3157 (and it should indeed be configurable) then this should probably be renamed to something more succinct
// Whether one or more of the inner chain items exceed the max width | ||
has_long_inner_item: bool, | ||
// Whether the final chain item exceeds the max width | ||
has_long_tail: bool, |
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.
instead of a single has_long
flag, these fields are used to have a more detailed view of where the chain has a long element based on how chains are formatted (parent and tail are formatted separately)
wrap_str(rewrite, max_width, shape).is_none() | ||
} | ||
|
||
fn format_chain_parent_inner( |
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.
).foo().bar().baz(); | ||
} | ||
|
||
fn long_parent() { |
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.
While working on this I discovered quite a variety of chain scenarios (position of long element in the chain, rhs of an assignment vs. free, etc.) that had to be explicitly handled, so there's test cases for each of those scenarios
@@ -0,0 +1,167 @@ | |||
// rustfmt-indent_style: Visual | |||
|
|||
fn long_parent() { |
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.
This scenario was the most difficult to deal with (Visual
for indent_style
with the long element being the chain parent).
As I mentioned in the PR description this is definitely not perfect, but probably still better than not formatting the chains at all. I felt like this approach was the better of the evils, as doing the typical Visual indent with this scenario would basically result in the entire chain body being off screen (as all the child elements would be shifted to the right of the end of the long parent).
In the future, it might be possible to leverage some of the heurstics added here to improve upon this scenario (for example checking whether the first child is long, etc.) but this feels like quite an edge case to me and I need a break from chains for a bit 😁
@topecongiro - I'm going to close this and then open a new PR with the changes. that should make it easier to review, provide a cleaner commit history, and allow me to avoid dealing with all the merge conflicts |
@calebcartwright any updates? #3157 linked here but I wasn't sure if anything else had been done since. |
Sorry @superhawk610, but no updates. There's some other discussions and decisions that will impact this relative to major version upgrades and the stability guarantee which need to settle first so we don't end up with divergent chain formatting implementations that are each massive. Will take another pass after some of those other items are resolved, but TBH this is still a ways out from being included in a released version of rustfmt. |
Makes sense. Thanks for working on this! 🙂 |
Resolves #3863, resolves #2970, and, I believe, resolves #3157 as well.
Apologies that this PR is on the larger side, though worth noting that it mostly consists of test files. As I'm sure folks are well aware, chains are tricky 😄, so I included a lot of tests for my own sanity (happy to remove anything that seems duplicative/unnecessary).
I also had to change my approach quite a few times while working on this and didn't do a great job of squashing commits along the way so I'd probably advise against trying to review this commit-by-commit. Instead I'd suggest reviewing the files associated with the update for the two referenced issues, and I've included a summary of the respective changes below for each issue accordingly.
Issue 3863 - handling of long chain elements
Currently, rustfmt will fail to format a chain if that chain contains one or more elements that exceeds
max_width
which has surfaced in a few issues (#3863 and rust-lang/rustup#2097 for example).This PR updates the handling of chains to ensure that rustfmt will still be able to format the chain even if there's a long item. There's one edge case (when
indent_style
isVisual
and the long chain item is the chain's parent) that's not perfect, but IMO is still an improvement over not being able to format the chain at all.Files associated with this update:
src/chains.rs
(all the changes except thefn format_chain_parent_inner()
function that starts on line730
)src/expr.rs
(See my inline comment in this file as this change may not be necessary/helpful)tests/source/chains_long_item_block.rs
tests/source/chains_long_item_visual.rs
tests/target/chains_long_item_block.rs
tests/target/chains_long_item_block.rs
Issue 3157 - configurability of chain indents for chains with block-like parents
The current state is described in far better detail in #3157, but the gist is that when the chain parent is block-like, then the chain elements are not indented like they are with a simple chain parent.
Based on that thread, my sense is that there's some subjective/stylistic-preferences around the indentation flavors. As such the approach I've proposed in this PR leverages two new configuration options (with the default indent behavior being rustfmt's current style/approach for these types of chains) to give users some flexibility and to support the requested formatting in #3157
Files associated with this update:
Configurations.md
src/chains.rs
(just thefn format_chain_parent_inner()
function that starts on line730
)src/config/mod.rs
src/config/options.rs
tests/source/chains_multiline_parent_always.rs
tests/source/chains_multiline_parent_never.rs
tests/source/chains_multiline_parent_simple_calls.rs
tests/source/chains_multiline_parent_tuples_and_simple_calls.rs
tests/target/chains_multiline_parent_always.rs
tests/target/chains_multiline_parent_never.rs
tests/target/chains_multiline_parent_simple_calls.rs
tests/target/chains_multiline_parent_tuples_and_simple_calls.rs