lsp/python: Temporarily report just a singular workspace folder instead of all of the roots (#35243)
Temporarily fixes #29133 Co-authored-by: Cole <cole@zed.dev> Release Notes: - python: Zed now reports a slightly different set of workspace folders for Python projects to work around quirks in handling of multi-lsp projects with virtual environment. This behavior will be revisited in a near future. Co-authored-by: Cole <cole@zed.dev>
This commit is contained in:
parent
d2ef287791
commit
e5269212ad
5 changed files with 76 additions and 27 deletions
|
@ -313,6 +313,15 @@ impl Attach {
|
|||
}
|
||||
}
|
||||
|
||||
/// Determines what gets sent out as a workspace folders content
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum WorkspaceFoldersContent {
|
||||
/// Send out a single entry with the root of the workspace.
|
||||
WorktreeRoot,
|
||||
/// Send out a list of subproject roots.
|
||||
SubprojectRoots,
|
||||
}
|
||||
|
||||
/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
|
||||
// e.g. to display a notification or fetch data from the web.
|
||||
#[async_trait]
|
||||
|
@ -606,6 +615,13 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
Attach::Shared
|
||||
}
|
||||
|
||||
/// Determines whether a language server supports workspace folders.
|
||||
///
|
||||
/// And does not trip over itself in the process.
|
||||
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||
WorkspaceFoldersContent::SubprojectRoots
|
||||
}
|
||||
|
||||
fn manifest_name(&self) -> Option<ManifestName> {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -867,7 +867,7 @@ impl LspLogView {
|
|||
BINARY = server.binary(),
|
||||
WORKSPACE_FOLDERS = server
|
||||
.workspace_folders()
|
||||
.iter()
|
||||
.into_iter()
|
||||
.filter_map(|path| path
|
||||
.to_file_path()
|
||||
.ok()
|
||||
|
|
|
@ -4,13 +4,13 @@ use async_trait::async_trait;
|
|||
use collections::HashMap;
|
||||
use gpui::{App, Task};
|
||||
use gpui::{AsyncApp, SharedString};
|
||||
use language::Toolchain;
|
||||
use language::ToolchainList;
|
||||
use language::ToolchainLister;
|
||||
use language::language_settings::language_settings;
|
||||
use language::{ContextLocation, LanguageToolchainStore};
|
||||
use language::{ContextProvider, LspAdapter, LspAdapterDelegate};
|
||||
use language::{LanguageName, ManifestName, ManifestProvider, ManifestQuery};
|
||||
use language::{Toolchain, WorkspaceFoldersContent};
|
||||
use lsp::LanguageServerBinary;
|
||||
use lsp::LanguageServerName;
|
||||
use node_runtime::NodeRuntime;
|
||||
|
@ -400,6 +400,9 @@ impl LspAdapter for PythonLspAdapter {
|
|||
fn manifest_name(&self) -> Option<ManifestName> {
|
||||
Some(SharedString::new_static("pyproject.toml").into())
|
||||
}
|
||||
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||
WorkspaceFoldersContent::WorktreeRoot
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_cached_server_binary(
|
||||
|
@ -1282,6 +1285,9 @@ impl LspAdapter for PyLspAdapter {
|
|||
fn manifest_name(&self) -> Option<ManifestName> {
|
||||
Some(SharedString::new_static("pyproject.toml").into())
|
||||
}
|
||||
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||
WorkspaceFoldersContent::WorktreeRoot
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -29,7 +29,7 @@ use std::{
|
|||
ffi::{OsStr, OsString},
|
||||
fmt,
|
||||
io::Write,
|
||||
ops::{Deref, DerefMut},
|
||||
ops::DerefMut,
|
||||
path::PathBuf,
|
||||
pin::Pin,
|
||||
sync::{
|
||||
|
@ -100,7 +100,7 @@ pub struct LanguageServer {
|
|||
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
|
||||
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
||||
server: Arc<Mutex<Option<Child>>>,
|
||||
workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
|
||||
workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
|
||||
root_uri: Url,
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ impl LanguageServer {
|
|||
binary: LanguageServerBinary,
|
||||
root_path: &Path,
|
||||
code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||
workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
|
||||
workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<Self> {
|
||||
let working_dir = if root_path.is_dir() {
|
||||
|
@ -381,7 +381,7 @@ impl LanguageServer {
|
|||
code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||
binary: LanguageServerBinary,
|
||||
root_uri: Url,
|
||||
workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
|
||||
workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
|
||||
cx: &mut AsyncApp,
|
||||
on_unhandled_notification: F,
|
||||
) -> Self
|
||||
|
@ -595,16 +595,26 @@ impl LanguageServer {
|
|||
}
|
||||
|
||||
pub fn default_initialize_params(&self, pull_diagnostics: bool, cx: &App) -> InitializeParams {
|
||||
let workspace_folders = self
|
||||
.workspace_folders
|
||||
.lock()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|uri| WorkspaceFolder {
|
||||
name: Default::default(),
|
||||
uri,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let workspace_folders = self.workspace_folders.as_ref().map_or_else(
|
||||
|| {
|
||||
vec![WorkspaceFolder {
|
||||
name: Default::default(),
|
||||
uri: self.root_uri.clone(),
|
||||
}]
|
||||
},
|
||||
|folders| {
|
||||
folders
|
||||
.lock()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|uri| WorkspaceFolder {
|
||||
name: Default::default(),
|
||||
uri,
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
);
|
||||
|
||||
#[allow(deprecated)]
|
||||
InitializeParams {
|
||||
process_id: None,
|
||||
|
@ -1315,7 +1325,10 @@ impl LanguageServer {
|
|||
return;
|
||||
}
|
||||
|
||||
let is_new_folder = self.workspace_folders.lock().insert(uri.clone());
|
||||
let Some(workspace_folders) = self.workspace_folders.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let is_new_folder = workspace_folders.lock().insert(uri.clone());
|
||||
if is_new_folder {
|
||||
let params = DidChangeWorkspaceFoldersParams {
|
||||
event: WorkspaceFoldersChangeEvent {
|
||||
|
@ -1345,7 +1358,10 @@ impl LanguageServer {
|
|||
{
|
||||
return;
|
||||
}
|
||||
let was_removed = self.workspace_folders.lock().remove(&uri);
|
||||
let Some(workspace_folders) = self.workspace_folders.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let was_removed = workspace_folders.lock().remove(&uri);
|
||||
if was_removed {
|
||||
let params = DidChangeWorkspaceFoldersParams {
|
||||
event: WorkspaceFoldersChangeEvent {
|
||||
|
@ -1360,7 +1376,10 @@ impl LanguageServer {
|
|||
}
|
||||
}
|
||||
pub fn set_workspace_folders(&self, folders: BTreeSet<Url>) {
|
||||
let mut workspace_folders = self.workspace_folders.lock();
|
||||
let Some(workspace_folders) = self.workspace_folders.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let mut workspace_folders = workspace_folders.lock();
|
||||
|
||||
let old_workspace_folders = std::mem::take(&mut *workspace_folders);
|
||||
let added: Vec<_> = folders
|
||||
|
@ -1389,8 +1408,11 @@ impl LanguageServer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn workspace_folders(&self) -> impl Deref<Target = BTreeSet<Url>> + '_ {
|
||||
self.workspace_folders.lock()
|
||||
pub fn workspace_folders(&self) -> BTreeSet<Url> {
|
||||
self.workspace_folders.as_ref().map_or_else(
|
||||
|| BTreeSet::from_iter([self.root_uri.clone()]),
|
||||
|folders| folders.lock().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn register_buffer(
|
||||
|
@ -1535,7 +1557,7 @@ impl FakeLanguageServer {
|
|||
None,
|
||||
binary.clone(),
|
||||
root,
|
||||
workspace_folders.clone(),
|
||||
Some(workspace_folders.clone()),
|
||||
cx,
|
||||
|_| {},
|
||||
);
|
||||
|
@ -1554,7 +1576,7 @@ impl FakeLanguageServer {
|
|||
None,
|
||||
binary,
|
||||
Self::root_path(),
|
||||
workspace_folders,
|
||||
Some(workspace_folders),
|
||||
cx,
|
||||
move |msg| {
|
||||
notifications_tx
|
||||
|
|
|
@ -46,6 +46,7 @@ use language::{
|
|||
DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
|
||||
LanguageRegistry, LanguageToolchainStore, LocalFile, LspAdapter, LspAdapterDelegate, Patch,
|
||||
PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
|
||||
WorkspaceFoldersContent,
|
||||
language_settings::{
|
||||
FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, language_settings,
|
||||
},
|
||||
|
@ -217,6 +218,7 @@ impl LocalLspStore {
|
|||
|
||||
let binary = self.get_language_server_binary(adapter.clone(), delegate.clone(), true, cx);
|
||||
let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
|
||||
|
||||
let pending_server = cx.spawn({
|
||||
let adapter = adapter.clone();
|
||||
let server_name = adapter.name.clone();
|
||||
|
@ -242,14 +244,18 @@ impl LocalLspStore {
|
|||
return Ok(server);
|
||||
}
|
||||
|
||||
let code_action_kinds = adapter.code_action_kinds();
|
||||
lsp::LanguageServer::new(
|
||||
stderr_capture,
|
||||
server_id,
|
||||
server_name,
|
||||
binary,
|
||||
&root_path,
|
||||
adapter.code_action_kinds(),
|
||||
pending_workspace_folders,
|
||||
code_action_kinds,
|
||||
Some(pending_workspace_folders).filter(|_| {
|
||||
adapter.adapter.workspace_folders_content()
|
||||
== WorkspaceFoldersContent::SubprojectRoots
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
@ -575,8 +581,7 @@ impl LocalLspStore {
|
|||
};
|
||||
let root = server.workspace_folders();
|
||||
Ok(Some(
|
||||
root.iter()
|
||||
.cloned()
|
||||
root.into_iter()
|
||||
.map(|uri| WorkspaceFolder {
|
||||
uri,
|
||||
name: Default::default(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue