8000 Format-on-save no longer functioning for rustfmt. No configuration change was made · Issue #4897 · dense-analysis/ale · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Format-on-save no longer functioning for rustfmt. No configuration change was made #4897

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

Open
ssokolow opened this issue Jan 21, 2025 · 6 comments
Labels

Comments

@ssokolow
Copy link
ssokolow commented Jan 21, 2025

Information

VIM version

VIM - Vi IMproved 9.0 (2022 Jun 28, compiled May 10 2022 08:40:37)
Included patches: 1-749

Operating System:

% lsb_release -a                                                               
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.5 LTS
Release:        22.04
Codename:       jammy

NOTE: LSP support is disabled because I'm also running coc.nvim for languages where a suitably performant, suitably licensed LSP is available... which does include Rust, though adding that predates format-on-save breaking by a long time and I have coc.nvim's format-on-save support disabled because it's much more laissez-faire than cargo fmt and I can't find docs for changing that.

What went wrong

Somewhere along the way, rustfmt-on-save stopped working and :ALEFix also has no effect.

I'm guessing it happened as a result of a :PlugUpdate bumping ALE somewhere along the way (I use vim-plug) though I suppose it could also have come as a result of a rustup update.

Running cargo fmt manually still has the expected effect, meaning that my test input is testing what I want it to test, given the context of my rustfmt.toml.

I couldn't find any issues that appeared to be describing the same problem and the ALEInfo command history says that rustfmt is getting run and returning an exit code of 1, which, if this list is still valid, basically means "anything but the code being too malformed to format".

Reproducing the bug

  1. Open a Rust source file
  2. >> (indent) a statement that's currently properly indented. (eg. println!(...);)
  3. :ALEFix
  4. Nothing happens
  5. :w
  6. Nothing happens
  7. !cargo fmt
  8. Line gets popped back to the correct indent level

:ALEInfo

Expand
 Current Filetype: rust
Available Linters: ['analyzer', 'cargo', 'cspell', 'rls', 'rustc']
   Linter Aliases:
'analyzer' -> ['rust_analyzer']
  Enabled Linters: ['analyzer']
  Ignored Linters: ['analyzer']
 Suggested Fixers:
  'remove_trailing_lines' - Remove all blank lines at the end of a file.
  'rustfmt' - Fix Rust files with Rustfmt.
  'trim_whitespace' - Remove all trailing whitespace characters at the end of every line.
 
 Linter Variables:
let g:ale_rust_analyzer_config = {'diagnostics': {'disabled': ['inactive-code', 'macro-error', 'unresolved-import', 'unresolved-proc-macro']}, 'procMacro': {'enable': v:true}}
let g:ale_rust_analyzer_executable = 'rust-analyzer'
let g:ale_rust_rustfmt_executable = 'rustfmt'
let g:ale_rust_rustfmt_options = ''
 
 Global Variables:
let g:ale_cache_executable_check_failures = v:null
let g:ale_change_sign_column_color = v:null
let g:ale_command_wrapper = ''
let g:ale_completion_delay = v:null
let g:ale_completion_enabled = 0
let g:ale_completion_max_suggestions = v:null
let g:ale_disable_lsp = 1
let g:ale_echo_cursor = 1
let g:ale_echo_msg_error_str = 'Error'
let g:ale_echo_msg_format = v:null
let g:ale_echo_msg_info_str = 'Info'
let g:ale_echo_msg_warning_str = 'Warning'
let g:ale_enabled = 1
let g:ale_fix_on_save = 1
let g:ale_fixers = {'xml': ['xmllint'], '*': ['remove_trailing_lines', 'trim_whitespace'], 'javascript': ['eslint'], 'css': ['stylelint'], 'make': ['remove_trailing_lines']}
let b:ale_fixers = ['rustfmt', 'trim_whitespace', 'remove_trailing_lines']
let g:ale_history_enabled = 1
let g:ale_info_default_mode = 'preview'
let g:ale_history_log_output = 1
let g:ale_keep_list_window_open = v:null
let g:ale_lint_delay = 200
let g:ale_lint_on_enter = 1
let g:ale_lint_on_filetype_changed = 1
let g:ale_lint_on_insert_leave = 0
let g:ale_lint_on_save = 1
let b:ale_lint_on_save = 0
let g:ale_lint_on_text_changed = 'never'
let g:ale_linter_aliases = {}
let g:ale_linters = {}
let b:ale_linters = ['analyzer']
let g:ale_linters_explicit = 0
let g:ale_linters_ignore = {}
let g:ale_list_vertical = v:null
let g:ale_list_window_size = v:null
let g:ale_loclist_msg_format = v:null
let g:ale_max_buffer_history_size = 20
let g:ale_max_signs = v:null
let g:ale_maximum_file_size = v:null
let g:ale_open_list = 1
let g:ale_pattern_options = v:null
let g:ale_pattern_options_enabled = v:null
let g:ale_root = {}
let g:ale_set_balloons = 1
let g:ale_set_highlights = 1
let g:ale_set_loclist = 0
let g:ale_set_quickfix = 1
let g:ale_set_signs = 1
let g:ale_sign_column_always = 1
let g:ale_sign_error = '✗'
let g:ale_sign_info = v:null
let g:ale_sign_offset = v:null
let g:ale_sign_style_error = v:null
let g:ale_sign_style_warning = v:null
let g:ale_sign_warning = '‼'
let g:ale_sign_highlight_linenrs = v:null
let g:ale_type_map = v:null
let g:ale_use_neovim_diagnostics_api = 0
let g:ale_use_global_executables = v:null
let g:ale_virtualtext_cursor = 'all'
let g:ale_warn_about_trailing_blank_lines = 1
let g:ale_warn_about_trailing_whitespace = 1
 
  Command History:

(finished - exit code 1) ['/usr/bin/zsh', '-c', '''rustfmt'' < ''/tmp/vpQIziD/3/main.rs''']
(finished - exit code 1) ['/usr/bin/zsh', '-c', '''rustfmt'' < ''/tmp/vpQIziD/8/main.rs''']
@ssokolow ssokolow added the bug label Jan 21, 2025
@yoann934
Copy link
yoann934 commented Apr 2, 2025

I had similar issue due to passing from edition 2021 to 2024. You should probably change the rustfmt.toml to setup 2021.

Probably we should also detect the first rustfmt.toml find in sub directories and use it, it would allow with ease to setup rustfmt by project.

@ssokolow
Copy link
Author
ssokolow commented Apr 2, 2025

I had similar issue due to passing from edition 2021 to 2024. You should probably change the rustfmt.toml to setup 2021.

Unacceptable. While less drastic, I still consider that a "Downgrade to Windows XP. Our product doesn't support Windows 11" answer.

I'll probably experiment with just turning off ALE's format-on-save in my ~/.vim/ftplugin/rust.vim and manually adding an autocmd BufWritePost that runs cargo fmt.

@yoann934
Copy link
yoann934 commented Apr 2, 2025

For now you can try something like this :
let g:ale_rust_rustfmt_options = '--config-path ~/.config/rustfmt.toml'

# replace with the correct version depending of your project
echo 'edition = "2021"' > ~/.config/rustfmt.toml

There's maybe a rustfmt option to point on the correct Cargo.toml, but I don't know about it.

@ssokolow
Copy link
Author
ssokolow commented Apr 2, 2025

Again, that would not achieve the desired result. I don't want it messing up or yelling at me that I'm trying to force formatting based on an edition that doesn't match the project or what have you.

Running cargo fmt outside ALE does exactly what I want in every project, regardless of edition, thanks to the occasional inclusion of a rustfmt.toml in the project as needed. It's just ALE that's breaking things.

@yoann934
Copy link
yoann934 commented Apr 2, 2025

It is the same tool, rustfmt points on cargo fmt :

ll /usr/bin/rustfmt 
# lrwxrwxrwx 1 root root 15 Mar  6 00:53 /usr/bin/rustfmt -> /usr/bin/rustup
ll /usr/bin/cargo
# lrwxrwxrwx 1 root root 15 Mar  6 00:53 /usr/bin/cargo -> /usr/bin/rustup

cargo fmt --version
# rustfmt 1.8.0-nightly (e2014e876e 2025-04-01)
rustfmt --version
# rustfmt 1.8.0-nightly (e2014e876e 2025-04-01)

The issue is about Cargo.toml detection. Maybe we should consider using cargo fmt as executable ?

@ssokolow
Copy link
Author
ssokolow commented Apr 2, 2025

It is the same tool, rustfmt points on cargo fmt :

No, Rust's toolchain just dispatches through rustup as part of rustup's version-management functionality. I believe it's done that way to support toolchain override shorthand.

(eg. If your default toolchain is the stable channel but you've got a matching nightly-channel build of the toolchain installed too, you can go cargo +nightly fmt to run that version.)

It's a toolchain-specific analogue to Debian's Alternatives system. (On a Debian-lineage distro such as Ubuntu, /usr/bin/yacc is a symlink to /etc/alternatives/yacc, which is a symlink to /usr/bin/bison.yacc, and the tool described in man update-alternatives lets you switch where those symlinks point.)

The real binaries will be elsewhere. (eg. when using rustup to install the stable-channel toolchain into your user profile as is the default configuration, you'll see separate rustfmt and cargo-fmt binaries under ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/)

The issue is about Cargo.toml detection. Maybe we should consider using cargo fmt as executable ?

As an alternative fixer and one I'd personally be fine with using, sure, but not as a silent change to how the rustfmt fixer works. Their semantics are different.

As cargo fmt --help says, "This utility formats all bin and lib files of the current crate using rustfmt."

It's a "Run make vs. invoke gcc directly" distinction and I'm just in a position where doing the equivalent of something like make fmt after each save is an acceptably performant solution.

I believe the "correct" solution for formatting a single file is to run cargo metadata --no-deps --offline --format-version 1 to defer to Cargo's machinery for finding Cargo.toml, parse the JSON it returns, and then call rustfmt with that path... with the caveat that there's no package_root key so, to get the package root instead of the workspace root, it looks like you have to derive it from the manifest_path.

The relevant parts of a non-workspace (i.e. single-package) project look like this:

{
    "packages": [{
        // ...
        "targets": [{
            // ...
            "src_path": "/home/ssokolow/src/hello/src/main.rs",
            // ...
        }],
        // ...
        "manifest_path": "/home/ssokolow/src/hello/Cargo.toml",
        // ...
    }],
    // ...
    "workspace_root": "/home/ssokolow/src/hello",
    // ...
}

With a workspace project, manifest_path will point to something like /home/ssokolow/src/hello/subproject_a/Cargo.toml while workspace_root continues to point to /home/ssokolow/src/hello and, since I'm only just getting to the point where workspaces would become useful for me, I haven't checked what lookup algorithm cargo fmt uses to find rustfmt.toml from those produce rustfmt's --config-path in a workspace project.

Their README just says this without clarifying whether "the project" means the package root or the workspace root in a workspace-based configuration:

Rustfmt is designed to be very configurable. You can create a TOML file called rustfmt.toml or .rustfmt.toml, place it in the project or any other parent directory and it will apply the options in that file.

(If you're OK with having looked at MIT-licensed code, given your 2BSD license, you could look at how https://github.com/rust-lang/rust.vim does it. That's what the rustfmt repo points people at for Vim integration... I just don't want all that overlap with my existing cross-language plugins for everything other than format-on-save.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants
0