Skip to content

feat(language_server/vscode): support multi workspace folder setups#10515

Closed
Sysix wants to merge 1 commit intomainfrom
04-20-feat_language_server_support_multiple_workspaces
Closed

feat(language_server/vscode): support multi workspace folder setups#10515
Sysix wants to merge 1 commit intomainfrom
04-20-feat_language_server_support_multiple_workspaces

Conversation

@Sysix
Copy link
Member

@Sysix Sysix commented Apr 20, 2025

Server Side Changes

As a Server, we need to make sure we follow the LSP specifications. So can not make changes in VSCode and implement them in the language server.

initialize

Check if a custom configuration is passed with initialization_options. Not every Client will send a configuration and expect that the server will request them with workspace/configuration.

We still uses root_uri as a fallback for older clients which do not support workspace folders.

Every use case tries to have a good fallback when something is wrong.

Change Configuration

The Client is sending a Custom Configuration to the Client. Not every Client will send it. So we request for the specific workspace configuration and update them.

Workspace Folder Change

This is new and should be self explained.

Client (VSCode Side Changes)

Changed Configuration scopes

This should reflect what the server will support.

screenshot

onConfigChange

We are now making sure that we check for every possible configuration. Custom User Configuration we will ignore.

Testing

Testing will be done with #10648.
We need to change the test structure to different between multi root setups and normal setups.
Not every test should be executed twice.

I tried to test every use case with VSCode possible and only found one problem.
When we add a workspace folder with an already defined oxc.configPath, we want to restart the server, but the onConfigChange event will already fire workspace/didChangeConfiguration request. This will result into a small error window, but still works perfectly.
We should avoid restarting the server when we need to create new file watchers. There are some workarounds that the server needs to support first. This is a task for later :)

Copy link
Member Author

Sysix commented Apr 20, 2025


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@codspeed-hq
Copy link

codspeed-hq bot commented Apr 20, 2025

CodSpeed Instrumentation Performance Report

Merging #10515 will not alter performance

Comparing 04-20-feat_language_server_support_multiple_workspaces (01cc2e4) with main (315143a)

Summary

✅ 36 untouched benchmarks

@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch 3 times, most recently from 63a5aff to 028d74c Compare April 21, 2025 17:33
@Sysix Sysix force-pushed the 04-18-feat_language_server_support_multiple_workspaces branch from ef3d0b1 to 94f0d9d Compare April 21, 2025 19:38
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch 3 times, most recently from 4668bd3 to 0b6b1f1 Compare April 21, 2025 21:36
@Sysix Sysix changed the base branch from 04-18-feat_language_server_support_multiple_workspaces to graphite-base/10515 April 22, 2025 17:19
@Sysix Sysix force-pushed the graphite-base/10515 branch from 94f0d9d to 327d41f Compare April 22, 2025 18:27
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch from 0b6b1f1 to 55d5a6c Compare April 22, 2025 18:27
@Sysix Sysix changed the base branch from graphite-base/10515 to 04-18-feat_language_server_support_multiple_workspaces April 22, 2025 18:27
@Sysix Sysix changed the base branch from 04-18-feat_language_server_support_multiple_workspaces to graphite-base/10515 April 23, 2025 17:04
@Sysix Sysix force-pushed the graphite-base/10515 branch from 327d41f to e9e176a Compare April 23, 2025 18:55
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch from 55d5a6c to a851e3b Compare April 23, 2025 18:55
@Sysix Sysix changed the base branch from graphite-base/10515 to 04-23-refactor_editor_split_config_to_vscodeconfig_and_workspaceconfig April 23, 2025 18:55
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch from a851e3b to f151e2e Compare April 23, 2025 19:16
@Sysix Sysix force-pushed the 04-23-refactor_editor_split_config_to_vscodeconfig_and_workspaceconfig branch 2 times, most recently from 284836b to 52bfc01 Compare April 24, 2025 16:49
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch 2 times, most recently from 8ffa8d6 to 30437da Compare April 25, 2025 12:36
@Sysix Sysix force-pushed the 04-23-refactor_editor_split_config_to_vscodeconfig_and_workspaceconfig branch from 52bfc01 to d9a77d9 Compare April 25, 2025 12:36
@graphite-app graphite-app bot changed the base branch from 04-23-refactor_editor_split_config_to_vscodeconfig_and_workspaceconfig to graphite-base/10515 April 25, 2025 12:42
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch 2 times, most recently from 05ed2c1 to 6c24b23 Compare April 29, 2025 12:40
@Sysix
Copy link
Member Author

Sysix commented Apr 29, 2025

Thanks for testing it out.
There is a problem with nested configuration, which is already in the main branch.
Created one test which passes for some reason, but fails in real world. Will look into it :)

EDIT: it is fixed in main and this PR is restacked

