mitranim / sublime-rust-fmt

Sublime Text plugin that formats Rust code with rustfmt
30 stars 3 forks source link

Plugin does not run rustfmt with correct edition #11

Open LPGhatguy opened 4 years ago

LPGhatguy commented 4 years ago

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.

mitranim commented 4 years ago

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

"executable": ["rustfmt", "--edition", "2018"],
mitranim commented 4 years ago

Please let me know if this solves the issue.

LPGhatguy commented 4 years ago

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?

mitranim commented 4 years ago

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.

LPGhatguy commented 4 years ago

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.

mitranim commented 4 years ago

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"]
LPGhatguy commented 4 years ago

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 commented 4 years ago

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!

mitranim commented 4 years ago

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.

saona-raimundo commented 3 years ago

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

2) Add

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