diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index 361c5665d2..31554edd34 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -57,6 +57,25 @@ pub const DEFAULT_LSP_REQUEST_TIMEOUT: Duration = /// The shutdown timeout for LSP servers (including Prettier/Copilot). const SERVER_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5); +pub fn workspace_folder_for_uri(uri: Uri) -> WorkspaceFolder { + let name = uri + .to_file_path() + .ok() + .map(|path| { + let name = path.file_name().unwrap_or(path.as_os_str()); + name.to_string_lossy().into_owned() + }) + .filter(|name| !name.is_empty()) + .or_else(|| { + uri.path_segments() + .and_then(|mut segments| segments.rfind(|segment| !segment.is_empty())) + .map(str::to_owned) + }) + .unwrap_or_else(|| uri.as_str().to_owned()); + + WorkspaceFolder { uri, name } +} + type NotificationHandler = Box, Value, &mut AsyncApp)>; type PendingRespondTasks = Arc>>>; type ResponseHandler = Box) -> Task<()>>; @@ -747,21 +766,13 @@ impl LanguageServer { cx: &App, ) -> InitializeParams { let workspace_folders = self.workspace_folders.as_ref().map_or_else( - || { - vec![WorkspaceFolder { - name: Default::default(), - uri: self.root_uri.clone(), - }] - }, + || vec![workspace_folder_for_uri(self.root_uri.clone())], |folders| { folders .lock() .iter() .cloned() - .map(|uri| WorkspaceFolder { - name: Default::default(), - uri, - }) + .map(workspace_folder_for_uri) .collect() }, ); @@ -1625,10 +1636,7 @@ impl LanguageServer { if is_new_folder { let params = DidChangeWorkspaceFoldersParams { event: WorkspaceFoldersChangeEvent { - added: vec![WorkspaceFolder { - uri, - name: String::default(), - }], + added: vec![workspace_folder_for_uri(uri)], removed: vec![], }, }; @@ -1660,10 +1668,7 @@ impl LanguageServer { let params = DidChangeWorkspaceFoldersParams { event: WorkspaceFoldersChangeEvent { added: vec![], - removed: vec![WorkspaceFolder { - uri, - name: String::default(), - }], + removed: vec![workspace_folder_for_uri(uri)], }, }; self.notify::(params).ok(); @@ -1678,18 +1683,14 @@ impl LanguageServer { let old_workspace_folders = std::mem::take(&mut *workspace_folders); let added: Vec<_> = folders .difference(&old_workspace_folders) - .map(|uri| WorkspaceFolder { - uri: uri.clone(), - name: String::default(), - }) + .cloned() + .map(workspace_folder_for_uri) .collect(); let removed: Vec<_> = old_workspace_folders .difference(&folders) - .map(|uri| WorkspaceFolder { - uri: uri.clone(), - name: String::default(), - }) + .cloned() + .map(workspace_folder_for_uri) .collect(); *workspace_folders = folders; let should_notify = !added.is_empty() || !removed.is_empty(); @@ -2291,7 +2292,7 @@ mod tests { } #[gpui::test] - async fn test_initialize_params_has_root_path_and_root_uri(cx: &mut TestAppContext) { + async fn test_default_initialize_params(cx: &mut TestAppContext) { cx.update(|cx| { release_channel::init(semver::Version::new(0, 0, 0), cx); }); @@ -2306,6 +2307,9 @@ mod tests { Default::default(), &mut cx.to_async(), ); + let project_uri = Uri::from_file_path(std::env::temp_dir().join("my project")) + .expect("workspace folder URI should be valid"); + server.set_workspace_folders(BTreeSet::from_iter([project_uri.clone()])); let params = cx.update(|cx| server.default_initialize_params(false, false, cx)); @@ -2322,5 +2326,14 @@ mod tests { expected_path.to_string_lossy(), "root_path should be derived from root_uri" ); + let workspace_folders = params + .workspace_folders + .expect("workspace folders should be set"); + + let expected_workspace_folders = vec![WorkspaceFolder { + uri: project_uri, + name: "my project".to_string(), + }]; + assert_eq!(workspace_folders, expected_workspace_folders); } } diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index c1e5ca31f5..fee9666ec7 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -99,7 +99,7 @@ use lsp::{ LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf, RenameFilesParams, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles, - WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles, + WorkDoneProgressCancelParams, notification::DidRenameFiles, }; use node_runtime::read_package_installed_version; use parking_lot::Mutex; @@ -984,10 +984,7 @@ impl LocalLspStore { let root = server.workspace_folders(); Ok(Some( root.into_iter() - .map(|uri| WorkspaceFolder { - uri, - name: Default::default(), - }) + .map(lsp::workspace_folder_for_uri) .collect(), )) }