simrat39 / rust-tools.nvim

Tools for better development in rust using neovim's builtin lsp
MIT License
2.17k stars 160 forks source link

rust-analyzer initializes again when jumping to code outside of current workspace #421

Open GuillaumeLagrange opened 11 months ago

GuillaumeLagrange commented 11 months ago

Hello,

Whenever I am jumping to definition outside of current workspace, rust-analyzer seems to start a new instance on the jumped file's location, while leaving the current instance hanging until it has started.

This is an issue because rust-analyzer is extremely slow to start on large code bases, and I sometimes lose the LSP for ~1 minute.

It happens when I jump to definition of something in std (Default, or Vec for example), or whenever I jump to a dependency (inside or outside my monorepo workspace)

In VSCode, I do not have the issue. I am not sure how to troubleshoot the problem, maybe I am missing some config file ?

Is it possible to have RA run as single file mode for any code that is outside the scope of the initial root directory ? Or to blacklist some paths (std lib and cargo deps mainly) and prevent them from starting a full steam rust-analyzer ?

NicolasGB commented 9 months ago

Yeah i noticed the same, Even when setting the LSP to standalone=true, it launches a full new instance. I don't know either if its lsp or plugin related issue, but if you say that this does not happen with VSCode i guess it's the plugin?

mrcjkb commented 9 months ago

I can't reproduce this with jump-to-definition (using my fork), but it does happen when I'm in a project with multiple subpackages, and I open files from more than one of them. I think that is because the plugin searches upward for the first directory containing a Cargo.toml, and uses that as the workspace root.

mrcjkb commented 9 months ago

So, the solution in my fork was to call workspace/didChangeWorkspaceFolders.

This plugin uses lspconfig, which should call that method, too. But it also supports a "standalone" client that doesn't use lspconfig.

Also, support for it in rust-analyzer is fairly recent (since February, see https://github.com/rust-lang/rust-analyzer/pull/14098). Maybe the version you're using with Neovim is an older one?

GuillaumeLagrange commented 9 months ago

Thanks for your input.

lspconfig indeed seems to send the didChangeWorkspaceFolders and it adds the new folder ot the workspaces, as shown by

lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))

{ "/home/guillaume/${initialWorkspace}", "/home/guillaume/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc" }

The behavior I find irritating is therefore not a restart, but a sort of unresponsiveness after this for a short while. rust-analyzer seems to re initialize, and tries to build all proc macros and re indexes everything. It is especially weird since adding a package from the monorepo cargo workspace does not trigger this, it just addes the new package as a lsp workspace folder and does not trigger re-indexing and rebuilding proc macros whatsoever.

It is not really noticeable on small repos, but on large monorepos with tons of packages, it takes a good minute to be operational again, which painful.

Disabling cachePriming in rust-analyzer shortens this time, but does not make it disappear.

I will try with your plugin when I get some time, maybe reducing the number of actors in play by getting rid of lspconfig could help troubleshoot. Thanks anyway for trying to help :heart:

For anyone interested, my current workaround is preventing ra to start whenever a new workspace is to be added and its root contains a path that looks like a dependency

if string.find(new_root_dir, ".cargo/") or string.find(new_root_dir, ".rustup/toolchain") then
    return nil
end

It is not clean and I use a fork of a plugin used for local config to do so (neoconf), but it works on my machine️️ :tm:

mrcjkb commented 9 months ago

rust-analyzer seems to re initialize, and tries to build all proc macros and re indexes everything.

Interesting :thinking:.

I don't have a second rust-analyzer process spawning, but it does spawn a second rust-analyzer-proc-macro-srv (but there's only one LSP client in Neovim).

rust-analyzer-proc-macro-srv

And you say this doesn't happen in VSCode? Maybe there's a server configuration option...

For anyone interested, my current workaround is preventing ra to start whenever a new workspace is to be added and its root contains a path that looks like a dependency

This might also work if you set rust-analyzer.files.excludeDirs. In rust-tools, that would be the server["rust-analyzer"].files.excludeDirs config.

mrcjkb commented 9 months ago

Ha!

> rust-analyzer --help
# <...>
rust-analyzer diagnostics

  ARGS:
    <path>
      Directory with Cargo.toml.

  OPTIONS:
    --disable-build-scripts
      Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis.

    --disable-proc-macros
      Don't use expand proc macros.

    --proc-macro-srv <path>
      Run a custom proc-macro-srv binary.

... maybe we're onto something.

Update:

I have tried

  server = {
    ['rust-analyzer'] = {
      procMacro = {
        enable = false,
      },
    },
  },

to no avail :disappointed:

GuillaumeLagrange commented 9 months ago

I will try and bisect the exact differences between rust analyzer behavior in vs code and nvim for this and will update if I find anything significant.

In the meantime, preventing ra from spawning in dependencies/std has been wroking fine for a few weeks with very few downsides