@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch from 6c24b23 to 74d4a12 Compare April 29, 2025 14:57
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch from 74d4a12 to 08c162b Compare April 29, 2025 15:20
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch from 08c162b to b7cdaa9 Compare April 29, 2025 17:26
@Sysix Sysix force-pushed the 04-20-feat_language_server_support_multiple_workspaces branch from b7cdaa9 to 01cc2e4 Compare April 29, 2025 17:46
@nrayburn-tech
Copy link
Collaborator

Re-tested within IntelliJ today and didn't notice any issues. Both nested config and specific config path support seems to be working. I don't think I'll be able to review the actual code changes here, but general usage seemed fine for me.

I did find that IntelliJ does have some support for the workspace concept, but I'm not sure if that means it supports LSP workspaces. https://blog.jetbrains.com/idea/2024/08/workspaces-in-intellij-idea/
In either case, I didn't do any workspace testing.

@Boshen
Copy link
Member

Boshen commented May 1, 2025

@camc314 can you merge after testing this PR manually?

@camc314
Copy link
Contributor

camc314 commented May 1, 2025

@Sysix , mind clarifying how this is meant to work? I think i'm just doing something wront while testing though.

I tested on https://github.com/oxc-project/oxc-intellij-plugin/tree/main/sandbox, added a sandbox.code-workspace, opened the folder as a workspace, however On the left hand side, I've got no-debugger: allow, however the warning is still there? likewise, the warning for curly is missing on the left.

This is my sandbox.code-workspace file

{
    "folders": [
      {
        "path": "custom-config"
      },
      {
        "path": "nested-configs"
      }
    ]
  }
Screenshot 2025-05-01 at 09 43 01

@Sysix
Copy link
Member Author

Sysix commented May 1, 2025

@Sysix , mind clarifying how this is meant to work? I think i'm just doing something wront while testing though.

I tested my changes with the following changes:

In C:\Users\sysix\.....\settings.json I use the debug server with extra information.
So I am sure I always use the debug language server for every editor instance.

{
  "oxc.path.server": "/home/sysix/dev/oxc/editors/vscode/target/debug/oxc_language_server",
  "oxc.trace.server": "verbose"
}

I am also updating the docs to clarify how to use the debug version: oxc-project/website#357

Then add / remove folders to the workspace with the explorer:

grafik

Add another Git Repo:
grafik

When you're in single folder mode and adding a folder, VSCode will restart the window on my side.
The real testing can only be done with 2 or more folders.

workspace-folders-add

Every workspace folder can be configured by its own Options:

workspace-folders-configuration

