-- rustaceanvim / rust-analyzer, matched to the VSCodium setup in ../../vscode/settings.json: -- clippy instead of cargo check, rustfmt on save, source.fixAll on save, hard tabs. -- -- Drop at: ~/.config/nvim/lua/plugins/rust.lua, and delete the rustaceanvim block -- from lua/plugins/init.lua — two lazy.nvim specs for the same plugin will fight. local timeout_ms = 2000 -- Equivalent of VS Code's "editor.codeActionsOnSave": { "source.fixAll.rust-analyzer" }. -- -- vim.lsp.buf.code_action{apply=true} is asynchronous, so from a BufWritePre autocmd -- the buffer is usually written before the edit arrives. buf_request_sync blocks, -- which is what makes this actually run before the write. -- -- Same caveat as in VS Code: this applies rust-analyzer's own fixes only. Lints that -- come from cargo check or clippy are not included — those still need `cargo fix` or -- `cargo clippy --fix` on the command line. local function apply_fix_all(bufnr) local client = vim.lsp.get_clients({ bufnr = bufnr, name = "rust-analyzer" })[1] if not client then return end local params = vim.lsp.util.make_range_params(0, client.offset_encoding) params.context = { only = { "source.fixAll" }, diagnostics = {} } local responses = vim.lsp.buf_request_sync(bufnr, "textDocument/codeAction", params, timeout_ms) if not responses then return end for _, response in pairs(responses) do for _, action in ipairs(response.result or {}) do -- A server may return the action unresolved, carrying only `data`; -- the edit then has to be fetched with a second request. if not action.edit and action.data then local resolved = client:request_sync("codeAction/resolve", action, timeout_ms, bufnr) action = (resolved and resolved.result) or action end if action.edit then vim.lsp.util.apply_workspace_edit(action.edit, client.offset_encoding) end end end end vim.api.nvim_create_autocmd("BufWritePre", { group = vim.api.nvim_create_augroup("rust_on_save", { clear = true }), pattern = "*.rs", callback = function(args) apply_fix_all(args.buf) -- VS Code's "editor.formatOnSave" for [rust]: rustfmt, driven by rust-analyzer. vim.lsp.buf.format({ bufnr = args.buf, timeout_ms = timeout_ms, filter = function(client) return client.name == "rust-analyzer" end, }) end, }) return { { "mrcjkb/rustaceanvim", version = "^6", -- No `ft = { "rust" }` here. It is dead weight next to lazy = false, and -- rustaceanvim's own docs advise against lazy-loading it by filetype: -- it installs the FileType handler that starts the LSP itself. lazy = false, config = function() vim.g.rustaceanvim = { server = { on_attach = function(client, bufnr) require("nvchad.configs.lspconfig").on_attach(client, bufnr) end, default_settings = { ["rust-analyzer"] = { cargo = { allFeatures = true }, checkOnSave = true, -- Matches "rust-analyzer.check.command": "clippy". check = { command = "clippy" }, }, }, }, } end, }, }