sublime-rust-fmt icon indicating copy to clipboard operation
sublime-rust-fmt copied to clipboard

Plugin does not run rustfmt with correct edition

Open LPGhatguy opened this issue 5 years ago • 10 comments

I recently started a new project using Rust's async/await feature, with some code like this:

async fn body() {
    let releases: github::Releases =
        reqwest::get("https://api.github.com/repos/foo/bar/releases")
            .await?
            .json()?;
}

When trying to save my buffer, the RustFmt plugin throws an error and fails to reformat the file because these features are not available in Rust 2015 Edition:

image

The same error can be found by running rustfmt foo.rs directly.

When run on a 2018 edition project, the --edition 2018 argument should be passed to rustfmt. This matches the behavior of cargo fmt.

LPGhatguy avatar Feb 11 '20 22:02 LPGhatguy

Perhaps this calls for edition = "2018" in rustfmt.toml or a project-specific executable setting in RustFmt?

"executable": ["rustfmt", "--edition", "2018"],

mitranim avatar Feb 12 '20 07:02 mitranim

Please let me know if this solves the issue.

mitranim avatar Mar 04 '20 07:03 mitranim

Changing the executable setting does solve my issue! There are a few 2015 projects that I still contribute to. Do you know if falsely giving rustfmt the 2018 edition flag could cause issues there?

LPGhatguy avatar Mar 04 '20 18:03 LPGhatguy

If having it globally causes problems in some projects, and if rustfmt.toml doesn't work, you can create Sublime projects for those folders, and put RustFmt settings in project settings.

mitranim avatar Mar 04 '20 23:03 mitranim

These ideas require changes to projects that work around a specific quirk in this plugin. It is not common to use rustfmt.toml to specify edition, because this is redundant with information that's already in Cargo.toml.

Does it make sense for sublime-rust-fmt to parse the package.edition field out of Cargo.toml? It feels like this plugin should have the correct behavior with no additional configuration, and ideally match the behavior of cargo fmt.

LPGhatguy avatar Mar 04 '20 23:03 LPGhatguy

The plugin expects the Rust tools to parse their corresponding configs, be it .toml or something else. But wait, if cargo fmt picks up settings from Cargo.toml, why not use it globally?

"executable": ["cargo", "fmt"]

mitranim avatar Mar 05 '20 06:03 mitranim

Expecting the Rust tools to parse their own configs makes a lot of sense.

I'm not sure if cargo fmt can format a single file. It seems to have the ability to pass arguments directly through to rustfmt, but I'm not sure what arguments will be passed automatically.

It looks like setting the executable to cargo fmt makes my file get cleared on save! 😄

Some other rustfmt extensions might have this same bug based on their source code, but I couldn't find any bug reports in their issue trackers:

LPGhatguy avatar Mar 05 '20 18:03 LPGhatguy

I had a conversation with some folks in the Rust Community Discord. It appears that rust-analyzer, the current cutting-edge Rust IDE experience, ends up pulling edition out of Cargo.toml (we can do this with cargo metadata, too) and passes it to rustfmt directly:

https://github.com/rust-analyzer/rust-analyzer/pull/2477

It has a couple linked issues of users being surprised, too!

LPGhatguy avatar Mar 05 '20 18:03 LPGhatguy

Thanks for looking into it, I'm out of the loop since I only occasionally deal with Rust.

I feel like rustfmt should be the one pulling edition out of cargo.toml. We explicitly give it the location of rustfmt.toml; it should also add an option for cargo.toml. That would spare tools such as RustFmt from having to include a TOML parser, and make execution faster since that would be done in Rust not Python. It would also futureproof such plugins, instead of having to constantly negotiate new options between cargo.toml and rustfmt as they get added over time. Users wouldn't have to wait for plugins to add new option support, or open GitHub issues to make it happen 🙂.

I've opened rust-lang/rustfmt#4074, let's see if this can be properly fixed upstream.

mitranim avatar Mar 06 '20 08:03 mitranim

Thank you for looking into it!

I had the same problem when using async in a project. Since I only work on the 2018 edition of Rust, the solution you mentioned worked for me:

  1. In Sublime, go to
Preferences → Package Settings → RustFmt → Settings
  1. Add
"executable": ["rustfmt", "--edition", "2018"],

saona-raimundo avatar May 24 '21 17:05 saona-raimundo