Comment on lines +458 to +462
let Ok(configs) = self.client.configuration(config_items).await else {
debug!("failed to get configuration");
// return none for each workspace folder
return vec![None; length];
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
let Ok(configs) = self.client.configuration(config_items).await else {
debug!("failed to get configuration");
// return none for each workspace folder
return vec![None; length];
};
let configs = match self.client.configuration(config_items).await {
Ok(config) => config,
Err(e) => {
debug!("failed to get configuration {e:?}");
return vec![None; length];
}
};

i think it would be ideal that the error is logged here?

@camc314
Copy link
Contributor

camc314 commented May 1, 2025

thanks - been debugging this trying to work out whats going on, I keep on seeing the following, when running this (i changed the code slightly to add more logging, but the lsp gets the workspace folders, but fails to get configuration - error server not initiaizlized

2025-05-01 17:53:18.005 [info] [2025-05-01T16:53:18Z INFO  oxc_language_server] initialize Some(Object {"settings": Object {"run": String("onType"), "configPath": String("./custom-oxlint.jsonc"), "flags": Object {}}})

2025-05-01 17:53:18.005 [info] [2025-05-01T16:53:18Z INFO  oxc_language_server] initialize: Options { run: OnType, config_path: Some("./custom-oxlint.jsonc"), flags: {} }
[2025-05-01T16:53:18Z INFO  oxc_language_server] language server version: "0.16.8"

2025-05-01 17:53:18.005 [info] [2025-05-01T16:53:18Z INFO  oxc_language_server] workspace folders: Some([WorkspaceFolder { uri: Uri(Uri { scheme: Some("file"), authority: Some(Authority { userinfo: None, host: Host { text: "", data: RegName("") }, port: None }), path: "/Users/cameron/github/tmp/oxc-intellij-plugin/sandbox/custom-config", query: None, fragment: None }), name: "custom-config" }, WorkspaceFolder { uri: Uri(Uri { scheme: Some("file"), authority: Some(Authority { userinfo: None, host: Host { text: "", data: RegName("") }, port: None }), path: "/Users/cameron/github/tmp/oxc-intellij-plugin/sandbox/nested-configs", query: None, fragment: None }), name: "nested-configs" }, WorkspaceFolder { uri: Uri(Uri { scheme: Some("file"), authority: Some(Authority { userinfo: None, host: Host { text: "", data: RegName("") }, port: None }), path: "/Users/cameron/github/tmp/nodejs-loaders", query: None, fragment: None }), name: "nodejs-loaders" }])
[2025-05-01T16:53:18Z INFO  oxc_language_server] capabilities.workspace_configuration: true

2025-05-01 17:53:18.005 [info] [2025-05-01T16:53:18Z INFO  oxc_language_server] failed to get configuration Error { code: ServerError(-32002), message: "Server not initialized", data: None }
[2025-05-01T16:53:18Z INFO  oxc_language_server] configs [None, None, None]

2025-05-01 17:53:18.040 [info] [2025-05-01T16:53:18Z INFO  oxc_language_server] workers [Some(Uri(Uri { scheme: Some("file"), authority: Some(Authority { userinfo: None, host: Host { text: "", data: RegName("") }, port: None }), path: "/Users/cameron/github/tmp/oxc-intellij-plugin/sandbox/custom-config", query: None, fragment: None }))Mutex { data: Options { run: OnType, config_path: None, flags: {} } }, Some(Uri(Uri { scheme: Some("file"), authority: Some(Authority { userinfo: None, host: Host { text: "", data: RegName("") }, port: None }), path: "/Users/cameron/github/tmp/oxc-intellij-plugin/sandbox/nested-configs", query: None, fragment: None }))Mutex { data: Options { run: OnType, config_path: None, flags: {} } }, Some(Uri(Uri { scheme: Some("file"), authority: Some(Authority { userinfo: None, host: Host { text: "", data: RegName("") }, port: None }), path: "/Users/cameron/github/tmp/nodejs-loaders", query: None, fragment: None }))Mutex { data: Options { run: OnType, config_path: None, flags: {} } }]

The error comes from tower_lsp_server, so it never actually goes to vscode. do we need to do this init logic after the server is initiialzied.

tower code:

    /// Sends a custom request to the client.
    ///
    /// # Initialization
    ///
    /// If the request is sent to the client before the server has been initialized, this will
    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
    ///
    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
    pub async fn send_request<R>(&self, params: R::Params) -> jsonrpc::Result<R::Result>
    where
        R: lsp_types::request::Request,
    {
        if let State::Initialized | State::ShutDown = self.inner.state.get() {
            self.send_request_unchecked::<R>(params).await
        } else {
            let id = i64::from(self.inner.request_id.load(Ordering::SeqCst)) + 1;
            let msg = Request::from_request::<R>(id.into(), params);
            trace!("server not initialized, supressing message: {}", msg);
            Err(jsonrpc::not_initialized_error())
        }
    }

@Sysix
Copy link
Member Author

Sysix commented May 1, 2025

Thanks for this info ❤️

I looked into the initialized request and hope to fix it with it. But I got some new problems on the way.
The workspace folders are only passed in the initialize request. We can pass a new object to initialization_options, which will include all configuration and will resolve the problem, but it is not expected from the clients (VSCode, Vim, JetBrains, ...). We need to make sure we get the right configuration fix_kind / nested_configs before creating the ServerLinter.

My Plan:
Check for the server's custom initialization_options configuration. If they passed a valid initialization_options, we will create the ServerLinter on initialize.
If the ServerLinter is not created, and we are in initialized request. Request the possible workspace configurations and create the ServerLinter. Use the fallback if not supported.

I guess we need to move WorkspaceWorker.options and WorkspaceWorker.nested_configs to WorkspaceWorker.server_linter. On the way, we can refactor the keys from oxc.flags to oxc.lint.flags. (Formatter flags in mind)

The configuration WorkspaceWorker.gitignore_glob will be interesting because with the inclusion of the
formatter it will change and should not include .eslintignore file.

This was mostly notes for me to get my problems / ideas structured. @camc314 and every other feel free to give some feedback.

Will start tomorrow and some new PRs to get the goal ❤️
If you guys want, you can close the 2 PRs and I will rebuild them. The changes will require some time.

@Sysix Sysix marked this pull request as draft May 1, 2025 20:20
@camc314
Copy link
Contributor

camc314 commented May 2, 2025

that sounds great, thank you for working on this! The code for this change looked good to me, just the issue with the client request during startup.

It's up to you if you would like to close this PR/create a new one

@Sysix Sysix closed this May 3, 2025
@Sysix Sysix deleted the 04-20-feat_language_server_support_multiple_workspaces branch May 8, 2025 18:31
graphite-app bot pushed a commit that referenced this pull request May 11, 2025
graphite-app bot pushed a commit that referenced this pull request May 11, 2025
graphite-app bot pushed a commit that referenced this pull request May 15, 2025
this was missed when coping the changes from #10515 to #10875
graphite-app bot pushed a commit that referenced this pull request May 15, 2025
…orkspace configuration is effected (#11017)

this was missed when coping the changes from #10515 to #10875
Boshen pushed a commit to oxc-project/oxc-vscode that referenced this pull request Feb 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-editor Area - Editor and Language Server C-enhancement Category - New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants