Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 58 additions & 54 deletions src/building/suggested.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,77 +144,81 @@ If running `./x check` on save is inconvenient, in VS Code you can use a [Build

### Neovim

For Neovim users, there are a few options.
The easiest way is by using [neoconf.nvim](https://github.com/folke/neoconf.nvim/),
which allows for project-local configuration files with the native LSP.
The steps for how to use it are below.
Note that they require rust-analyzer to already be configured with Neovim.
Steps for this can be [found here](https://rust-analyzer.github.io/manual.html#nvim-lsp).
For Neovim users, there are a few options:

1. The easiest way is using [neoconf.nvim](https://github.com/folke/neoconf.nvim/) but it uses the
deprecated `require('lspconfig')` API which displays a warning on neovim 0.11+.
2. Using `coc.nvim` is another option but it requires node.js to be installed.
3. Using a custom script to load rust-analyzer settings.

#### neoconf.nvim

[neoconf.nvim](https://github.com/folke/neoconf.nvim/) allows for project-local configuration
files with the native LSP. The steps for how to use it are below. Note that they require
rust-analyzer to already be configured with Neovim. Steps for this can be
[found here](https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp).
Comment on lines +149 to +159
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. The easiest way is using [neoconf.nvim](https://github.com/folke/neoconf.nvim/) but it uses the
deprecated `require('lspconfig')` API which displays a warning on neovim 0.11+.
2. Using `coc.nvim` is another option but it requires node.js to be installed.
3. Using a custom script to load rust-analyzer settings.
#### neoconf.nvim
[neoconf.nvim](https://github.com/folke/neoconf.nvim/) allows for project-local configuration
files with the native LSP. The steps for how to use it are below. Note that they require
rust-analyzer to already be configured with Neovim. Steps for this can be
[found here](https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp).
1. The easiest way is using [neoconf.nvim] but it uses the
deprecated `require('lspconfig')` API which displays a warning on neovim 0.11+.
2. Using `coc.nvim` is another option but it requires node.js to be installed.
3. Using a custom script to load rust-analyzer settings.
#### neoconf.nvim
[neoconf.nvim] allows for project-local configuration
files with the native LSP. The steps for how to use it are below. Note that they require
rust-analyzer to already be configured with Neovim. Steps for this can be
[found here](https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp).
[neoconf.nvim]: https://github.com/folke/neoconf.nvim/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels a bit strange to make a suggestion via GitHub suggest, so...

could you please change it so that the references to https://github.com/folke/neoconf.nvim/ and https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp
are placed at the end of the line and then applied?

like

[neoconf.nvim] allows for project-local configuration
files with the native LSP. The steps for how to use it are below. Note that they require
rust-analyzer to already be configured with Neovim. Steps for this can be
[found here][r-a nvim lsp].

(...)

1. Make sure rust-analyzer [LSP][r-a nvim lsp] is set up 

(...)

[neoconf.nvim]: https://github.com/folke/neoconf.nvim/
[r-a nvim lsp]: https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp

If a link is referenced multiple times, I think it would be better to manage it this way.


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

#### coc.nvim

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

Another way is without a plugin, and creating your own logic in your configuration.
The following code will work for any checkout of rust-lang/rust (newer than February 2025):
#### Custom LSP settings

If you're running neovim 0.11+, you can configure rust-analyzer with just
[nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) and a custom script.

1. Make sure rust-analyzer LSP is set up
<https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp>
2. Create `$HOME/.config/nvim/after/plugged/rust_analyzer.lua` with the following content:

```lua
local function expand_config_variables(option)
local var_placeholders = {
['${workspaceFolder}'] = function(_)
return vim.lsp.buf.list_workspace_folders()[1]
end,
}

if type(option) == "table" then
local mt = getmetatable(option)
local result = {}
for k, v in pairs(option) do
result[expand_config_variables(k)] = expand_config_variables(v)
end
return setmetatable(result, mt)
end
if type(option) ~= "string" then
return option
end
local ret = option
for key, fn in pairs(var_placeholders) do
ret = ret:gsub(key, fn)
end
return ret
end
lspconfig.rust_analyzer.setup {
root_dir = function()
local default = lspconfig.rust_analyzer.config_def.default_config.root_dir()
-- the default root detection uses the cargo workspace root.
-- but for rust-lang/rust, the standard library is in its own workspace.
-- use the git root instead.
local compiler_config = vim.fs.joinpath(default, "../src/bootstrap/defaults/config.compiler.toml")
if vim.fs.basename(default) == "library" and vim.uv.fs_stat(compiler_config) then
return vim.fs.dirname(default)
-- Capture the default functions from nvim-lspconfig/lsp/rust_analyzer.lua before overriding it.
-- This file is in after/plugin to guarantee nvim-lspconfig has been initialised already.
local default_root_dir = vim.lsp.config['rust_analyzer'].root_dir
local default_before_init = vim.lsp.config['rust_analyzer'].before_init

vim.lsp.config('rust_analyzer', {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with Lua, so is it correct that there is a difference between _ and - in vim.lsp.config('rust_analyzer', {, cmd = { 'rust-analyzer' },, config.settings["rust-analyzer"] = json.lsp["rust-analyzer"] and vim.lsp.enable('rust_analyzer')?

cmd = { 'rust-analyzer' },
filetypes = { 'rust' },
-- To support rust_lang/rust, we need to detect when we're in the rust repo and use the git root
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- To support rust_lang/rust, we need to detect when we're in the rust repo and use the git root
-- To support rust-lang/rust, we need to detect when we're in the rust repo and use the git root

-- instead of cargo project root.
root_dir = function(bufnr, on_dir)
local git_root = vim.fs.root(bufnr, { '.git' })
if git_root then
if vim.uv.fs_stat(vim.fs.joinpath(git_root, "src/etc/rust_analyzer_zed.json")) then
on_dir(git_root)
return
end
end
return default
-- For anything that doesn't match rust-lang/rust, fallback to default root_dir
default_root_dir(bufnr, on_dir)
end,
on_init = function(client)
local path = client.workspace_folders[1].name
local config = vim.fs.joinpath(path, "src/etc/rust_analyzer_zed.json")
if vim.uv.fs_stat(config) then
-- load rust-lang/rust settings
local file = io.open(config)
local json = vim.json.decode(file:read("*a"))
client.config.settings["rust-analyzer"] = expand_config_variables(json.lsp["rust-analyzer"].initialization_options)
client.notify("workspace/didChangeConfiguration", { settings = client.config.settings })
before_init = function(init_params, config)
-- When inside rust_lang/rust, we need to use the special rust_analyzer settings.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- When inside rust_lang/rust, we need to use the special rust_analyzer settings.
-- When inside rust-lang/rust, we need to use the special rust_analyzer settings.

local settings = vim.fs.joinpath(config.root_dir, "src/etc/rust_analyzer_zed.json")
if vim.uv.fs_stat(settings) then
local file = io.open(settings)
local content = file:read("*a")
file:close()
-- vim.json.decode doesn't support JSONC so we need strip out comments.
content = content:gsub("//[^\n]*", "")
local json = vim.json.decode(content)
config.settings["rust-analyzer"] = json.lsp["rust-analyzer"].initialization_options
end
return true
end
}
default_before_init(init_params, config)
end,
})

vim.lsp.enable('rust_analyzer')
```

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