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
|
/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
|
||||||
// e.g. to display a notification or fetch data from the web.
|
// e.g. to display a notification or fetch data from the web.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -606,6 +615,13 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
Attach::Shared
|
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> {
|
fn manifest_name(&self) -> Option<ManifestName> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -867,7 +867,7 @@ impl LspLogView {
|
||||||
BINARY = server.binary(),
|
BINARY = server.binary(),
|
||||||
WORKSPACE_FOLDERS = server
|
WORKSPACE_FOLDERS = server
|
||||||
.workspace_folders()
|
.workspace_folders()
|
||||||
.iter()
|
.into_iter()
|
||||||
.filter_map(|path| path
|
.filter_map(|path| path
|
||||||
.to_file_path()
|
.to_file_path()
|
||||||
.ok()
|
.ok()
|
||||||
|
|
|
@ -4,13 +4,13 @@ use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{App, Task};
|
use gpui::{App, Task};
|
||||||
use gpui::{AsyncApp, SharedString};
|
use gpui::{AsyncApp, SharedString};
|
||||||
use language::Toolchain;
|
|
||||||
use language::ToolchainList;
|
use language::ToolchainList;
|
||||||
use language::ToolchainLister;
|
use language::ToolchainLister;
|
||||||
use language::language_settings::language_settings;
|
use language::language_settings::language_settings;
|
||||||
use language::{ContextLocation, LanguageToolchainStore};
|
use language::{ContextLocation, LanguageToolchainStore};
|
||||||
use language::{ContextProvider, LspAdapter, LspAdapterDelegate};
|
use language::{ContextProvider, LspAdapter, LspAdapterDelegate};
|
||||||
use language::{LanguageName, ManifestName, ManifestProvider, ManifestQuery};
|
use language::{LanguageName, ManifestName, ManifestProvider, ManifestQuery};
|
||||||
|
use language::{Toolchain, WorkspaceFoldersContent};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
use lsp::LanguageServerName;
|
use lsp::LanguageServerName;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
|
@ -400,6 +400,9 @@ impl LspAdapter for PythonLspAdapter {
|
||||||
fn manifest_name(&self) -> Option<ManifestName> {
|
fn manifest_name(&self) -> Option<ManifestName> {
|
||||||
Some(SharedString::new_static("pyproject.toml").into())
|
Some(SharedString::new_static("pyproject.toml").into())
|
||||||
}
|
}
|
||||||
|
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||||
|
WorkspaceFoldersContent::WorktreeRoot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_cached_server_binary(
|
async fn get_cached_server_binary(
|
||||||
|
@ -1282,6 +1285,9 @@ impl LspAdapter for PyLspAdapter {
|
||||||
fn manifest_name(&self) -> Option<ManifestName> {
|
fn manifest_name(&self) -> Option<ManifestName> {
|
||||||
Some(SharedString::new_static("pyproject.toml").into())
|
Some(SharedString::new_static("pyproject.toml").into())
|
||||||
}
|
}
|
||||||
|
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||||
|
WorkspaceFoldersContent::WorktreeRoot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -29,7 +29,7 @@ use std::{
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
fmt,
|
fmt,
|
||||||
io::Write,
|
io::Write,
|
||||||
ops::{Deref, DerefMut},
|
ops::DerefMut,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -100,7 +100,7 @@ pub struct LanguageServer {
|
||||||
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
|
io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
|
||||||
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
||||||
server: Arc<Mutex<Option<Child>>>,
|
server: Arc<Mutex<Option<Child>>>,
|
||||||
workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
|
workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
|
||||||
root_uri: Url,
|
root_uri: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ impl LanguageServer {
|
||||||
binary: LanguageServerBinary,
|
binary: LanguageServerBinary,
|
||||||
root_path: &Path,
|
root_path: &Path,
|
||||||
code_action_kinds: Option<Vec<CodeActionKind>>,
|
code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||||
workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
|
workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let working_dir = if root_path.is_dir() {
|
let working_dir = if root_path.is_dir() {
|
||||||
|
@ -381,7 +381,7 @@ impl LanguageServer {
|
||||||
code_action_kinds: Option<Vec<CodeActionKind>>,
|
code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||||
binary: LanguageServerBinary,
|
binary: LanguageServerBinary,
|
||||||
root_uri: Url,
|
root_uri: Url,
|
||||||
workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
|
workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
on_unhandled_notification: F,
|
on_unhandled_notification: F,
|
||||||
) -> Self
|
) -> Self
|
||||||
|
@ -595,16 +595,26 @@ impl LanguageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_initialize_params(&self, pull_diagnostics: bool, cx: &App) -> InitializeParams {
|
pub fn default_initialize_params(&self, pull_diagnostics: bool, cx: &App) -> InitializeParams {
|
||||||
let workspace_folders = self
|
let workspace_folders = self.workspace_folders.as_ref().map_or_else(
|
||||||
.workspace_folders
|
|| {
|
||||||
.lock()
|
vec![WorkspaceFolder {
|
||||||
.iter()
|
name: Default::default(),
|
||||||
.cloned()
|
uri: self.root_uri.clone(),
|
||||||
.map(|uri| WorkspaceFolder {
|
}]
|
||||||
name: Default::default(),
|
},
|
||||||
uri,
|
|folders| {
|
||||||
})
|
folders
|
||||||
.collect::<Vec<_>>();
|
.lock()
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|uri| WorkspaceFolder {
|
||||||
|
name: Default::default(),
|
||||||
|
uri,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
InitializeParams {
|
InitializeParams {
|
||||||
process_id: None,
|
process_id: None,
|
||||||
|
@ -1315,7 +1325,10 @@ impl LanguageServer {
|
||||||
return;
|
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 {
|
if is_new_folder {
|
||||||
let params = DidChangeWorkspaceFoldersParams {
|
let params = DidChangeWorkspaceFoldersParams {
|
||||||
event: WorkspaceFoldersChangeEvent {
|
event: WorkspaceFoldersChangeEvent {
|
||||||
|
@ -1345,7 +1358,10 @@ impl LanguageServer {
|
||||||
{
|
{
|
||||||
return;
|
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 {
|
if was_removed {
|
||||||
let params = DidChangeWorkspaceFoldersParams {
|
let params = DidChangeWorkspaceFoldersParams {
|
||||||
event: WorkspaceFoldersChangeEvent {
|
event: WorkspaceFoldersChangeEvent {
|
||||||
|
@ -1360,7 +1376,10 @@ impl LanguageServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_workspace_folders(&self, folders: BTreeSet<Url>) {
|
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 old_workspace_folders = std::mem::take(&mut *workspace_folders);
|
||||||
let added: Vec<_> = folders
|
let added: Vec<_> = folders
|
||||||
|
@ -1389,8 +1408,11 @@ impl LanguageServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspace_folders(&self) -> impl Deref<Target = BTreeSet<Url>> + '_ {
|
pub fn workspace_folders(&self) -> BTreeSet<Url> {
|
||||||
self.workspace_folders.lock()
|
self.workspace_folders.as_ref().map_or_else(
|
||||||
|
|| BTreeSet::from_iter([self.root_uri.clone()]),
|
||||||
|
|folders| folders.lock().clone(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_buffer(
|
pub fn register_buffer(
|
||||||
|
@ -1535,7 +1557,7 @@ impl FakeLanguageServer {
|
||||||
None,
|
None,
|
||||||
binary.clone(),
|
binary.clone(),
|
||||||
root,
|
root,
|
||||||
workspace_folders.clone(),
|
Some(workspace_folders.clone()),
|
||||||
cx,
|
cx,
|
||||||
|_| {},
|
|_| {},
|
||||||
);
|
);
|
||||||
|
@ -1554,7 +1576,7 @@ impl FakeLanguageServer {
|
||||||
None,
|
None,
|
||||||
binary,
|
binary,
|
||||||
Self::root_path(),
|
Self::root_path(),
|
||||||
workspace_folders,
|
Some(workspace_folders),
|
||||||
cx,
|
cx,
|
||||||
move |msg| {
|
move |msg| {
|
||||||
notifications_tx
|
notifications_tx
|
||||||
|
|
|
@ -46,6 +46,7 @@ use language::{
|
||||||
DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
|
DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
|
||||||
LanguageRegistry, LanguageToolchainStore, LocalFile, LspAdapter, LspAdapterDelegate, Patch,
|
LanguageRegistry, LanguageToolchainStore, LocalFile, LspAdapter, LspAdapterDelegate, Patch,
|
||||||
PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
|
PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
|
||||||
|
WorkspaceFoldersContent,
|
||||||
language_settings::{
|
language_settings::{
|
||||||
FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, 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 binary = self.get_language_server_binary(adapter.clone(), delegate.clone(), true, cx);
|
||||||
let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
|
let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
|
||||||
|
|
||||||
let pending_server = cx.spawn({
|
let pending_server = cx.spawn({
|
||||||
let adapter = adapter.clone();
|
let adapter = adapter.clone();
|
||||||
let server_name = adapter.name.clone();
|
let server_name = adapter.name.clone();
|
||||||
|
@ -242,14 +244,18 @@ impl LocalLspStore {
|
||||||
return Ok(server);
|
return Ok(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let code_action_kinds = adapter.code_action_kinds();
|
||||||
lsp::LanguageServer::new(
|
lsp::LanguageServer::new(
|
||||||
stderr_capture,
|
stderr_capture,
|
||||||
server_id,
|
server_id,
|
||||||
server_name,
|
server_name,
|
||||||
binary,
|
binary,
|
||||||
&root_path,
|
&root_path,
|
||||||
adapter.code_action_kinds(),
|
code_action_kinds,
|
||||||
pending_workspace_folders,
|
Some(pending_workspace_folders).filter(|_| {
|
||||||
|
adapter.adapter.workspace_folders_content()
|
||||||
|
== WorkspaceFoldersContent::SubprojectRoots
|
||||||
|
}),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -575,8 +581,7 @@ impl LocalLspStore {
|
||||||
};
|
};
|
||||||
let root = server.workspace_folders();
|
let root = server.workspace_folders();
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
root.iter()
|
root.into_iter()
|
||||||
.cloned()
|
|
||||||
.map(|uri| WorkspaceFolder {
|
.map(|uri| WorkspaceFolder {
|
||||||
uri,
|
uri,
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue