rust-lang / rust-analyzer

A Rust compiler front-end for IDEs
https://rust-analyzer.github.io/
Apache License 2.0
14.35k stars 1.62k forks source link

VSCode extension loads before direnv, doesn't notice direnv env vars #15852

Open lilyball opened 1 year ago

lilyball commented 1 year ago

rust-analyzer version: 0.3.1722-standalone

rustc version: rustc 1.73.0 (cc66ad468 2023-10-03)

relevant settings: VSCode extension, direnv extension installed as well

In my project, some of my dependencies can't build until I set some env vars first (things like telling it where to find cc). I use direnv with an .envrc to set the relevant variables. If I open my project, and then open a Rust file, rust-analyzer works fine. But if I already have a Rust file open when I open my project (or reload the window), rust-analyzer seems to load before direnv, and it doesn't notice when direnv sets env vars. This results in rust-analyzer failing to build proc macros. At this point, even if I run "rust-analyzer: Rebuild proc macros and build scripts" or "rust-analyzer: Reload workspace" it still fails. It's acting as though it snapshotted the env vars at the point where the extension loaded and doesn't notice that they've changed.

I think what's happening is it's starting the rust-analyzer server and then never communicating changed env vars to it. If I invoke "rust-analyzer: Stop server" and then "rust-analyzer: Start server" then it works (or if I restart the entire extension host).

So either the VSCode extension needs to tell rust-analyzer that env vars have changed, or if there's not a way to do that then it needs to restart the server if any relevant vars change.

I'd also accept as a stopgap measure a way to simply delay starting the rust-analyzer server until after the direnv extension has done its work, but I'm not sure if there's any way to do that. Somehow the CMake extension is delayed until after direnv, but I don't know if that's just a quirk of activation order.

Veykril commented 1 year ago

I assume direnv is used via a vscode extension here, so yes this requires vscode extension load order which funnily got raised here for rust-analyzer as well https://github.com/microsoft/vscode/issues/46846#issuecomment-718225990, and to no one's surprise this issue is out of scope in vscode and they didn't even give a reason for this...

Veykril commented 1 year ago

Would be neat to look into what the CMake extension does, assuming its not sheer luck t hat the load order hits just right there. Alternatively, we might be able to special case the direnv extension and require it to load first somehow (feels like that might be something the rust-analyzer can depend on?).

Not sure if we can notice env vars changing or not, but that would be another option that does seem reasonable as well.

lilyball commented 1 year ago

It's entirely possible that it's sheer luck. It's also possible that CMake is waiting for startup to finish before doing anything. When I look at the extension host logs it looks like

2023-11-10 10:48:14.097 [info] Extension host with pid 1323450 started
2023-11-10 10:48:14.102 [info] Lock '/home/lily/.vscode-server/data/User/workspaceStorage/cfda223b0785b6f8fb459fc845de2779/vscode.lock': Lock acquired.
2023-11-10 10:48:14.283 [info] ExtensionService#_doActivateExtension rust-lang.rust-analyzer, startup: false, activationEvent: 'onLanguage:rust'
2023-11-10 10:48:14.283 [info] ExtensionService#_doActivateExtension vscode.emmet, startup: false, activationEvent: 'onLanguage'
2023-11-10 10:48:14.836 [info] ExtensionService#_doActivateExtension vscode.git-base, startup: true, activationEvent: '*', root cause: vscode.git
2023-11-10 10:48:14.836 [info] ExtensionService#_doActivateExtension cab404.vscode-direnv, startup: true, activationEvent: '*'
2023-11-10 10:48:14.836 [info] ExtensionService#_doActivateExtension chrislajoie.vscode-modelines, startup: true, activationEvent: '*'
2023-11-10 10:48:14.836 [info] ExtensionService#_doActivateExtension EditorConfig.EditorConfig, startup: true, activationEvent: '*'
2023-11-10 10:48:14.836 [info] ExtensionService#_doActivateExtension fabiospampinato.vscode-todo-plus, startup: true, activationEvent: '*'
2023-11-10 10:48:14.837 [info] ExtensionService#_doActivateExtension geddski.macros, startup: true, activationEvent: '*'
2023-11-10 10:48:14.837 [info] ExtensionService#_doActivateExtension Tyriar.vscode-terminal-here, startup: true, activationEvent: '*'
2023-11-10 10:48:14.978 [info] ExtensionService#_doActivateExtension ms-dotnettools.vscode-dotnet-runtime, startup: true, activationEvent: 'workspaceContains:CMakeLists.txt', root cause: josetr.cmake-language-support-vscode
2023-11-10 10:48:15.035 [info] ExtensionService#_doActivateExtension ms-vscode.cmake-tools, startup: true, activationEvent: 'workspaceContains:CMakeLists.txt'

So rust-analyzer is actually ending up as the very first loaded extension. Apparently the onLanguage event is the very first event fired after starting the extension host? Which is kind of surprising. I assume the direnv extension does its work asynchronously but quickly.

I just tried reloading the window to pay attention, and it looks like the CMake extension isn't invoking cmake until after startup has finished, which gives the direnv extension plenty of time to do its work. So that's perhaps not so useful, assuming we don't want to delay launching the language server until onStartupFinished (which is about a 10 second delay for me in this workspace).

It looks like the direnv extension ultimately just sets keys on process.env. I don't know if there's any way to notice that. I don't know enough about extensions, maybe the direnv extension could be updated to emit some sort of event that rust-analyzer could then use to restart the server if any relevant env vars changed?

Or, if nothing else works, the rust-analyzer extension could add a hacky opt-in setting that just adds a delay to startup (either a fixed delay, or waiting until onStartupFinished).