-
Notifications
You must be signed in to change notification settings - Fork 927
Add option space_before_fn_sig_paren #4302
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
Add option space_before_fn_sig_paren #4302
Conversation
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.
Thank you for the PR @dylni! Really appreciate the willingness to jump in and propose an implementation.
Some modifications would be required for merging this however, and I've left details inline below.
Configurations.md
Outdated
Leave a space after the function name. | ||
|
||
- **Default value**: `"Never"` | ||
- **Possible values**: `"AfterGenerics"`, `"Never"` |
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'm not convinced yet that a single config option with many variants would be the best way to handle all the corresponding scenarios.
Opening this door creates several spacing options that I see:
- no spaces period between the ident and opening paren
- space between the ident and opening paren w/no generics
- space between ident and generics and generics and paren
- lhs space on the generics but none on rhs
- rhs space on the generics but none on the lhs
Users would then also be able to argue that they should be able to have various combinations of these stylings, for example no spacing between the ident and paren in the absence of generics, but lhs, rhs, or both spacing in the presence of generics.
I understand you may prefer to use only one of those personally, but if we're opening up control of spacing between the ident and parens at all then we'll be forced to support the other minor spacing variants/combinations as well.
If you still feel that this is best done as a single, multi-variant config option then please update this as described above to account for all such variants and combinations to see if that approach is really viable. Otherwise please change this to be a boolean that only impacts rhs spacing in the presence of generics because space_after_function_name = AfterGenerics
is really unintuitive for the non-generic scenarios
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.
Using a boolean would make it easier to support those other styles later, except for "space between the ident and opening paren w/no generics". Should I make space_before_fn_params
an enum of "Always"
, "Generics"
, and "Never"
to support that style? Since it wasn't mentioned in the tracking issue, I think it's enough to keep the option as a boolean.
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 I make space_before_fn_params an enum of "Always", "Generics", and "Never" to support that style? Since it wasn't mentioned in the tracking issue, I think it's enough to keep the option as a boolean.
I probably need to think on this one a bit, but my initial reaction is that a boolean is probably fine. The no-generics, just a space between the name and paren scenario really is binary in nature so a boolean feels natural. It's the generics scenario that has the Never/OnlyBefore/OnlyAfter/BeforeAndAfter mix that needs the extra control.
Think one boolean option for the fn foo()
vs fn foo ()
scenario and an enum option for fn foo<T>()
vs fn foo<T> ()
vs etc. should cover everything, including the two explicitly requested spacing styles
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.
All styles are covered now. Most of the code is needed to support adding a space before generics, since that style is inconsistent with other formatting for generics.
I think we'll probably also want to add some other test scenarios as well, including with this enabled alongside some other config opts. For example, a test that also has |
This reverts commit 6350a15.
I'll add more tests once the implementation is finalized. I already have some that use these options with max_width. |
Awesome thank you. I went ahead and did a quick spot check that the spacing in the signature didn't impact the parameter alignment with "Visual" indent style so will give the updated implementation another pass shortly |
Thanks @calebcartwright. Were you able to make the other pass and see if the implementation is ready for more tests? |
Not yet unfortunately. We've got a high priority broken toolstate issue that's occupying my rustfmt bandwidth ATM |
Ok, take your time |
Configurations.md
Outdated
@@ -803,6 +803,140 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi | |||
|
|||
See also [`max_width`](#max_width) and [`width_heuristics`](#width_heuristics) | |||
|
|||
## `fn_generics_space` |
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.
Just a little bikeshedding on the names, but I'm wondering if something like fn_sig_generics_spacing
or fn_generics_spacing
would be more explicit given we're not talking about just one space. What do you think?
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 agree that "spacing" is better, but "sig" feels redundant since generics are only in the signature. I'm okay with whichever you prefer
Configurations.md
Outdated
|
||
See also [`fn_no_generics_space`](#fn_no_generics_space). | ||
|
||
## `fn_no_generics_space` |
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.
Same bikeshed here. What would you think about fn_sig_name_paren_space
or fn_name_paren_space
and then in the descriptions for the two config options (and with inline comments in example) we can re-emphasize that this one's only used in signatures that have no generics and vice versa?
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 added comments inline, but I prefer fn_no_generics_spacing
. I wouldn't expect fn_name_paren_space
to only apply without generics. It's also not very clear that it's the complement of fn_generics_spacing
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 wouldn't expect fn_name_paren_space to only apply without generics. It's also not very clear that it's the complement of fn_generics_spacing
I always try to think about folks using config options they aren't terribly familiar with and doing so either via cli override or from their editor in a rustfmt config file vs. always being on the config documentation page, and that's why I generally prefer the names to be as explicit and self-explaining as possible.
My original thought was that by itself, the name just hints at some spacing for a function signature that lacks generics vs. explicitly whether it'd inject a space between the ident of the function name and the opening paren. I was trying to think of something would more clearly indicate what the config option did and not just when it would do something.
I do take your other point though, so let's see how the broader discussion in this PR plays out and then maybe we can iterate a bit more on the name to see if we can address both concerns 👍
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.
that's why I generally prefer the names to be as explicit and self-explaining as possible.
I agree. This is very helpful
let's see how the broader discussion in this PR plays out and then maybe we can iterate a bit more on the name to see if we can address both concerns
👍
src/formatting/items.rs
Outdated
@@ -916,7 +916,7 @@ fn format_impl_ref_and_type( | |||
result.push_str(format_unsafety(unsafety)); | |||
|
|||
let shape = Shape::indented(offset + last_line_width(&result), context.config); | |||
let generics_str = rewrite_generics(context, "impl", generics, shape)?; | |||
let generics_str = rewrite_generics(context, "impl", generics, shape, false)?; |
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 feel like adding a boolean to the signature for rewrite_generics
is shifting some of the aspects of formatting generics to the callers 🤔
What if instead the new param added to rewrite_generics
was an ItemKind and then internally rewrite_generics
could deal with enabling/disabling the spacing based on the combination of the ItemKind
and config options.
IIRC not all of these functions that internally call rewrite_generics
have the original AST Item node, but they could either pass the corresponding ItemKind variant to rewrite_generics
or could themselves take an extra param
Apologies for the delay @dylni. I feel like this is heading in a good direction and have left some inline feedback for your review. |
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.
Sorry for the late review, and thank you both @dylni and @calebcartwright for taking to time to work and review this PR. However, I have to say that I am not in favor of the direction this PR is heading.
I don't think it's a good idea to have many configuration variants for controlling spaces around function names; the benefit of having these options does not worth the complexity of interface and implementation.
I am ok with adding fn_no_generics_space
, provided we rename it to something more general. For fn_generic_spaces
, I prefer to remove it from this PR.
Are you thinking we should have the option apply only spacing to fn sigs that have no generics, and generics will still be |
I can see why you're saying this, but almost all of the complexity is coming from I don't think @dangerbarber and @bugeats Are you still interested in having a space before generics too? |
IMO it'd be good to get clarity on what spacing style variants you think we should allow @topecongiro Within the original issue there were several different spacing options requested and discussed. We obviously have to support the following as default no spacing is the (by far) most commonly used style that's required in the style guide: fn foo() {}
fn foo<T>(bar: T) {} Shortened snippets from new spacing options requested in #3564 (comment) fn foo () {}
fn foo <T> (bar: T) {} Additional ask from lower in that thread at #3564 (comment) fn foo<T> (bar: T) {} I still believe all of these style variants to be rather niche in Rust, but if we're going to support one of them then I personally struggle to justify not supporting the others; it's a "why this but not that" question I can't really answer 🤷♂️ |
I prefer to have a single configuration option, which, when is set to Note the last example in
|
That SGTM, and if I'm not mistaken that's the style you originally preferred as well @dylni. This approach would ensure consistency between generics in fns with other generic usage, which is one way we could justify this change without the granular lhs/rhs spacing on the generics. |
Yes @calebcartwright. I wanted to wait for you to comment, because I'm biased. The PR now uses the simpler interface @topecongiro Why not add a space when the function's multilined? I would expect it to make implementation more complicated and a little inconsistent |
@dylni My first thought was that it would be more consistent with rustfmt other styles if we don't add a space between the closing |
I don't have any objections to this. I still think there could be value in having something along the lines of I suppose this new config option will be released alongside the new |
This is actually a good point. @dylni Would you mind renaming the configuration option to |
There's now a test for indent_style
Fixed
No problem. Thank you and @calebcartwright for the reviews |
Awesome, thank you @dylni 🎉 |
Thanks 🎉 |
Also want to note that this new option will of course be available if you build rustfmt from source, though do want to note it'll probably be a few release cycles yet before it's available in rustfmt obtained via rustup |
Thanks everybody for working on this! I'll go ahead and close the tracking issue now. |
Was this feature removed? I can't find references in the codebase and trying to use the option gives an "Unknown configuration option" in the latest nightly |
You should always look at the config site (https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=) and select the version of rustfmt that you are using in order to see the available configuration options in your version. Unless you're compiling rustfmt from source I'd advise against looking at what's in source control. This particular option hasn't been ported to a released version of rustfmt yet, which as an fyi, is what the |
Modify VSCode's code highlighting regardless of function definition async patch_rust () {
const fp_rust = 'C:/Program Files/Microsoft VS Code/resources/app/extensions/rust/syntaxes/rust.tmLanguage.json'
let config = await fread_json(fp_rust)
let funcdef = config.repository.functions.patterns[1]
assert(funcdef.comment === 'function definition')
// original: \\b(fn)\\s+((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)((\\()|(<))
// add ' ?' after function name
funcdef.begin = '\\b(fn)\\s+((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+) ?((\\()|(<))'
await fwrite(fp_rust, config)
} Add function name in function definition with black bold and highlight "editor.tokenColorCustomizations": {
"textMateRules": [
{"scope": "entity.name.function", "settings": {"foreground": "#000000", "fontStyle": "bold"}},
{"scope": "support.function", "settings": {"foreground": "#000000", "fontStyle": "bold"}} ,
]
}, Restart VSCode and you will get For https://doc.rust-lang.org/book/ span.hljs-function::after
content: ' ' if (location.hostname.includes('doc.rust-lang.org'))
$$('code.language-rust span.hljs-function').forEach($fn => {
let sibling = $fn.nextSibling
if (sibling.nodeType === Node.TEXT_NODE)
sibling.textContent = sibling.textContent.replace(/<(.*)>\((.*)\) {/, '<$1> ($2) {')
})
function $$ <TElement extends Element> (selector: string) {
return document.querySelectorAll<TElement>(selector)
} |
This option adds very little code, so it would be great to have it supported.
It's an enum, because the tracking issue originally asked for a space before generics too, which is not part of this PR. This option can be extended later to add#4302 (comment)BeforeGenerics
orAroundGenerics
as other values.Tracking issue: #3564