Rust-analyzer, cargo workspaces and members (in Helix editor)

Hi all,

I'm trying to use rust-analyzer (with the helix text editor, if that matters at all), in a cargo workspace with multiple members.
I tried many things, but I can't seem to get this to work: I'd like to get diagnostics only for a given member of the workspace, that I'm currently working on.
My issue is that I'm doing some pretty massive refactoring, and I get diagnostics from multiple members of the cargo workspace all the time, making it pretty difficult to track what I'm doing on the single member I'm working on.
For now, my solution is to have a second terminal open and run cargo check on my workspace member... which I'd love to replace with some rust-analyzer goodness.

Thanks !

EDIT: forgot to say that yes, I open helix in the workspace member directly, something like hx . when I'm in worspace_root/workspace_member_A/

Disclaimer: Didn't test, nor intend to.

You seem to want diagnostics on single member, so check out User Manual for disabling workspace like rust-analyzer.check.workspace or somthing. Plus, you should know how to tweak LSP config in helix Languages (specifically for where to put the config file and the field conversion from JSON to TOML).

Hi ! Thanks for responding.
I've tried setting this check.workspace = false, and also these:

  • check.invocationLocation="package"
  • check.invocationStrategy="once"
  • linkedProjects =["/path/to/my/workspace/member/Cargo.toml"]

I also set this check.overrideCommand="cargo check --message-format=json" because the docs say that invocationLocation or invocationStrategy have no effect unless you set it.

I've also tried this workspace-lsp-roots = ["/path/to/my/workspace/member/"] in the languages.toml "local" config of helix, which is a file located at: /path/to/my/workspace/member/.helix/languages.toml.
Still, no luck...

In helix logs, I see this line:

2024-04-21T19:30:42.850 helix_lsp::transport [INFO] rust-analyzer <- {"jsonrpc":"2.0","id":2,"method":"client/registerCapability","params":{"registrations":[{"id":"workspace/didChangeWatchedFiles","method":"workspace/didChangeWatchedFiles","registerOptions":{"watchers":[{"globPattern":"/path/to/my/workspace/OTHERmember1/**/*.rs"},{"globPattern":"/path/to/my/workspace/OTHERmember1/**/Cargo.toml"},{"globPattern":"/path/to/my/workspace/OTHERmember1**/Cargo.lock"},{"globPattern":"/path/to/my/workspace/member/**/*.rs"},{"globPattern":"/path/to/my/workspace/member/**/Cargo.toml"},{"globPattern":"/path/to/my/workspace/member/**/Cargo.lock"},{"globPattern":"/path/to/my/workspace/OTHERmember2/**/*.rs"},{"globPattern":"/path/to/my/workspace/OTHERmember2/**/Cargo.toml"},{"globPattern":"/path/to/my/workspace/OTHERmember2/**/Cargo.lock"}]}}]}}

which makes me think that maybe the config is ignored ?

So I've fiddled with RA's configuration for a while, and here's what I've found:

To override the behavior by checking on single member:

  • "rust-analyzer.check.overrideCommand": "cargo check --message-format=json -p one-member" can be used to only check for one-member package
  • "rust-analyzer.check.overrideCommand": "cargo check --message-format=json" can be used to check the current package, which is useful for the following case:
    • You want diagnostics only from single package from which files are being saved, with other members opened, edited and analyzed, but no diagnostics from them.

overrideCommand seems to have highest priority, so no need to use "rust-analyzer.check.workspace": false again. (I've tested it. workspace = false and overrideCommand = "cargo check --message-format=json" work the same, because check.workspace = false just strip --workspace argument from check command.)

For your case, setting check.workspace to false can be enough.


Settings you mentioned

  • "rust-analyzer.check.invocationStrategy"
    • by default, the value is "per_workspace", meaning cargo check (even with no workspace argument) will be run for each workspace. If your project consists of multi-workspace, RA still checks for other packages, because RA still tries to invoke cago-check multiple times.
    • you can set it to "once" to run check only once anyway
  • "rust-analyzer.check.invocationLocation"
    • "workspace" by default: I think it's just because RA by default run check for workspace
    • "root": a bit confusing, but I think it means root for a package, not necessary to be a root of a workspace. But the documentation says project’s root directory, so what is project in this context? IDK
      • invocationStrategy = once implies invocationLocation = root
      • but I don't what's point of this setting: workspace = false or overrideCommand = "cargo check --message-format=json" works fine without setting it to "root"
  • "rust-analyzer.linkedProjects"
    • it's for non-cargo project, an example of this is rustlings lsp will generate a rust-project.json file to make RA work, since rustlings contains a collection of exercises with non-cargo layout; each exercise are single file (there are some exceptions in it, so non-cargo layout is a bit inaccurate, strictly speaking, "rust-analyzer.linkedProjects" are for mixed layouts).
    • if your project are already based on cargo layout, RA seems to work on cargo layout anyway, even though you force linkedProjects layout
    • at least in my testing, if a package is a member of workspace, linkedProjects or rust-project.json has no effect; if a package is an exclusion of workspace, they do work.

config loading

I think this would be a big problem and cause great time waste if people're unaware of /unfamiliar to how to load config on your IDE/editor/plugin.

For myself, when testing the settings above, I was hindered by these

  • in cargo project layout, I incorrectly expected rust-analyzer.json in member package folder to work for the member, but in reality
    • the config file for workspace members should be in root of the workspace to work
    • in non-cargo layout (like a package exluded from workspace), the config file in the isolated package should just work
  • the loading bugs: I use plugins in neovim to config RA, so there are several ways/places to write RA settings, but I may notice check.workspace = false works globally but not locally:
    • sometimes I have to manually reload local config to see it work
      • if you didn't know it work, you'll never try to make it work :slight_smile:

Thanks a lot for all your time and answers.

I'm leaning towards me not understanding my editor well enough, like you mentioned. I tried everything you said, and many other combinations (changing where I put the helix configs, using rust-analyzer.json, or even setting the RA options globally), but that still won't work.
This pull request seems to suggest that you're right and check.workspace is exactly the setting I need

One thing that is weird to me is that there are two (what they call) pickers in helix, for diagnostics. The "document" one, with space + d, and the "global" or "workspace" one, with space + D. What I was trying to do is get my package diagnostics in the "global" one. Maybe I misinterpreted what the "workspace picker" was about ?

Anyway, since you tested it and made it work in nvim, it's probably a helix issue if not an issue between my chair and my keyboard !
Thanks again for helping, I can mark your answer as the solution I think.

Well, on my old helix (23.10), space + d shows current diagnostics directly. (space+D for diagnostics from all workspace members.) So you might not need to config anything for RA.

I'm not using workspaces and space-d gives me errors in just the active buffer, while space-D gives errors in all buffers. Are you sure that's not what you're seeing?

1 Like

:sweat_smile: You're right. I can comfirm that too. I didn't test multi-files in a member package.

Helix should describe space + d as Open diagnostic picker for current buffer/document/file only instead of Open diagnostic picker.

So I've also confirmed check.workspace = false works for mere single member. (Though I vaguely remember it didn't work for a while this morning. Anyway, it works now.)

# $PROJECT/.helix/languages.toml
[language-server.rust-analyzer.config]
check.workspace = false

Update: with the setting, it seems the diagnostics are from all members the first time they are seen, after several edits on the file, the diagnostics are finally from one member. The same behavior appears on nvim, which I though was a config loading delay.

check.workspace-false

Update: reported the bug in RA repo Setting check.workspace to false still emits diagnostics from all members the first time they are seen · Issue #17126 · rust-lang/rust-analyzer · GitHub

1 Like

Ha, so it was a bug then ? I agree with you in the issue you made on GH (thanks for doing that btw) that this is not what I expect when using RA that way.
Maybe I have not edited the file in my project enough times then (you mention that it needs several edits to work as we expect it).
I remember at some point thinking that it finally worked (had been trying for a while without closing the editor I think), only for the behavior I don't want to be back the next time I used helix. Maybe it's what you describe with the many edits.
I'll try again today and update. Thanks a lot !

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.