project: Add dynamic capabilities registration for "workspace/didChangeWorkspaceFolders" (#37005)

Smit Barmase created

Fixes missing capability registration for
"workspace/didChangeWorkspaceFolders".

```
WARN  [project::lsp_store] unhandled capability registration: Registration { id: "e288546c-4458-401a-a029-bbba759d5a71", method: "workspace/didChangeWorkspaceFolders", register_options: Some(Object {}) }
```

We already correctly send back events to server on workspace add and
remove by checking this capability.
https://github.com/zed-industries/zed/blob/cf89691b85e4652093548c0bf8b79d881e26562b/crates/lsp/src/lsp.rs#L1353


https://github.com/zed-industries/zed/blob/cf89691b85e4652093548c0bf8b79d881e26562b/crates/lsp/src/lsp.rs#L1388

Release Notes:

- N/A

Change summary

crates/lsp/src/lsp.rs           |  3 ++-
crates/project/src/lsp_store.rs | 26 ++++++++++++++++++++++++++
2 files changed, 28 insertions(+), 1 deletion(-)

Detailed changes

crates/lsp/src/lsp.rs 🔗

@@ -1383,7 +1383,8 @@ impl LanguageServer {
             self.notify::<DidChangeWorkspaceFolders>(&params).ok();
         }
     }
-    /// Add new workspace folder to the list.
+
+    /// Remove existing workspace folder from the list.
     pub fn remove_workspace_folder(&self, uri: Url) {
         if self
             .capabilities()

crates/project/src/lsp_store.rs 🔗

@@ -11702,6 +11702,20 @@ impl LspStore {
                 "workspace/didChangeConfiguration" => {
                     // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
                 }
+                "workspace/didChangeWorkspaceFolders" => {
+                    // In this case register options is an empty object, we can ignore it
+                    let caps = lsp::WorkspaceFoldersServerCapabilities {
+                        supported: Some(true),
+                        change_notifications: Some(OneOf::Right(reg.id)),
+                    };
+                    server.update_capabilities(|capabilities| {
+                        capabilities
+                            .workspace
+                            .get_or_insert_default()
+                            .workspace_folders = Some(caps);
+                    });
+                    notify_server_capabilities_updated(&server, cx);
+                }
                 "workspace/symbol" => {
                     let options = parse_register_capabilities(reg)?;
                     server.update_capabilities(|capabilities| {
@@ -11944,6 +11958,18 @@ impl LspStore {
                 "workspace/didChangeConfiguration" => {
                     // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
                 }
+                "workspace/didChangeWorkspaceFolders" => {
+                    server.update_capabilities(|capabilities| {
+                        capabilities
+                            .workspace
+                            .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
+                                workspace_folders: None,
+                                file_operations: None,
+                            })
+                            .workspace_folders = None;
+                    });
+                    notify_server_capabilities_updated(&server, cx);
+                }
                 "workspace/symbol" => {
                     server.update_capabilities(|capabilities| {
                         capabilities.workspace_symbol_provider = None