Skip to content

Commit 6f55318

Browse files
committed
Update neovim instructions for neovim 0.11+
1 parent c737fb6 commit 6f55318

1 file changed

Lines changed: 58 additions & 54 deletions

File tree

src/building/suggested.md

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -144,77 +144,81 @@ If running `./x check` on save is inconvenient, in VS Code you can use a [Build
144144

145145
### Neovim
146146

147-
For Neovim users, there are a few options.
148-
The easiest way is by using [neoconf.nvim](https://github.com/folke/neoconf.nvim/),
149-
which allows for project-local configuration files with the native LSP.
150-
The steps for how to use it are below.
151-
Note that they require rust-analyzer to already be configured with Neovim.
152-
Steps for this can be [found here](https://rust-analyzer.github.io/manual.html#nvim-lsp).
147+
For Neovim users, there are a few options:
148+
149+
1. The easiest way is using [neoconf.nvim](https://github.com/folke/neoconf.nvim/) but it uses the
150+
deprecated `require('lspconfig')` API which displays a warning on neovim 0.11+.
151+
2. Using `coc.nvim` is another option but it requires node.js to be installed.
152+
3. Using a custom script to load rust-analyzer settings.
153+
154+
#### neoconf.nvim
155+
156+
[neoconf.nvim](https://github.com/folke/neoconf.nvim/) allows for project-local configuration
157+
files with the native LSP. The steps for how to use it are below. Note that they require
158+
rust-analyzer to already be configured with Neovim. Steps for this can be
159+
[found here](https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp).
153160

154161
1. First install the plugin.
155162
This can be done by following the steps in the README.
156163
2. Run `./x setup editor`, and select `vscode` to create a `.vscode/settings.json` file.
157164
`neoconf` is able to read and update
158165
rust-analyzer settings automatically when the project is opened when this file is detected.
159166

167+
#### coc.nvim
168+
160169
If you're using `coc.nvim`, you can run `./x setup editor` and select `vim` to
161170
create a `.vim/coc-settings.json`.
162171
The settings can be edited with `:CocLocalConfig`.
163172
The recommended settings live at [`src/etc/rust_analyzer_settings.json`].
164173

165-
Another way is without a plugin, and creating your own logic in your configuration.
166-
The following code will work for any checkout of rust-lang/rust (newer than February 2025):
174+
#### Custom LSP settings
175+
176+
If you're running neovim 0.11+, you can configure rust-analyzer with just
177+
[nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) and a custom script.
178+
179+
1. Make sure rust-analyzer LSP is set up
180+
<https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp>
181+
2. Create `$HOME/.config/nvim/after/plugged/rust_analyzer.lua` with the following content:
167182

168183
```lua
169-
local function expand_config_variables(option)
170-
local var_placeholders = {
171-
['${workspaceFolder}'] = function(_)
172-
return vim.lsp.buf.list_workspace_folders()[1]
173-
end,
174-
}
175-
176-
if type(option) == "table" then
177-
local mt = getmetatable(option)
178-
local result = {}
179-
for k, v in pairs(option) do
180-
result[expand_config_variables(k)] = expand_config_variables(v)
181-
end
182-
return setmetatable(result, mt)
183-
end
184-
if type(option) ~= "string" then
185-
return option
186-
end
187-
local ret = option
188-
for key, fn in pairs(var_placeholders) do
189-
ret = ret:gsub(key, fn)
190-
end
191-
return ret
192-
end
193-
lspconfig.rust_analyzer.setup {
194-
root_dir = function()
195-
local default = lspconfig.rust_analyzer.config_def.default_config.root_dir()
196-
-- the default root detection uses the cargo workspace root.
197-
-- but for rust-lang/rust, the standard library is in its own workspace.
198-
-- use the git root instead.
199-
local compiler_config = vim.fs.joinpath(default, "../src/bootstrap/defaults/config.compiler.toml")
200-
if vim.fs.basename(default) == "library" and vim.uv.fs_stat(compiler_config) then
201-
return vim.fs.dirname(default)
184+
-- Capture the default functions from nvim-lspconfig/lsp/rust_analyzer.lua before overriding it.
185+
-- This file is in after/plugin to guarantee nvim-lspconfig has been initialised already.
186+
local default_root_dir = vim.lsp.config['rust_analyzer'].root_dir
187+
local default_before_init = vim.lsp.config['rust_analyzer'].before_init
188+
189+
vim.lsp.config('rust_analyzer', {
190+
cmd = { 'rust-analyzer' },
191+
filetypes = { 'rust' },
192+
-- To support rust_lang/rust, we need to detect when we're in the rust repo and use the git root
193+
-- instead of cargo project root.
194+
root_dir = function(bufnr, on_dir)
195+
local git_root = vim.fs.root(bufnr, { '.git' })
196+
if git_root then
197+
if vim.uv.fs_stat(vim.fs.joinpath(git_root, "src/etc/rust_analyzer_zed.json")) then
198+
on_dir(git_root)
199+
return
200+
end
202201
end
203-
return default
202+
-- For anything that doesn't match rust-lang/rust, fallback to default root_dir
203+
default_root_dir(bufnr, on_dir)
204204
end,
205-
on_init = function(client)
206-
local path = client.workspace_folders[1].name
207-
local config = vim.fs.joinpath(path, "src/etc/rust_analyzer_zed.json")
208-
if vim.uv.fs_stat(config) then
209-
-- load rust-lang/rust settings
210-
local file = io.open(config)
211-
local json = vim.json.decode(file:read("*a"))
212-
client.config.settings["rust-analyzer"] = expand_config_variables(json.lsp["rust-analyzer"].initialization_options)
213-
client.notify("workspace/didChangeConfiguration", { settings = client.config.settings })
205+
before_init = function(init_params, config)
206+
-- When inside rust_lang/rust, we need to use the special rust_analyzer settings.
207+
local settings = vim.fs.joinpath(config.root_dir, "src/etc/rust_analyzer_zed.json")
208+
if vim.uv.fs_stat(settings) then
209+
local file = io.open(settings)
210+
local content = file:read("*a")
211+
file:close()
212+
-- vim.json.decode doesn't support JSONC so we need strip out comments.
213+
content = content:gsub("//[^\n]*", "")
214+
local json = vim.json.decode(content)
215+
config.settings["rust-analyzer"] = json.lsp["rust-analyzer"].initialization_options
214216
end
215-
return true
216-
end
217-
}
217+
default_before_init(init_params, config)
218+
end,
219+
})
220+
221+
vim.lsp.enable('rust_analyzer')
218222
```
219223

220224
If you would like to use the build task that is described above, you may either

0 commit comments

Comments
 (0)