diff --git a/src/building/suggested.md b/src/building/suggested.md index 959d0687b..d9921cbb1 100644 --- a/src/building/suggested.md +++ b/src/building/suggested.md @@ -144,12 +144,19 @@ 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][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][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. First install the plugin. This can be done by following the steps in the README. @@ -157,64 +164,62 @@ Steps for this can be [found here](https://rust-analyzer.github.io/manual.html#n `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][r-a nvim lsp] is set up +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) +-- 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", { + 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 + -- 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 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) - 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. + 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) + -- nvim 0.12+ supports comments otherwise you'll need content:gsub("//[^\n]*", ""). + local json = vim.json.decode(file:read("*a"), { skip_comments = true }) + file:close() + config.settings["rust-analyzer"] = vim.tbl_deep_extend( + "force", -- Overwrite with the special settings when there is a conflict. + config.settings["rust-analyzer"] or {}, + 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 @@ -223,6 +228,9 @@ make your own command in your config, or you can install a plugin such as files](https://github.com/stevearc/overseer.nvim/blob/master/doc/guides.md#vs-code-tasks), and follow the same instructions as above. +[neoconf.nvim]: https://github.com/folke/neoconf.nvim/ +[r-a nvim lsp]: https://rust-analyzer.github.io/book/other_editors.html#nvim-lsp + ### Emacs Emacs provides support for rust-analyzer with project-local configuration