rust-lang / rustfmt

Format Rust code
https://rust-lang.github.io/rustfmt/
Apache License 2.0
6.04k stars 889 forks source link

New config option for more control over block wrapping match arm bodies #4896

Open calebcartwright opened 3 years ago

calebcartwright commented 3 years ago

Context

The Rust Style Guide codifies the rules for formatting match expressions which is accordingly the default formatting rustfmt applies, including whether match arm bodies should or should not be block wrapped.

There's been a number of feature requests over the years to provide users with more control and flexibility around block wrapping arm bodies and a couple configuration options do exist today, including match_arm_blocks and force_multiline_blocks, that provide a degree of control.

While those two new options have proven useful, they don't provide a sufficient amount of control that some users desire. The objective for this issue is to provide enhanced rustfmt support for block wrapping match arm bodies that can be controlled by users via a new config option

Requirements

Ultimately, the new config option should support the following use cases (each one of which would be mapped to a different value of the config option)

This new config option should of course be an enum type with corresponding variants for the different styles, and it would naturally obviate the need for the boolean match_arm_blocks. We'll need to do a soft deprecate of match_arm_blocks which means that when rustfmt encounters a case where the user has set match_arm_blocks then rustfmt should print a warning about deprecation, and internally map the specified match_arm_blocks value to the corresponding variant of the new option (there's several other cases where we've done this which can serve as references)

Implementation hints

It would probably be easiest to break this work up into chunks, and first start with the creation of the new option with the variants that map to the existing true/false values for match_arm_blocks. The next easiest piece (which could potentially be incorporated with the first) would probably be the "always wrap" variant, since the other two would require some additional work to inspect elements to conditionally determine whether to wrap and may have a few other considerations.

Feel free to propose a name for the new option and its corresponding variants as part of the PR, as we don't have any preferred names at this time. Don't worry too much about the name up front as we can always (and likely will) bikeshed on it later.

A decent starting location in the codebase for arm handling would probably be:

https://github.com/rust-lang/rustfmt/blob/2837ca557fd5e9aaf9a7986072314e660cb3e7fa/src/matches.rs#L217-L223

And the configuration option info can be found in: https://github.com/rust-lang/rustfmt/tree/master/src/config https://github.com/rust-lang/rustfmt/blob/master/Configurations.md https://github.com/rust-lang/rustfmt/commit/71863753bd53da50dd26bd8ab78a5da581e73f5c#diff-3fadefeddae400d637b630074fb57b82a1e37a0c44f2ba7cfa95c0a1c8a3dc75 (example soft deprecation/mapping an old op to a new one)

There should be plenty of existing snippets under tests/{source,target]/.. for matches particularly with the existing configuration options that provide similar formatting behavior, but please also feel free to reference the contributing docs on adding tests and/or asks any questions here or in Discord

ashvin021 commented 3 years ago

Hi! I could give this a shot.

calebcartwright commented 3 years ago

That's great @ashvin021! Let us know if you have any questions