bug: inconsistent formatting when using `rustfmt` through `conform` as opposed to the shell
Neovim version (nvim -v)
v0.10.0 (tag commit)
Operating system/version
Ubuntu 20.04
Add the debug logs
- [X] I have set
log_level = vim.log.levels.DEBUGand pasted the log contents below.
Log file
Logs when running require("conform").format({ async = true, lsp_fallback = false }) on this file look normal:
02:30:13[DEBUG] Running formatters on /home/thomas/Documents/Coding/openraft/openraft/src/storage/v2.rs: { "rustfmt" }
02:30:13[INFO] Run rustfmt on /home/thomas/Documents/Coding/openraft/openraft/src/storage/v2.rs
02:30:13[DEBUG] Run command: { "/home/thomas/.cargo/bin/rustfmt", "--emit=stdout", "--edition=2021" }
02:30:13[DEBUG] rustfmt exited with code 0
Describe the bug
When I run the command /home/thomas/.cargo/bin/rustfmt -emit=stdout -edition=2021 in the shell, I get correct formatting. When this same command is run in nvim through conform.nvim, the result is inconsistent; formatting is correct at times, but not at others. I thought it was a matter of finding the rustfmt.toml at first, but when I set --config-path to the
rustfmt.toml file, the issue persists. The differences in formatting are all to do with function signatures, e.g. (green is the incorrect output of conform), which makes me think it's a matter of using the wrong rustfmt.toml (even though I explicitly pass its path):
- async fn try_get_log_entry(&mut self, log_index: u64) -> Result<Option<C::Entry>, StorageError<C::NodeId>> {
+ async fn try_get_log_entry(
+ &mut self,
+ log_index: u64,
+ ) -> Result<Option<C::Entry>, StorageError<C::NodeId>> {
What is the severity of this bug?
breaking (some functionality is broken)
Steps To Reproduce
The keybind that triggers the bug is:
{
"<leader>bf",
function()
require("conform").format({ async = false, lsp_fallback = false })
end,
mode = "",
desc = "[B]uffer (or selection) [F]ormat",
},
I pointed rustfmt to a specific binary to rule out shell sourcing shenanigans, using the following config in conform.nvim:
formatters_by_ft = {
rust = { "rustfmt" },
},
formatters = {
rustfmt = {
command = vim.fn.expand("~") .. "/.cargo/bin/rustfmt",
prepends_args = { "--config-path", "/home/thomas/Documents/Coding/openraft/rustfmt.toml" },
},
},
but this did not fix the bug consistently.
Contents of rustfmt.toml: https://github.com/datafuselabs/openraft/blob/main/rustfmt.toml
Expected Behavior
Formatting should be consistent between the shell and conform invocations of rustfmt
Minimal example file
No response
Minimal init.lua
-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")
-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end
-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"--single-branch",
"https://github.com/folke/lazy.nvim.git",
lazypath,
})
end
vim.opt.runtimepath:prepend(lazypath)
-- install plugins
local plugins = {
"folke/tokyonight.nvim",
{
"stevearc/conform.nvim",
config = function()
require("conform").setup({
log_level = vim.log.levels.DEBUG,
-- add your config here
})
end,
},
-- add any other plugins here
{
"stevearc/conform.nvim",
lazy = false,
keys = {
{
"<leader>bf",
function()
require("conform").format({ async = false, lsp_fallback = false })
end,
mode = "",
desc = "[B]uffer (or selection) [F]ormat",
},
},
opts = {
notify_on_error = false,
formatters_by_ft = {
lua = { "stylua" },
rust = { "rustfmt" },
},
formatters = {
rustfmt = {
command = vim.fn.expand("~") .. "/.cargo/bin/rustfmt",
},
},
log_level = 1,
},
}
}
require("lazy").setup(plugins, {
root = root .. "/plugins",
})
vim.cmd.colorscheme("tokyonight")
-- add anything else here
Additional context
No response
Check that you are running the command line program from the same cwd that you're opening vim from. If the same binary is producing different output when fed the same stdin, arguments, and when run in the same cwd, then something very weird is going on. I suspect that instead there is something different in how the commands are run.
Yep, you're right, changing the cwd in nvim fixes the issue. Before, I was running from ~, which triggers wrong formatting. If I cd to the basedir of the file, all works fine.
The weird thing though is that in the terminal, the cwd seems to have no impact on the result; running /home/thomas/.cargo/bin/rustfmt --edition=2021 [--emit=stdout]* ~/Documents/Coding/openraft/openraft/src/storage/v2.rs from ~ does work, whereas through conform it does not. The only other thing I can think of (with low confidence, given that I just diagonally read some of the conform code) is that using relative file paths here in the codebase somehow confuses rustfmt into checking the wrong folder for the rustfmt.toml file, and coming up empty.
Adding the following workaround to the config of rustfmt does fix the issue for me, it seems:
cwd = function(self, ctx)
local root = require("conform.util").root_file({ "rustfmt.toml", ".rustfmt.toml" })
print("root found:", vim.inspect(root(self, ctx)))
return root(self, ctx)
end,
Great! I've added that as part of the default config