lsp: Identify language servers by their configuration (#35270)
- **WIP: reorganize dispositions** - **Introduce a LocalToolchainStore trait and use it for LspAdapter methods** Closes #35782 Closes #27331 Release Notes: - Python: Improved propagation of a selected virtual environment into the LSP configuration. This should the make all language-related features such as Go to definition or Find all references more reliable. --------- Co-authored-by: Cole Miller <cole@zed.dev> Co-authored-by: Lukas Wirth <lukas@zed.dev>
This commit is contained in:
parent
42ffa8900a
commit
b8a106632f
32 changed files with 1037 additions and 1085 deletions
|
@ -16022,23 +16022,11 @@ impl Editor {
|
||||||
cx.spawn_in(window, async move |editor, cx| {
|
cx.spawn_in(window, async move |editor, cx| {
|
||||||
let location_task = editor.update(cx, |_, cx| {
|
let location_task = editor.update(cx, |_, cx| {
|
||||||
project.update(cx, |project, cx| {
|
project.update(cx, |project, cx| {
|
||||||
let language_server_name = project
|
project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
|
||||||
.language_server_statuses(cx)
|
|
||||||
.find(|(id, _)| server_id == *id)
|
|
||||||
.map(|(_, status)| status.name.clone());
|
|
||||||
language_server_name.map(|language_server_name| {
|
|
||||||
project.open_local_buffer_via_lsp(
|
|
||||||
lsp_location.uri.clone(),
|
|
||||||
server_id,
|
|
||||||
language_server_name,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
let location = match location_task {
|
let location = Some({
|
||||||
Some(task) => Some({
|
let target_buffer_handle = location_task.await.context("open local buffer")?;
|
||||||
let target_buffer_handle = task.await.context("open local buffer")?;
|
|
||||||
let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
|
let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
|
||||||
let target_start = target_buffer
|
let target_start = target_buffer
|
||||||
.clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
|
.clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
|
||||||
|
@ -16051,9 +16039,7 @@ impl Editor {
|
||||||
buffer: target_buffer_handle,
|
buffer: target_buffer_handle,
|
||||||
range,
|
range,
|
||||||
}
|
}
|
||||||
}),
|
});
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
Ok(location)
|
Ok(location)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1275,6 +1275,7 @@ impl ExtensionStore {
|
||||||
queries,
|
queries,
|
||||||
context_provider,
|
context_provider,
|
||||||
toolchain_provider: None,
|
toolchain_provider: None,
|
||||||
|
manifest_name: None,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -163,6 +163,7 @@ impl HeadlessExtensionStore {
|
||||||
queries: LanguageQueries::default(),
|
queries: LanguageQueries::default(),
|
||||||
context_provider: None,
|
context_provider: None,
|
||||||
toolchain_provider: None,
|
toolchain_provider: None,
|
||||||
|
manifest_name: None,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -938,7 +938,7 @@ impl ExtensionImports for WasmState {
|
||||||
binary: settings.binary.map(|binary| settings::CommandSettings {
|
binary: settings.binary.map(|binary| settings::CommandSettings {
|
||||||
path: binary.path,
|
path: binary.path,
|
||||||
arguments: binary.arguments,
|
arguments: binary.arguments,
|
||||||
env: binary.env,
|
env: binary.env.map(|env| env.into_iter().collect()),
|
||||||
}),
|
}),
|
||||||
settings: settings.settings,
|
settings: settings.settings,
|
||||||
initialization_options: settings.initialization_options,
|
initialization_options: settings.initialization_options,
|
||||||
|
|
|
@ -1571,6 +1571,7 @@ impl Buffer {
|
||||||
diagnostics: diagnostics.iter().cloned().collect(),
|
diagnostics: diagnostics.iter().cloned().collect(),
|
||||||
lamport_timestamp,
|
lamport_timestamp,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.apply_diagnostic_update(server_id, diagnostics, lamport_timestamp, cx);
|
self.apply_diagnostic_update(server_id, diagnostics, lamport_timestamp, cx);
|
||||||
self.send_operation(op, true, cx);
|
self.send_operation(op, true, cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use settings::WorktreeId;
|
use settings::WorktreeId;
|
||||||
use smol::future::FutureExt as _;
|
use smol::future::FutureExt as _;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
|
@ -59,7 +60,6 @@ use std::{
|
||||||
atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
|
atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{num::NonZeroU32, sync::OnceLock};
|
|
||||||
use syntax_map::{QueryCursorHandle, SyntaxSnapshot};
|
use syntax_map::{QueryCursorHandle, SyntaxSnapshot};
|
||||||
use task::RunnableTag;
|
use task::RunnableTag;
|
||||||
pub use task_context::{ContextLocation, ContextProvider, RunnableRange};
|
pub use task_context::{ContextLocation, ContextProvider, RunnableRange};
|
||||||
|
@ -67,7 +67,9 @@ pub use text_diff::{
|
||||||
DiffOptions, apply_diff_patch, line_diff, text_diff, text_diff_with_options, unified_diff,
|
DiffOptions, apply_diff_patch, line_diff, text_diff, text_diff_with_options, unified_diff,
|
||||||
};
|
};
|
||||||
use theme::SyntaxTheme;
|
use theme::SyntaxTheme;
|
||||||
pub use toolchain::{LanguageToolchainStore, Toolchain, ToolchainList, ToolchainLister};
|
pub use toolchain::{
|
||||||
|
LanguageToolchainStore, LocalLanguageToolchainStore, Toolchain, ToolchainList, ToolchainLister,
|
||||||
|
};
|
||||||
use tree_sitter::{self, Query, QueryCursor, WasmStore, wasmtime};
|
use tree_sitter::{self, Query, QueryCursor, WasmStore, wasmtime};
|
||||||
use util::serde::default_true;
|
use util::serde::default_true;
|
||||||
|
|
||||||
|
@ -165,7 +167,6 @@ pub struct CachedLspAdapter {
|
||||||
pub adapter: Arc<dyn LspAdapter>,
|
pub adapter: Arc<dyn LspAdapter>,
|
||||||
pub reinstall_attempt_count: AtomicU64,
|
pub reinstall_attempt_count: AtomicU64,
|
||||||
cached_binary: futures::lock::Mutex<Option<LanguageServerBinary>>,
|
cached_binary: futures::lock::Mutex<Option<LanguageServerBinary>>,
|
||||||
manifest_name: OnceLock<Option<ManifestName>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for CachedLspAdapter {
|
impl Debug for CachedLspAdapter {
|
||||||
|
@ -201,7 +202,6 @@ impl CachedLspAdapter {
|
||||||
adapter,
|
adapter,
|
||||||
cached_binary: Default::default(),
|
cached_binary: Default::default(),
|
||||||
reinstall_attempt_count: AtomicU64::new(0),
|
reinstall_attempt_count: AtomicU64::new(0),
|
||||||
manifest_name: Default::default(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ impl CachedLspAdapter {
|
||||||
pub async fn get_language_server_command(
|
pub async fn get_language_server_command(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
delegate: Arc<dyn LspAdapterDelegate>,
|
delegate: Arc<dyn LspAdapterDelegate>,
|
||||||
toolchains: Arc<dyn LanguageToolchainStore>,
|
toolchains: Option<Toolchain>,
|
||||||
binary_options: LanguageServerBinaryOptions,
|
binary_options: LanguageServerBinaryOptions,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<LanguageServerBinary> {
|
) -> Result<LanguageServerBinary> {
|
||||||
|
@ -281,12 +281,6 @@ impl CachedLspAdapter {
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| language_name.lsp_id())
|
.unwrap_or_else(|| language_name.lsp_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn manifest_name(&self) -> Option<ManifestName> {
|
|
||||||
self.manifest_name
|
|
||||||
.get_or_init(|| self.adapter.manifest_name())
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines what gets sent out as a workspace folders content
|
/// Determines what gets sent out as a workspace folders content
|
||||||
|
@ -327,7 +321,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
fn get_language_server_command<'a>(
|
fn get_language_server_command<'a>(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
delegate: Arc<dyn LspAdapterDelegate>,
|
delegate: Arc<dyn LspAdapterDelegate>,
|
||||||
toolchains: Arc<dyn LanguageToolchainStore>,
|
toolchains: Option<Toolchain>,
|
||||||
binary_options: LanguageServerBinaryOptions,
|
binary_options: LanguageServerBinaryOptions,
|
||||||
mut cached_binary: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
mut cached_binary: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
||||||
cx: &'a mut AsyncApp,
|
cx: &'a mut AsyncApp,
|
||||||
|
@ -402,7 +396,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
_: &dyn LspAdapterDelegate,
|
_: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
None
|
None
|
||||||
|
@ -535,7 +529,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
_: &Arc<dyn LspAdapterDelegate>,
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_cx: &mut AsyncApp,
|
_cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
Ok(serde_json::json!({}))
|
Ok(serde_json::json!({}))
|
||||||
|
@ -555,7 +549,6 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
_target_language_server_id: LanguageServerName,
|
_target_language_server_id: LanguageServerName,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
_: &Arc<dyn LspAdapterDelegate>,
|
_: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
|
||||||
_cx: &mut AsyncApp,
|
_cx: &mut AsyncApp,
|
||||||
) -> Result<Option<Value>> {
|
) -> Result<Option<Value>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -594,10 +587,6 @@ pub trait LspAdapter: 'static + Send + Sync {
|
||||||
WorkspaceFoldersContent::SubprojectRoots
|
WorkspaceFoldersContent::SubprojectRoots
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manifest_name(&self) -> Option<ManifestName> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Method only implemented by the default JSON language server adapter.
|
/// Method only implemented by the default JSON language server adapter.
|
||||||
/// Used to provide dynamic reloading of the JSON schemas used to
|
/// Used to provide dynamic reloading of the JSON schemas used to
|
||||||
/// provide autocompletion and diagnostics in Zed setting and keybind
|
/// provide autocompletion and diagnostics in Zed setting and keybind
|
||||||
|
@ -1108,6 +1097,7 @@ pub struct Language {
|
||||||
pub(crate) grammar: Option<Arc<Grammar>>,
|
pub(crate) grammar: Option<Arc<Grammar>>,
|
||||||
pub(crate) context_provider: Option<Arc<dyn ContextProvider>>,
|
pub(crate) context_provider: Option<Arc<dyn ContextProvider>>,
|
||||||
pub(crate) toolchain: Option<Arc<dyn ToolchainLister>>,
|
pub(crate) toolchain: Option<Arc<dyn ToolchainLister>>,
|
||||||
|
pub(crate) manifest_name: Option<ManifestName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||||
|
@ -1318,6 +1308,7 @@ impl Language {
|
||||||
}),
|
}),
|
||||||
context_provider: None,
|
context_provider: None,
|
||||||
toolchain: None,
|
toolchain: None,
|
||||||
|
manifest_name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1331,6 +1322,10 @@ impl Language {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_manifest(mut self, name: Option<ManifestName>) -> Self {
|
||||||
|
self.manifest_name = name;
|
||||||
|
self
|
||||||
|
}
|
||||||
pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
|
pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
|
||||||
if let Some(query) = queries.highlights {
|
if let Some(query) = queries.highlights {
|
||||||
self = self
|
self = self
|
||||||
|
@ -1764,6 +1759,9 @@ impl Language {
|
||||||
pub fn name(&self) -> LanguageName {
|
pub fn name(&self) -> LanguageName {
|
||||||
self.config.name.clone()
|
self.config.name.clone()
|
||||||
}
|
}
|
||||||
|
pub fn manifest(&self) -> Option<&ManifestName> {
|
||||||
|
self.manifest_name.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn code_fence_block_name(&self) -> Arc<str> {
|
pub fn code_fence_block_name(&self) -> Arc<str> {
|
||||||
self.config
|
self.config
|
||||||
|
@ -2209,7 +2207,7 @@ impl LspAdapter for FakeLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
_: &dyn LspAdapterDelegate,
|
_: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
Some(self.language_server_binary.clone())
|
Some(self.language_server_binary.clone())
|
||||||
|
@ -2218,7 +2216,7 @@ impl LspAdapter for FakeLspAdapter {
|
||||||
fn get_language_server_command<'a>(
|
fn get_language_server_command<'a>(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: Arc<dyn LspAdapterDelegate>,
|
_: Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: LanguageServerBinaryOptions,
|
_: LanguageServerBinaryOptions,
|
||||||
_: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
_: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
||||||
_: &'a mut AsyncApp,
|
_: &'a mut AsyncApp,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher,
|
CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher,
|
||||||
LanguageServerName, LspAdapter, PLAIN_TEXT, ToolchainLister,
|
LanguageServerName, LspAdapter, ManifestName, PLAIN_TEXT, ToolchainLister,
|
||||||
language_settings::{
|
language_settings::{
|
||||||
AllLanguageSettingsContent, LanguageSettingsContent, all_language_settings,
|
AllLanguageSettingsContent, LanguageSettingsContent, all_language_settings,
|
||||||
},
|
},
|
||||||
|
@ -172,6 +172,7 @@ pub struct AvailableLanguage {
|
||||||
hidden: bool,
|
hidden: bool,
|
||||||
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
|
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
|
||||||
loaded: bool,
|
loaded: bool,
|
||||||
|
manifest_name: Option<ManifestName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AvailableLanguage {
|
impl AvailableLanguage {
|
||||||
|
@ -259,6 +260,7 @@ pub struct LoadedLanguage {
|
||||||
pub queries: LanguageQueries,
|
pub queries: LanguageQueries,
|
||||||
pub context_provider: Option<Arc<dyn ContextProvider>>,
|
pub context_provider: Option<Arc<dyn ContextProvider>>,
|
||||||
pub toolchain_provider: Option<Arc<dyn ToolchainLister>>,
|
pub toolchain_provider: Option<Arc<dyn ToolchainLister>>,
|
||||||
|
pub manifest_name: Option<ManifestName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LanguageRegistry {
|
impl LanguageRegistry {
|
||||||
|
@ -349,12 +351,14 @@ impl LanguageRegistry {
|
||||||
config.grammar.clone(),
|
config.grammar.clone(),
|
||||||
config.matcher.clone(),
|
config.matcher.clone(),
|
||||||
config.hidden,
|
config.hidden,
|
||||||
|
None,
|
||||||
Arc::new(move || {
|
Arc::new(move || {
|
||||||
Ok(LoadedLanguage {
|
Ok(LoadedLanguage {
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
queries: Default::default(),
|
queries: Default::default(),
|
||||||
toolchain_provider: None,
|
toolchain_provider: None,
|
||||||
context_provider: None,
|
context_provider: None,
|
||||||
|
manifest_name: None,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -487,6 +491,7 @@ impl LanguageRegistry {
|
||||||
grammar_name: Option<Arc<str>>,
|
grammar_name: Option<Arc<str>>,
|
||||||
matcher: LanguageMatcher,
|
matcher: LanguageMatcher,
|
||||||
hidden: bool,
|
hidden: bool,
|
||||||
|
manifest_name: Option<ManifestName>,
|
||||||
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
|
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
|
||||||
) {
|
) {
|
||||||
let state = &mut *self.state.write();
|
let state = &mut *self.state.write();
|
||||||
|
@ -496,6 +501,7 @@ impl LanguageRegistry {
|
||||||
existing_language.grammar = grammar_name;
|
existing_language.grammar = grammar_name;
|
||||||
existing_language.matcher = matcher;
|
existing_language.matcher = matcher;
|
||||||
existing_language.load = load;
|
existing_language.load = load;
|
||||||
|
existing_language.manifest_name = manifest_name;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,6 +514,7 @@ impl LanguageRegistry {
|
||||||
load,
|
load,
|
||||||
hidden,
|
hidden,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
manifest_name,
|
||||||
});
|
});
|
||||||
state.version += 1;
|
state.version += 1;
|
||||||
state.reload_count += 1;
|
state.reload_count += 1;
|
||||||
|
@ -575,6 +582,7 @@ impl LanguageRegistry {
|
||||||
grammar: language.config.grammar.clone(),
|
grammar: language.config.grammar.clone(),
|
||||||
matcher: language.config.matcher.clone(),
|
matcher: language.config.matcher.clone(),
|
||||||
hidden: language.config.hidden,
|
hidden: language.config.hidden,
|
||||||
|
manifest_name: None,
|
||||||
load: Arc::new(|| Err(anyhow!("already loaded"))),
|
load: Arc::new(|| Err(anyhow!("already loaded"))),
|
||||||
loaded: true,
|
loaded: true,
|
||||||
});
|
});
|
||||||
|
@ -914,10 +922,12 @@ impl LanguageRegistry {
|
||||||
Language::new_with_id(id, loaded_language.config, grammar)
|
Language::new_with_id(id, loaded_language.config, grammar)
|
||||||
.with_context_provider(loaded_language.context_provider)
|
.with_context_provider(loaded_language.context_provider)
|
||||||
.with_toolchain_lister(loaded_language.toolchain_provider)
|
.with_toolchain_lister(loaded_language.toolchain_provider)
|
||||||
|
.with_manifest(loaded_language.manifest_name)
|
||||||
.with_queries(loaded_language.queries)
|
.with_queries(loaded_language.queries)
|
||||||
} else {
|
} else {
|
||||||
Ok(Language::new_with_id(id, loaded_language.config, None)
|
Ok(Language::new_with_id(id, loaded_language.config, None)
|
||||||
.with_context_provider(loaded_language.context_provider)
|
.with_context_provider(loaded_language.context_provider)
|
||||||
|
.with_manifest(loaded_language.manifest_name)
|
||||||
.with_toolchain_lister(loaded_language.toolchain_provider))
|
.with_toolchain_lister(loaded_language.toolchain_provider))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,12 @@ impl Borrow<SharedString> for ManifestName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Borrow<str> for ManifestName {
|
||||||
|
fn borrow(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<SharedString> for ManifestName {
|
impl From<SharedString> for ManifestName {
|
||||||
fn from(value: SharedString) -> Self {
|
fn from(value: SharedString) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
|
|
|
@ -17,7 +17,7 @@ use settings::WorktreeId;
|
||||||
use crate::{LanguageName, ManifestName};
|
use crate::{LanguageName, ManifestName};
|
||||||
|
|
||||||
/// Represents a single toolchain.
|
/// Represents a single toolchain.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Eq)]
|
||||||
pub struct Toolchain {
|
pub struct Toolchain {
|
||||||
/// User-facing label
|
/// User-facing label
|
||||||
pub name: SharedString,
|
pub name: SharedString,
|
||||||
|
@ -27,6 +27,14 @@ pub struct Toolchain {
|
||||||
pub as_json: serde_json::Value,
|
pub as_json: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for Toolchain {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
self.path.hash(state);
|
||||||
|
self.language_name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Toolchain {
|
impl PartialEq for Toolchain {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// Do not use as_json for comparisons; it shouldn't impact equality, as it's not user-surfaced.
|
// Do not use as_json for comparisons; it shouldn't impact equality, as it's not user-surfaced.
|
||||||
|
@ -64,6 +72,29 @@ pub trait LanguageToolchainStore: Send + Sync + 'static {
|
||||||
) -> Option<Toolchain>;
|
) -> Option<Toolchain>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LocalLanguageToolchainStore: Send + Sync + 'static {
|
||||||
|
fn active_toolchain(
|
||||||
|
self: Arc<Self>,
|
||||||
|
worktree_id: WorktreeId,
|
||||||
|
relative_path: &Arc<Path>,
|
||||||
|
language_name: LanguageName,
|
||||||
|
cx: &mut AsyncApp,
|
||||||
|
) -> Option<Toolchain>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait(?Send )]
|
||||||
|
impl<T: LocalLanguageToolchainStore> LanguageToolchainStore for T {
|
||||||
|
async fn active_toolchain(
|
||||||
|
self: Arc<Self>,
|
||||||
|
worktree_id: WorktreeId,
|
||||||
|
relative_path: Arc<Path>,
|
||||||
|
language_name: LanguageName,
|
||||||
|
cx: &mut AsyncApp,
|
||||||
|
) -> Option<Toolchain> {
|
||||||
|
self.active_toolchain(worktree_id, &relative_path, language_name, cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type DefaultIndex = usize;
|
type DefaultIndex = usize;
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct ToolchainList {
|
pub struct ToolchainList {
|
||||||
|
|
|
@ -12,8 +12,8 @@ use fs::Fs;
|
||||||
use futures::{Future, FutureExt, future::join_all};
|
use futures::{Future, FutureExt, future::join_all};
|
||||||
use gpui::{App, AppContext, AsyncApp, Task};
|
use gpui::{App, AppContext, AsyncApp, Task};
|
||||||
use language::{
|
use language::{
|
||||||
BinaryStatus, CodeLabel, HighlightId, Language, LanguageName, LanguageToolchainStore,
|
BinaryStatus, CodeLabel, HighlightId, Language, LanguageName, LspAdapter, LspAdapterDelegate,
|
||||||
LspAdapter, LspAdapterDelegate,
|
Toolchain,
|
||||||
};
|
};
|
||||||
use lsp::{
|
use lsp::{
|
||||||
CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName,
|
CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName,
|
||||||
|
@ -159,7 +159,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
fn get_language_server_command<'a>(
|
fn get_language_server_command<'a>(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
delegate: Arc<dyn LspAdapterDelegate>,
|
delegate: Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: LanguageServerBinaryOptions,
|
_: LanguageServerBinaryOptions,
|
||||||
_: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
_: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
||||||
_: &'a mut AsyncApp,
|
_: &'a mut AsyncApp,
|
||||||
|
@ -288,7 +288,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_cx: &mut AsyncApp,
|
_cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
||||||
|
@ -336,7 +336,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
||||||
target_language_server_id: LanguageServerName,
|
target_language_server_id: LanguageServerName,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
|
||||||
_cx: &mut AsyncApp,
|
_cx: &mut AsyncApp,
|
||||||
) -> Result<Option<serde_json::Value>> {
|
) -> Result<Option<serde_json::Value>> {
|
||||||
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl ExtensionLanguageProxy for LanguageServerRegistryProxy {
|
||||||
load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
|
load: Arc<dyn Fn() -> Result<LoadedLanguage> + Send + Sync + 'static>,
|
||||||
) {
|
) {
|
||||||
self.language_registry
|
self.language_registry
|
||||||
.register_language(language, grammar, matcher, hidden, load);
|
.register_language(language, grammar, matcher, hidden, None, load);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_languages(
|
fn remove_languages(
|
||||||
|
|
|
@ -28,7 +28,7 @@ impl super::LspAdapter for CLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{Context as _, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::AsyncApp;
|
use gpui::AsyncApp;
|
||||||
use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate};
|
use language::{LspAdapter, LspAdapterDelegate, Toolchain};
|
||||||
use lsp::{LanguageServerBinary, LanguageServerName};
|
use lsp::{LanguageServerBinary, LanguageServerName};
|
||||||
use node_runtime::{NodeRuntime, VersionStrategy};
|
use node_runtime::{NodeRuntime, VersionStrategy};
|
||||||
use project::{Fs, lsp_store::language_server_settings};
|
use project::{Fs, lsp_store::language_server_settings};
|
||||||
|
@ -43,7 +43,7 @@ impl LspAdapter for CssLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate
|
let path = delegate
|
||||||
|
@ -144,7 +144,7 @@ impl LspAdapter for CssLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<serde_json::Value> {
|
) -> Result<serde_json::Value> {
|
||||||
let mut default_config = json!({
|
let mut default_config = json!({
|
||||||
|
|
|
@ -75,7 +75,7 @@ impl super::LspAdapter for GoLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
||||||
|
|
|
@ -8,8 +8,8 @@ use futures::StreamExt;
|
||||||
use gpui::{App, AsyncApp, Task};
|
use gpui::{App, AsyncApp, Task};
|
||||||
use http_client::github::{GitHubLspBinaryVersion, latest_github_release};
|
use http_client::github::{GitHubLspBinaryVersion, latest_github_release};
|
||||||
use language::{
|
use language::{
|
||||||
ContextProvider, LanguageName, LanguageRegistry, LanguageToolchainStore, LocalFile as _,
|
ContextProvider, LanguageName, LanguageRegistry, LocalFile as _, LspAdapter,
|
||||||
LspAdapter, LspAdapterDelegate,
|
LspAdapterDelegate, Toolchain,
|
||||||
};
|
};
|
||||||
use lsp::{LanguageServerBinary, LanguageServerName};
|
use lsp::{LanguageServerBinary, LanguageServerName};
|
||||||
use node_runtime::{NodeRuntime, VersionStrategy};
|
use node_runtime::{NodeRuntime, VersionStrategy};
|
||||||
|
@ -303,7 +303,7 @@ impl LspAdapter for JsonLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate
|
let path = delegate
|
||||||
|
@ -404,7 +404,7 @@ impl LspAdapter for JsonLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let mut config = self.get_or_init_workspace_config(cx).await?;
|
let mut config = self.get_or_init_workspace_config(cx).await?;
|
||||||
|
@ -529,7 +529,7 @@ impl LspAdapter for NodeVersionAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use feature_flags::{FeatureFlag, FeatureFlagAppExt as _};
|
use feature_flags::{FeatureFlag, FeatureFlagAppExt as _};
|
||||||
use gpui::{App, UpdateGlobal};
|
use gpui::{App, SharedString, UpdateGlobal};
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use python::PyprojectTomlManifestProvider;
|
use python::PyprojectTomlManifestProvider;
|
||||||
use rust::CargoManifestProvider;
|
use rust::CargoManifestProvider;
|
||||||
|
@ -177,11 +177,13 @@ pub fn init(languages: Arc<LanguageRegistry>, node: NodeRuntime, cx: &mut App) {
|
||||||
adapters: vec![python_lsp_adapter.clone(), py_lsp_adapter.clone()],
|
adapters: vec![python_lsp_adapter.clone(), py_lsp_adapter.clone()],
|
||||||
context: Some(python_context_provider),
|
context: Some(python_context_provider),
|
||||||
toolchain: Some(python_toolchain_provider),
|
toolchain: Some(python_toolchain_provider),
|
||||||
|
manifest_name: Some(SharedString::new_static("pyproject.toml").into()),
|
||||||
},
|
},
|
||||||
LanguageInfo {
|
LanguageInfo {
|
||||||
name: "rust",
|
name: "rust",
|
||||||
adapters: vec![rust_lsp_adapter],
|
adapters: vec![rust_lsp_adapter],
|
||||||
context: Some(rust_context_provider),
|
context: Some(rust_context_provider),
|
||||||
|
manifest_name: Some(SharedString::new_static("Cargo.toml").into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
LanguageInfo {
|
LanguageInfo {
|
||||||
|
@ -234,6 +236,7 @@ pub fn init(languages: Arc<LanguageRegistry>, node: NodeRuntime, cx: &mut App) {
|
||||||
registration.adapters,
|
registration.adapters,
|
||||||
registration.context,
|
registration.context,
|
||||||
registration.toolchain,
|
registration.toolchain,
|
||||||
|
registration.manifest_name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +343,7 @@ pub fn init(languages: Arc<LanguageRegistry>, node: NodeRuntime, cx: &mut App) {
|
||||||
Arc::from(PyprojectTomlManifestProvider),
|
Arc::from(PyprojectTomlManifestProvider),
|
||||||
];
|
];
|
||||||
for provider in manifest_providers {
|
for provider in manifest_providers {
|
||||||
project::ManifestProviders::global(cx).register(provider);
|
project::ManifestProvidersStore::global(cx).register(provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,6 +353,7 @@ struct LanguageInfo {
|
||||||
adapters: Vec<Arc<dyn LspAdapter>>,
|
adapters: Vec<Arc<dyn LspAdapter>>,
|
||||||
context: Option<Arc<dyn ContextProvider>>,
|
context: Option<Arc<dyn ContextProvider>>,
|
||||||
toolchain: Option<Arc<dyn ToolchainLister>>,
|
toolchain: Option<Arc<dyn ToolchainLister>>,
|
||||||
|
manifest_name: Option<ManifestName>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_language(
|
fn register_language(
|
||||||
|
@ -358,6 +362,7 @@ fn register_language(
|
||||||
adapters: Vec<Arc<dyn LspAdapter>>,
|
adapters: Vec<Arc<dyn LspAdapter>>,
|
||||||
context: Option<Arc<dyn ContextProvider>>,
|
context: Option<Arc<dyn ContextProvider>>,
|
||||||
toolchain: Option<Arc<dyn ToolchainLister>>,
|
toolchain: Option<Arc<dyn ToolchainLister>>,
|
||||||
|
manifest_name: Option<ManifestName>,
|
||||||
) {
|
) {
|
||||||
let config = load_config(name);
|
let config = load_config(name);
|
||||||
for adapter in adapters {
|
for adapter in adapters {
|
||||||
|
@ -368,12 +373,14 @@ fn register_language(
|
||||||
config.grammar.clone(),
|
config.grammar.clone(),
|
||||||
config.matcher.clone(),
|
config.matcher.clone(),
|
||||||
config.hidden,
|
config.hidden,
|
||||||
|
manifest_name.clone(),
|
||||||
Arc::new(move || {
|
Arc::new(move || {
|
||||||
Ok(LoadedLanguage {
|
Ok(LoadedLanguage {
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
queries: load_queries(name),
|
queries: load_queries(name),
|
||||||
context_provider: context.clone(),
|
context_provider: context.clone(),
|
||||||
toolchain_provider: toolchain.clone(),
|
toolchain_provider: toolchain.clone(),
|
||||||
|
manifest_name: manifest_name.clone(),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -127,7 +127,7 @@ impl LspAdapter for PythonLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
if let Some(pyright_bin) = delegate.which("pyright-langserver".as_ref()).await {
|
if let Some(pyright_bin) = delegate.which("pyright-langserver".as_ref()).await {
|
||||||
|
@ -319,17 +319,9 @@ impl LspAdapter for PythonLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
adapter: &Arc<dyn LspAdapterDelegate>,
|
adapter: &Arc<dyn LspAdapterDelegate>,
|
||||||
toolchains: Arc<dyn LanguageToolchainStore>,
|
toolchain: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let toolchain = toolchains
|
|
||||||
.active_toolchain(
|
|
||||||
adapter.worktree_id(),
|
|
||||||
Arc::from("".as_ref()),
|
|
||||||
LanguageName::new("Python"),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
cx.update(move |cx| {
|
cx.update(move |cx| {
|
||||||
let mut user_settings =
|
let mut user_settings =
|
||||||
language_server_settings(adapter.as_ref(), &Self::SERVER_NAME, cx)
|
language_server_settings(adapter.as_ref(), &Self::SERVER_NAME, cx)
|
||||||
|
@ -397,9 +389,7 @@ impl LspAdapter for PythonLspAdapter {
|
||||||
user_settings
|
user_settings
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn manifest_name(&self) -> Option<ManifestName> {
|
|
||||||
Some(SharedString::new_static("pyproject.toml").into())
|
|
||||||
}
|
|
||||||
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||||
WorkspaceFoldersContent::WorktreeRoot
|
WorkspaceFoldersContent::WorktreeRoot
|
||||||
}
|
}
|
||||||
|
@ -1046,8 +1036,8 @@ impl LspAdapter for PyLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
toolchains: Arc<dyn LanguageToolchainStore>,
|
toolchain: Option<Toolchain>,
|
||||||
cx: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
if let Some(pylsp_bin) = delegate.which(Self::SERVER_NAME.as_ref()).await {
|
if let Some(pylsp_bin) = delegate.which(Self::SERVER_NAME.as_ref()).await {
|
||||||
let env = delegate.shell_env().await;
|
let env = delegate.shell_env().await;
|
||||||
|
@ -1057,14 +1047,7 @@ impl LspAdapter for PyLspAdapter {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let venv = toolchains
|
let venv = toolchain?;
|
||||||
.active_toolchain(
|
|
||||||
delegate.worktree_id(),
|
|
||||||
Arc::from("".as_ref()),
|
|
||||||
LanguageName::new("Python"),
|
|
||||||
&mut cx.clone(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let pylsp_path = Path::new(venv.path.as_ref()).parent()?.join("pylsp");
|
let pylsp_path = Path::new(venv.path.as_ref()).parent()?.join("pylsp");
|
||||||
pylsp_path.exists().then(|| LanguageServerBinary {
|
pylsp_path.exists().then(|| LanguageServerBinary {
|
||||||
path: venv.path.to_string().into(),
|
path: venv.path.to_string().into(),
|
||||||
|
@ -1211,17 +1194,9 @@ impl LspAdapter for PyLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
adapter: &Arc<dyn LspAdapterDelegate>,
|
adapter: &Arc<dyn LspAdapterDelegate>,
|
||||||
toolchains: Arc<dyn LanguageToolchainStore>,
|
toolchain: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let toolchain = toolchains
|
|
||||||
.active_toolchain(
|
|
||||||
adapter.worktree_id(),
|
|
||||||
Arc::from("".as_ref()),
|
|
||||||
LanguageName::new("Python"),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
cx.update(move |cx| {
|
cx.update(move |cx| {
|
||||||
let mut user_settings =
|
let mut user_settings =
|
||||||
language_server_settings(adapter.as_ref(), &Self::SERVER_NAME, cx)
|
language_server_settings(adapter.as_ref(), &Self::SERVER_NAME, cx)
|
||||||
|
@ -1282,9 +1257,6 @@ impl LspAdapter for PyLspAdapter {
|
||||||
user_settings
|
user_settings
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn manifest_name(&self) -> Option<ManifestName> {
|
|
||||||
Some(SharedString::new_static("pyproject.toml").into())
|
|
||||||
}
|
|
||||||
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||||
WorkspaceFoldersContent::WorktreeRoot
|
WorkspaceFoldersContent::WorktreeRoot
|
||||||
}
|
}
|
||||||
|
@ -1377,8 +1349,8 @@ impl LspAdapter for BasedPyrightLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
toolchains: Arc<dyn LanguageToolchainStore>,
|
toolchain: Option<Toolchain>,
|
||||||
cx: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
if let Some(bin) = delegate.which(Self::BINARY_NAME.as_ref()).await {
|
if let Some(bin) = delegate.which(Self::BINARY_NAME.as_ref()).await {
|
||||||
let env = delegate.shell_env().await;
|
let env = delegate.shell_env().await;
|
||||||
|
@ -1388,15 +1360,7 @@ impl LspAdapter for BasedPyrightLspAdapter {
|
||||||
arguments: vec!["--stdio".into()],
|
arguments: vec!["--stdio".into()],
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let venv = toolchains
|
let path = Path::new(toolchain?.path.as_ref())
|
||||||
.active_toolchain(
|
|
||||||
delegate.worktree_id(),
|
|
||||||
Arc::from("".as_ref()),
|
|
||||||
LanguageName::new("Python"),
|
|
||||||
&mut cx.clone(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let path = Path::new(venv.path.as_ref())
|
|
||||||
.parent()?
|
.parent()?
|
||||||
.join(Self::BINARY_NAME);
|
.join(Self::BINARY_NAME);
|
||||||
path.exists().then(|| LanguageServerBinary {
|
path.exists().then(|| LanguageServerBinary {
|
||||||
|
@ -1543,17 +1507,9 @@ impl LspAdapter for BasedPyrightLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
adapter: &Arc<dyn LspAdapterDelegate>,
|
adapter: &Arc<dyn LspAdapterDelegate>,
|
||||||
toolchains: Arc<dyn LanguageToolchainStore>,
|
toolchain: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let toolchain = toolchains
|
|
||||||
.active_toolchain(
|
|
||||||
adapter.worktree_id(),
|
|
||||||
Arc::from("".as_ref()),
|
|
||||||
LanguageName::new("Python"),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
cx.update(move |cx| {
|
cx.update(move |cx| {
|
||||||
let mut user_settings =
|
let mut user_settings =
|
||||||
language_server_settings(adapter.as_ref(), &Self::SERVER_NAME, cx)
|
language_server_settings(adapter.as_ref(), &Self::SERVER_NAME, cx)
|
||||||
|
@ -1622,10 +1578,6 @@ impl LspAdapter for BasedPyrightLspAdapter {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manifest_name(&self) -> Option<ManifestName> {
|
|
||||||
Some(SharedString::new_static("pyproject.toml").into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
fn workspace_folders_content(&self) -> WorkspaceFoldersContent {
|
||||||
WorkspaceFoldersContent::WorktreeRoot
|
WorkspaceFoldersContent::WorktreeRoot
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,14 +109,10 @@ impl LspAdapter for RustLspAdapter {
|
||||||
SERVER_NAME.clone()
|
SERVER_NAME.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manifest_name(&self) -> Option<ManifestName> {
|
|
||||||
Some(SharedString::new_static("Cargo.toml").into())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate.which("rust-analyzer".as_ref()).await?;
|
let path = delegate.which("rust-analyzer".as_ref()).await?;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::AsyncApp;
|
use gpui::AsyncApp;
|
||||||
use language::{LanguageName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageName, LspAdapter, LspAdapterDelegate, Toolchain};
|
||||||
use lsp::{LanguageServerBinary, LanguageServerName};
|
use lsp::{LanguageServerBinary, LanguageServerName};
|
||||||
use node_runtime::{NodeRuntime, VersionStrategy};
|
use node_runtime::{NodeRuntime, VersionStrategy};
|
||||||
use project::{Fs, lsp_store::language_server_settings};
|
use project::{Fs, lsp_store::language_server_settings};
|
||||||
|
@ -50,7 +50,7 @@ impl LspAdapter for TailwindLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
||||||
|
@ -155,7 +155,7 @@ impl LspAdapter for TailwindLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let mut tailwind_user_settings = cx.update(|cx| {
|
let mut tailwind_user_settings = cx.update(|cx| {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use gpui::{App, AppContext, AsyncApp, Task};
|
||||||
use http_client::github::{AssetKind, GitHubLspBinaryVersion, build_asset_url};
|
use http_client::github::{AssetKind, GitHubLspBinaryVersion, build_asset_url};
|
||||||
use language::{
|
use language::{
|
||||||
ContextLocation, ContextProvider, File, LanguageName, LanguageToolchainStore, LspAdapter,
|
ContextLocation, ContextProvider, File, LanguageName, LanguageToolchainStore, LspAdapter,
|
||||||
LspAdapterDelegate,
|
LspAdapterDelegate, Toolchain,
|
||||||
};
|
};
|
||||||
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
|
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
|
||||||
use node_runtime::{NodeRuntime, VersionStrategy};
|
use node_runtime::{NodeRuntime, VersionStrategy};
|
||||||
|
@ -722,7 +722,7 @@ impl LspAdapter for TypeScriptLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let override_options = cx.update(|cx| {
|
let override_options = cx.update(|cx| {
|
||||||
|
@ -822,7 +822,7 @@ impl LspAdapter for EsLintLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let workspace_root = delegate.worktree_root_path();
|
let workspace_root = delegate.worktree_root_path();
|
||||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::Result;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::AsyncApp;
|
use gpui::AsyncApp;
|
||||||
use language::{LanguageName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageName, LspAdapter, LspAdapterDelegate, Toolchain};
|
||||||
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
|
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
|
||||||
use node_runtime::{NodeRuntime, VersionStrategy};
|
use node_runtime::{NodeRuntime, VersionStrategy};
|
||||||
use project::{Fs, lsp_store::language_server_settings};
|
use project::{Fs, lsp_store::language_server_settings};
|
||||||
|
@ -86,7 +86,7 @@ impl LspAdapter for VtslsLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let env = delegate.shell_env().await;
|
let env = delegate.shell_env().await;
|
||||||
|
@ -211,7 +211,7 @@ impl LspAdapter for VtslsLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
fs: &dyn Fs,
|
fs: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let tsdk_path = Self::tsdk_path(fs, delegate).await;
|
let tsdk_path = Self::tsdk_path(fs, delegate).await;
|
||||||
|
|
|
@ -2,9 +2,7 @@ use anyhow::{Context as _, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::AsyncApp;
|
use gpui::AsyncApp;
|
||||||
use language::{
|
use language::{LspAdapter, LspAdapterDelegate, Toolchain, language_settings::AllLanguageSettings};
|
||||||
LanguageToolchainStore, LspAdapter, LspAdapterDelegate, language_settings::AllLanguageSettings,
|
|
||||||
};
|
|
||||||
use lsp::{LanguageServerBinary, LanguageServerName};
|
use lsp::{LanguageServerBinary, LanguageServerName};
|
||||||
use node_runtime::{NodeRuntime, VersionStrategy};
|
use node_runtime::{NodeRuntime, VersionStrategy};
|
||||||
use project::{Fs, lsp_store::language_server_settings};
|
use project::{Fs, lsp_store::language_server_settings};
|
||||||
|
@ -57,7 +55,7 @@ impl LspAdapter for YamlLspAdapter {
|
||||||
async fn check_if_user_installed(
|
async fn check_if_user_installed(
|
||||||
&self,
|
&self,
|
||||||
delegate: &dyn LspAdapterDelegate,
|
delegate: &dyn LspAdapterDelegate,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
_: &AsyncApp,
|
_: &AsyncApp,
|
||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
let path = delegate.which(Self::SERVER_NAME.as_ref()).await?;
|
||||||
|
@ -135,7 +133,7 @@ impl LspAdapter for YamlLspAdapter {
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: &dyn Fs,
|
_: &dyn Fs,
|
||||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||||
_: Arc<dyn LanguageToolchainStore>,
|
_: Option<Toolchain>,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let location = SettingsLocation {
|
let location = SettingsLocation {
|
||||||
|
|
|
@ -500,13 +500,12 @@ impl LspCommand for PerformRename {
|
||||||
mut cx: AsyncApp,
|
mut cx: AsyncApp,
|
||||||
) -> Result<ProjectTransaction> {
|
) -> Result<ProjectTransaction> {
|
||||||
if let Some(edit) = message {
|
if let Some(edit) = message {
|
||||||
let (lsp_adapter, lsp_server) =
|
let (_, lsp_server) =
|
||||||
language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
|
language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
|
||||||
LocalLspStore::deserialize_workspace_edit(
|
LocalLspStore::deserialize_workspace_edit(
|
||||||
lsp_store,
|
lsp_store,
|
||||||
edit,
|
edit,
|
||||||
self.push_to_history,
|
self.push_to_history,
|
||||||
lsp_adapter,
|
|
||||||
lsp_server,
|
lsp_server,
|
||||||
&mut cx,
|
&mut cx,
|
||||||
)
|
)
|
||||||
|
@ -1116,18 +1115,12 @@ pub async fn location_links_from_lsp(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (lsp_adapter, language_server) =
|
let (_, language_server) = language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
|
||||||
language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
|
|
||||||
let mut definitions = Vec::new();
|
let mut definitions = Vec::new();
|
||||||
for (origin_range, target_uri, target_range) in unresolved_links {
|
for (origin_range, target_uri, target_range) in unresolved_links {
|
||||||
let target_buffer_handle = lsp_store
|
let target_buffer_handle = lsp_store
|
||||||
.update(&mut cx, |this, cx| {
|
.update(&mut cx, |this, cx| {
|
||||||
this.open_local_buffer_via_lsp(
|
this.open_local_buffer_via_lsp(target_uri, language_server.server_id(), cx)
|
||||||
target_uri,
|
|
||||||
language_server.server_id(),
|
|
||||||
lsp_adapter.name.clone(),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -1172,8 +1165,7 @@ pub async fn location_link_from_lsp(
|
||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Result<LocationLink> {
|
) -> Result<LocationLink> {
|
||||||
let (lsp_adapter, language_server) =
|
let (_, language_server) = language_server_for_buffer(&lsp_store, &buffer, server_id, cx)?;
|
||||||
language_server_for_buffer(&lsp_store, &buffer, server_id, cx)?;
|
|
||||||
|
|
||||||
let (origin_range, target_uri, target_range) = (
|
let (origin_range, target_uri, target_range) = (
|
||||||
link.origin_selection_range,
|
link.origin_selection_range,
|
||||||
|
@ -1183,12 +1175,7 @@ pub async fn location_link_from_lsp(
|
||||||
|
|
||||||
let target_buffer_handle = lsp_store
|
let target_buffer_handle = lsp_store
|
||||||
.update(cx, |lsp_store, cx| {
|
.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.open_local_buffer_via_lsp(
|
lsp_store.open_local_buffer_via_lsp(target_uri, language_server.server_id(), cx)
|
||||||
target_uri,
|
|
||||||
language_server.server_id(),
|
|
||||||
lsp_adapter.name.clone(),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -1326,7 +1313,7 @@ impl LspCommand for GetReferences {
|
||||||
mut cx: AsyncApp,
|
mut cx: AsyncApp,
|
||||||
) -> Result<Vec<Location>> {
|
) -> Result<Vec<Location>> {
|
||||||
let mut references = Vec::new();
|
let mut references = Vec::new();
|
||||||
let (lsp_adapter, language_server) =
|
let (_, language_server) =
|
||||||
language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
|
language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
|
||||||
|
|
||||||
if let Some(locations) = locations {
|
if let Some(locations) = locations {
|
||||||
|
@ -1336,7 +1323,6 @@ impl LspCommand for GetReferences {
|
||||||
lsp_store.open_local_buffer_via_lsp(
|
lsp_store.open_local_buffer_via_lsp(
|
||||||
lsp_location.uri,
|
lsp_location.uri,
|
||||||
language_server.server_id(),
|
language_server.server_id(),
|
||||||
lsp_adapter.name.clone(),
|
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,18 +7,12 @@ mod manifest_store;
|
||||||
mod path_trie;
|
mod path_trie;
|
||||||
mod server_tree;
|
mod server_tree;
|
||||||
|
|
||||||
use std::{
|
use std::{borrow::Borrow, collections::hash_map::Entry, ops::ControlFlow, path::Path, sync::Arc};
|
||||||
borrow::Borrow,
|
|
||||||
collections::{BTreeMap, hash_map::Entry},
|
|
||||||
ops::ControlFlow,
|
|
||||||
path::Path,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Subscription};
|
use gpui::{App, AppContext as _, Context, Entity, Subscription};
|
||||||
use language::{ManifestDelegate, ManifestName, ManifestQuery};
|
use language::{ManifestDelegate, ManifestName, ManifestQuery};
|
||||||
pub use manifest_store::ManifestProviders;
|
pub use manifest_store::ManifestProvidersStore;
|
||||||
use path_trie::{LabelPresence, RootPathTrie, TriePath};
|
use path_trie::{LabelPresence, RootPathTrie, TriePath};
|
||||||
use settings::{SettingsStore, WorktreeId};
|
use settings::{SettingsStore, WorktreeId};
|
||||||
use worktree::{Event as WorktreeEvent, Snapshot, Worktree};
|
use worktree::{Event as WorktreeEvent, Snapshot, Worktree};
|
||||||
|
@ -28,9 +22,7 @@ use crate::{
|
||||||
worktree_store::{WorktreeStore, WorktreeStoreEvent},
|
worktree_store::{WorktreeStore, WorktreeStoreEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use server_tree::{
|
pub(crate) use server_tree::{LanguageServerTree, LanguageServerTreeNode, LaunchDisposition};
|
||||||
AdapterQuery, LanguageServerTree, LanguageServerTreeNode, LaunchDisposition,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WorktreeRoots {
|
struct WorktreeRoots {
|
||||||
roots: RootPathTrie<ManifestName>,
|
roots: RootPathTrie<ManifestName>,
|
||||||
|
@ -81,14 +73,6 @@ pub struct ManifestTree {
|
||||||
_subscriptions: [Subscription; 2],
|
_subscriptions: [Subscription; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub(crate) enum ManifestTreeEvent {
|
|
||||||
WorktreeRemoved(WorktreeId),
|
|
||||||
Cleared,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventEmitter<ManifestTreeEvent> for ManifestTree {}
|
|
||||||
|
|
||||||
impl ManifestTree {
|
impl ManifestTree {
|
||||||
pub fn new(worktree_store: Entity<WorktreeStore>, cx: &mut App) -> Entity<Self> {
|
pub fn new(worktree_store: Entity<WorktreeStore>, cx: &mut App) -> Entity<Self> {
|
||||||
cx.new(|cx| Self {
|
cx.new(|cx| Self {
|
||||||
|
@ -101,30 +85,28 @@ impl ManifestTree {
|
||||||
worktree_roots.roots = RootPathTrie::new();
|
worktree_roots.roots = RootPathTrie::new();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
cx.emit(ManifestTreeEvent::Cleared);
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
worktree_store,
|
worktree_store,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn root_for_path(
|
pub(crate) fn root_for_path(
|
||||||
&mut self,
|
&mut self,
|
||||||
ProjectPath { worktree_id, path }: ProjectPath,
|
ProjectPath { worktree_id, path }: &ProjectPath,
|
||||||
manifests: &mut dyn Iterator<Item = ManifestName>,
|
manifest_name: &ManifestName,
|
||||||
delegate: Arc<dyn ManifestDelegate>,
|
delegate: &Arc<dyn ManifestDelegate>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> BTreeMap<ManifestName, ProjectPath> {
|
) -> Option<ProjectPath> {
|
||||||
debug_assert_eq!(delegate.worktree_id(), worktree_id);
|
debug_assert_eq!(delegate.worktree_id(), *worktree_id);
|
||||||
let mut roots = BTreeMap::from_iter(
|
let (mut marked_path, mut current_presence) = (None, LabelPresence::KnownAbsent);
|
||||||
manifests.map(|manifest| (manifest, (None, LabelPresence::KnownAbsent))),
|
let worktree_roots = match self.root_points.entry(*worktree_id) {
|
||||||
);
|
|
||||||
let worktree_roots = match self.root_points.entry(worktree_id) {
|
|
||||||
Entry::Occupied(occupied_entry) => occupied_entry.get().clone(),
|
Entry::Occupied(occupied_entry) => occupied_entry.get().clone(),
|
||||||
Entry::Vacant(vacant_entry) => {
|
Entry::Vacant(vacant_entry) => {
|
||||||
let Some(worktree) = self
|
let Some(worktree) = self
|
||||||
.worktree_store
|
.worktree_store
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.worktree_for_id(worktree_id, cx)
|
.worktree_for_id(*worktree_id, cx)
|
||||||
else {
|
else {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
};
|
};
|
||||||
|
@ -133,16 +115,16 @@ impl ManifestTree {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let key = TriePath::from(&*path);
|
let key = TriePath::from(&**path);
|
||||||
worktree_roots.read_with(cx, |this, _| {
|
worktree_roots.read_with(cx, |this, _| {
|
||||||
this.roots.walk(&key, &mut |path, labels| {
|
this.roots.walk(&key, &mut |path, labels| {
|
||||||
for (label, presence) in labels {
|
for (label, presence) in labels {
|
||||||
if let Some((marked_path, current_presence)) = roots.get_mut(label) {
|
if label == manifest_name {
|
||||||
if *current_presence > *presence {
|
if current_presence > *presence {
|
||||||
debug_assert!(false, "RootPathTrie precondition violation; while walking the tree label presence is only allowed to increase");
|
debug_assert!(false, "RootPathTrie precondition violation; while walking the tree label presence is only allowed to increase");
|
||||||
}
|
}
|
||||||
*marked_path = Some(ProjectPath {worktree_id, path: path.clone()});
|
marked_path = Some(ProjectPath {worktree_id: *worktree_id, path: path.clone()});
|
||||||
*current_presence = *presence;
|
current_presence = *presence;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -150,12 +132,9 @@ impl ManifestTree {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
for (manifest_name, (root_path, presence)) in &mut roots {
|
if current_presence == LabelPresence::KnownAbsent {
|
||||||
if *presence == LabelPresence::Present {
|
// Some part of the path is unexplored.
|
||||||
continue;
|
let depth = marked_path
|
||||||
}
|
|
||||||
|
|
||||||
let depth = root_path
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|root_path| {
|
.map(|root_path| {
|
||||||
path.strip_prefix(&root_path.path)
|
path.strip_prefix(&root_path.path)
|
||||||
|
@ -165,13 +144,10 @@ impl ManifestTree {
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| path.components().count() + 1);
|
.unwrap_or_else(|| path.components().count() + 1);
|
||||||
|
|
||||||
if depth > 0 {
|
if depth > 0
|
||||||
let Some(provider) = ManifestProviders::global(cx).get(manifest_name.borrow())
|
&& let Some(provider) =
|
||||||
else {
|
ManifestProvidersStore::global(cx).get(manifest_name.borrow())
|
||||||
log::warn!("Manifest provider `{}` not found", manifest_name.as_ref());
|
{
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let root = provider.search(ManifestQuery {
|
let root = provider.search(ManifestQuery {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
depth,
|
depth,
|
||||||
|
@ -182,9 +158,9 @@ impl ManifestTree {
|
||||||
let root = TriePath::from(&*known_root);
|
let root = TriePath::from(&*known_root);
|
||||||
this.roots
|
this.roots
|
||||||
.insert(&root, manifest_name.clone(), LabelPresence::Present);
|
.insert(&root, manifest_name.clone(), LabelPresence::Present);
|
||||||
*presence = LabelPresence::Present;
|
current_presence = LabelPresence::Present;
|
||||||
*root_path = Some(ProjectPath {
|
marked_path = Some(ProjectPath {
|
||||||
worktree_id,
|
worktree_id: *worktree_id,
|
||||||
path: known_root,
|
path: known_root,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -195,25 +171,35 @@ impl ManifestTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
marked_path.filter(|_| current_presence.eq(&LabelPresence::Present))
|
||||||
roots
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(k, (path, presence))| {
|
|
||||||
let path = path?;
|
|
||||||
presence.eq(&LabelPresence::Present).then(|| (k, path))
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn root_for_path_or_worktree_root(
|
||||||
|
&mut self,
|
||||||
|
project_path: &ProjectPath,
|
||||||
|
manifest_name: Option<&ManifestName>,
|
||||||
|
delegate: &Arc<dyn ManifestDelegate>,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> ProjectPath {
|
||||||
|
let worktree_id = project_path.worktree_id;
|
||||||
|
// Backwards-compat: Fill in any adapters for which we did not detect the root as having the project root at the root of a worktree.
|
||||||
|
manifest_name
|
||||||
|
.and_then(|manifest_name| self.root_for_path(project_path, manifest_name, delegate, cx))
|
||||||
|
.unwrap_or_else(|| ProjectPath {
|
||||||
|
worktree_id,
|
||||||
|
path: Arc::from(Path::new("")),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn on_worktree_store_event(
|
fn on_worktree_store_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: Entity<WorktreeStore>,
|
_: Entity<WorktreeStore>,
|
||||||
evt: &WorktreeStoreEvent,
|
evt: &WorktreeStoreEvent,
|
||||||
cx: &mut Context<Self>,
|
_: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
match evt {
|
match evt {
|
||||||
WorktreeStoreEvent::WorktreeRemoved(_, worktree_id) => {
|
WorktreeStoreEvent::WorktreeRemoved(_, worktree_id) => {
|
||||||
self.root_points.remove(&worktree_id);
|
self.root_points.remove(&worktree_id);
|
||||||
cx.emit(ManifestTreeEvent::WorktreeRemoved(*worktree_id));
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -223,6 +209,7 @@ impl ManifestTree {
|
||||||
pub(crate) struct ManifestQueryDelegate {
|
pub(crate) struct ManifestQueryDelegate {
|
||||||
worktree: Snapshot,
|
worktree: Snapshot,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ManifestQueryDelegate {
|
impl ManifestQueryDelegate {
|
||||||
pub fn new(worktree: Snapshot) -> Self {
|
pub fn new(worktree: Snapshot) -> Self {
|
||||||
Self { worktree }
|
Self { worktree }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use collections::HashMap;
|
use collections::{HashMap, HashSet};
|
||||||
use gpui::{App, Global, SharedString};
|
use gpui::{App, Global, SharedString};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::{ops::Deref, sync::Arc};
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
@ -11,13 +11,13 @@ struct ManifestProvidersState {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct ManifestProviders(Arc<RwLock<ManifestProvidersState>>);
|
pub struct ManifestProvidersStore(Arc<RwLock<ManifestProvidersState>>);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct GlobalManifestProvider(ManifestProviders);
|
struct GlobalManifestProvider(ManifestProvidersStore);
|
||||||
|
|
||||||
impl Deref for GlobalManifestProvider {
|
impl Deref for GlobalManifestProvider {
|
||||||
type Target = ManifestProviders;
|
type Target = ManifestProvidersStore;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
|
@ -26,7 +26,7 @@ impl Deref for GlobalManifestProvider {
|
||||||
|
|
||||||
impl Global for GlobalManifestProvider {}
|
impl Global for GlobalManifestProvider {}
|
||||||
|
|
||||||
impl ManifestProviders {
|
impl ManifestProvidersStore {
|
||||||
/// Returns the global [`ManifestStore`].
|
/// Returns the global [`ManifestStore`].
|
||||||
///
|
///
|
||||||
/// Inserts a default [`ManifestStore`] if one does not yet exist.
|
/// Inserts a default [`ManifestStore`] if one does not yet exist.
|
||||||
|
@ -45,4 +45,7 @@ impl ManifestProviders {
|
||||||
pub(super) fn get(&self, name: &SharedString) -> Option<Arc<dyn ManifestProvider>> {
|
pub(super) fn get(&self, name: &SharedString) -> Option<Arc<dyn ManifestProvider>> {
|
||||||
self.0.read().providers.get(name).cloned()
|
self.0.read().providers.get(name).cloned()
|
||||||
}
|
}
|
||||||
|
pub(crate) fn manifest_file_names(&self) -> HashSet<ManifestName> {
|
||||||
|
self.0.read().providers.keys().cloned().collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! ## RPC
|
//! ## RPC
|
||||||
//! LSP Tree is transparent to RPC peers; when clients ask host to spawn a new language server, the host will perform LSP Tree lookup for provided path; it may decide
|
//! LSP Tree is transparent to RPC peers; when clients ask host to spawn a new language server, the host will perform LSP Tree lookup for provided path; it may decide
|
||||||
//! to reuse existing language server. The client maintains it's own LSP Tree that is a subset of host LSP Tree. Done this way, the client does not need to
|
//! to reuse existing language server.
|
||||||
//! ask about suitable language server for each path it interacts with; it can resolve most of the queries locally.
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
@ -14,20 +13,23 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use collections::IndexMap;
|
use collections::IndexMap;
|
||||||
use gpui::{App, AppContext as _, Entity, Subscription};
|
use gpui::{App, Entity};
|
||||||
use language::{
|
use language::{
|
||||||
CachedLspAdapter, LanguageName, LanguageRegistry, ManifestDelegate,
|
CachedLspAdapter, LanguageName, LanguageRegistry, ManifestDelegate, ManifestName, Toolchain,
|
||||||
language_settings::AllLanguageSettings,
|
language_settings::AllLanguageSettings,
|
||||||
};
|
};
|
||||||
use lsp::LanguageServerName;
|
use lsp::LanguageServerName;
|
||||||
use settings::{Settings, SettingsLocation, WorktreeId};
|
use settings::{Settings, SettingsLocation, WorktreeId};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use crate::{LanguageServerId, ProjectPath, project_settings::LspSettings};
|
use crate::{
|
||||||
|
LanguageServerId, ProjectPath, project_settings::LspSettings,
|
||||||
|
toolchain_store::LocalToolchainStore,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{ManifestTree, ManifestTreeEvent};
|
use super::ManifestTree;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub(crate) struct ServersForWorktree {
|
pub(crate) struct ServersForWorktree {
|
||||||
pub(crate) roots: BTreeMap<
|
pub(crate) roots: BTreeMap<
|
||||||
Arc<Path>,
|
Arc<Path>,
|
||||||
|
@ -39,7 +41,7 @@ pub struct LanguageServerTree {
|
||||||
manifest_tree: Entity<ManifestTree>,
|
manifest_tree: Entity<ManifestTree>,
|
||||||
pub(crate) instances: BTreeMap<WorktreeId, ServersForWorktree>,
|
pub(crate) instances: BTreeMap<WorktreeId, ServersForWorktree>,
|
||||||
languages: Arc<LanguageRegistry>,
|
languages: Arc<LanguageRegistry>,
|
||||||
_subscriptions: Subscription,
|
toolchains: Entity<LocalToolchainStore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A node in language server tree represents either:
|
/// A node in language server tree represents either:
|
||||||
|
@ -49,22 +51,15 @@ pub struct LanguageServerTree {
|
||||||
pub struct LanguageServerTreeNode(Weak<InnerTreeNode>);
|
pub struct LanguageServerTreeNode(Weak<InnerTreeNode>);
|
||||||
|
|
||||||
/// Describes a request to launch a language server.
|
/// Describes a request to launch a language server.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct LaunchDisposition<'a> {
|
pub(crate) struct LaunchDisposition {
|
||||||
pub(crate) server_name: &'a LanguageServerName,
|
pub(crate) server_name: LanguageServerName,
|
||||||
|
/// Path to the root directory of a subproject.
|
||||||
pub(crate) path: ProjectPath,
|
pub(crate) path: ProjectPath,
|
||||||
pub(crate) settings: Arc<LspSettings>,
|
pub(crate) settings: Arc<LspSettings>,
|
||||||
|
pub(crate) toolchain: Option<Toolchain>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a InnerTreeNode> for LaunchDisposition<'a> {
|
|
||||||
fn from(value: &'a InnerTreeNode) -> Self {
|
|
||||||
LaunchDisposition {
|
|
||||||
server_name: &value.name,
|
|
||||||
path: value.path.clone(),
|
|
||||||
settings: value.settings.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl LanguageServerTreeNode {
|
impl LanguageServerTreeNode {
|
||||||
/// Returns a language server ID for this node if there is one.
|
/// Returns a language server ID for this node if there is one.
|
||||||
/// Returns None if this node has not been initialized yet or it is no longer in the tree.
|
/// Returns None if this node has not been initialized yet or it is no longer in the tree.
|
||||||
|
@ -76,19 +71,17 @@ impl LanguageServerTreeNode {
|
||||||
/// May return None if the node no longer belongs to the server tree it was created in.
|
/// May return None if the node no longer belongs to the server tree it was created in.
|
||||||
pub(crate) fn server_id_or_init(
|
pub(crate) fn server_id_or_init(
|
||||||
&self,
|
&self,
|
||||||
init: impl FnOnce(LaunchDisposition) -> LanguageServerId,
|
init: impl FnOnce(&Arc<LaunchDisposition>) -> LanguageServerId,
|
||||||
) -> Option<LanguageServerId> {
|
) -> Option<LanguageServerId> {
|
||||||
let this = self.0.upgrade()?;
|
let this = self.0.upgrade()?;
|
||||||
Some(
|
Some(*this.id.get_or_init(|| init(&this.disposition)))
|
||||||
*this
|
|
||||||
.id
|
|
||||||
.get_or_init(|| init(LaunchDisposition::from(&*this))),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a language server name as the language server adapter would return.
|
/// Returns a language server name as the language server adapter would return.
|
||||||
pub fn name(&self) -> Option<LanguageServerName> {
|
pub fn name(&self) -> Option<LanguageServerName> {
|
||||||
self.0.upgrade().map(|node| node.name.clone())
|
self.0
|
||||||
|
.upgrade()
|
||||||
|
.map(|node| node.disposition.server_name.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,126 +94,79 @@ impl From<Weak<InnerTreeNode>> for LanguageServerTreeNode {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InnerTreeNode {
|
pub struct InnerTreeNode {
|
||||||
id: OnceLock<LanguageServerId>,
|
id: OnceLock<LanguageServerId>,
|
||||||
name: LanguageServerName,
|
disposition: Arc<LaunchDisposition>,
|
||||||
path: ProjectPath,
|
|
||||||
settings: Arc<LspSettings>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerTreeNode {
|
impl InnerTreeNode {
|
||||||
fn new(
|
fn new(
|
||||||
name: LanguageServerName,
|
server_name: LanguageServerName,
|
||||||
path: ProjectPath,
|
path: ProjectPath,
|
||||||
settings: impl Into<Arc<LspSettings>>,
|
settings: LspSettings,
|
||||||
|
toolchain: Option<Toolchain>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
InnerTreeNode {
|
InnerTreeNode {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
name,
|
disposition: Arc::new(LaunchDisposition {
|
||||||
|
server_name,
|
||||||
path,
|
path,
|
||||||
settings: settings.into(),
|
settings: settings.into(),
|
||||||
|
toolchain,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines how the list of adapters to query should be constructed.
|
|
||||||
pub(crate) enum AdapterQuery<'a> {
|
|
||||||
/// Search for roots of all adapters associated with a given language name.
|
|
||||||
/// Layman: Look for all project roots along the queried path that have any
|
|
||||||
/// language server associated with this language running.
|
|
||||||
Language(&'a LanguageName),
|
|
||||||
/// Search for roots of adapter with a given name.
|
|
||||||
/// Layman: Look for all project roots along the queried path that have this server running.
|
|
||||||
Adapter(&'a LanguageServerName),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LanguageServerTree {
|
impl LanguageServerTree {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
manifest_tree: Entity<ManifestTree>,
|
manifest_tree: Entity<ManifestTree>,
|
||||||
languages: Arc<LanguageRegistry>,
|
languages: Arc<LanguageRegistry>,
|
||||||
cx: &mut App,
|
toolchains: Entity<LocalToolchainStore>,
|
||||||
) -> Entity<Self> {
|
) -> Self {
|
||||||
cx.new(|cx| Self {
|
Self {
|
||||||
_subscriptions: cx.subscribe(&manifest_tree, |_: &mut Self, _, event, _| {
|
|
||||||
if event == &ManifestTreeEvent::Cleared {}
|
|
||||||
}),
|
|
||||||
manifest_tree,
|
manifest_tree,
|
||||||
instances: Default::default(),
|
instances: Default::default(),
|
||||||
|
|
||||||
languages,
|
languages,
|
||||||
})
|
toolchains,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all initialized language server IDs for a given path.
|
||||||
|
pub(crate) fn get<'a>(
|
||||||
|
&'a self,
|
||||||
|
path: ProjectPath,
|
||||||
|
language_name: LanguageName,
|
||||||
|
manifest_name: Option<&ManifestName>,
|
||||||
|
delegate: &Arc<dyn ManifestDelegate>,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> impl Iterator<Item = LanguageServerId> + 'a {
|
||||||
|
let manifest_location = self.manifest_location_for_path(&path, manifest_name, delegate, cx);
|
||||||
|
let adapters = self.adapters_for_language(&manifest_location, &language_name, cx);
|
||||||
|
self.get_with_adapters(manifest_location, adapters)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all language server root points for a given path and language; the language servers might already be initialized at a given path.
|
/// Get all language server root points for a given path and language; the language servers might already be initialized at a given path.
|
||||||
pub(crate) fn get<'a>(
|
pub(crate) fn walk<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
path: ProjectPath,
|
path: ProjectPath,
|
||||||
query: AdapterQuery<'_>,
|
language_name: LanguageName,
|
||||||
delegate: Arc<dyn ManifestDelegate>,
|
manifest_name: Option<&ManifestName>,
|
||||||
cx: &mut App,
|
delegate: &Arc<dyn ManifestDelegate>,
|
||||||
|
cx: &'a mut App,
|
||||||
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
||||||
let settings_location = SettingsLocation {
|
let manifest_location = self.manifest_location_for_path(&path, manifest_name, delegate, cx);
|
||||||
worktree_id: path.worktree_id,
|
let adapters = self.adapters_for_language(&manifest_location, &language_name, cx);
|
||||||
path: &path.path,
|
self.init_with_adapters(manifest_location, language_name, adapters, cx)
|
||||||
};
|
|
||||||
let adapters = match query {
|
|
||||||
AdapterQuery::Language(language_name) => {
|
|
||||||
self.adapters_for_language(settings_location, language_name, cx)
|
|
||||||
}
|
|
||||||
AdapterQuery::Adapter(language_server_name) => {
|
|
||||||
IndexMap::from_iter(self.adapter_for_name(language_server_name).map(|adapter| {
|
|
||||||
(
|
|
||||||
adapter.name(),
|
|
||||||
(LspSettings::default(), BTreeSet::new(), adapter),
|
|
||||||
)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.get_with_adapters(path, adapters, delegate, cx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_with_adapters<'a>(
|
fn init_with_adapters<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
path: ProjectPath,
|
root_path: ProjectPath,
|
||||||
adapters: IndexMap<
|
language_name: LanguageName,
|
||||||
LanguageServerName,
|
adapters: IndexMap<LanguageServerName, (LspSettings, Arc<CachedLspAdapter>)>,
|
||||||
(LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>),
|
cx: &'a App,
|
||||||
>,
|
|
||||||
delegate: Arc<dyn ManifestDelegate>,
|
|
||||||
cx: &mut App,
|
|
||||||
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
||||||
let worktree_id = path.worktree_id;
|
adapters.into_iter().map(move |(_, (settings, adapter))| {
|
||||||
|
let root_path = root_path.clone();
|
||||||
let mut manifest_to_adapters = BTreeMap::default();
|
|
||||||
for (_, _, adapter) in adapters.values() {
|
|
||||||
if let Some(manifest_name) = adapter.manifest_name() {
|
|
||||||
manifest_to_adapters
|
|
||||||
.entry(manifest_name)
|
|
||||||
.or_insert_with(Vec::default)
|
|
||||||
.push(adapter.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let roots = self.manifest_tree.update(cx, |this, cx| {
|
|
||||||
this.root_for_path(
|
|
||||||
path,
|
|
||||||
&mut manifest_to_adapters.keys().cloned(),
|
|
||||||
delegate,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let root_path = std::cell::LazyCell::new(move || ProjectPath {
|
|
||||||
worktree_id,
|
|
||||||
path: Arc::from("".as_ref()),
|
|
||||||
});
|
|
||||||
adapters
|
|
||||||
.into_iter()
|
|
||||||
.map(move |(_, (settings, new_languages, adapter))| {
|
|
||||||
// Backwards-compat: Fill in any adapters for which we did not detect the root as having the project root at the root of a worktree.
|
|
||||||
let root_path = adapter
|
|
||||||
.manifest_name()
|
|
||||||
.and_then(|name| roots.get(&name))
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_else(|| root_path.clone());
|
|
||||||
|
|
||||||
let inner_node = self
|
let inner_node = self
|
||||||
.instances
|
.instances
|
||||||
.entry(root_path.worktree_id)
|
.entry(root_path.worktree_id)
|
||||||
|
@ -230,31 +176,67 @@ impl LanguageServerTree {
|
||||||
.or_default()
|
.or_default()
|
||||||
.entry(adapter.name());
|
.entry(adapter.name());
|
||||||
let (node, languages) = inner_node.or_insert_with(|| {
|
let (node, languages) = inner_node.or_insert_with(|| {
|
||||||
|
let toolchain = self.toolchains.read(cx).active_toolchain(
|
||||||
|
root_path.worktree_id,
|
||||||
|
&root_path.path,
|
||||||
|
language_name.clone(),
|
||||||
|
);
|
||||||
(
|
(
|
||||||
Arc::new(InnerTreeNode::new(
|
Arc::new(InnerTreeNode::new(
|
||||||
adapter.name(),
|
adapter.name(),
|
||||||
root_path.clone(),
|
root_path.clone(),
|
||||||
settings.clone(),
|
settings.clone(),
|
||||||
|
toolchain,
|
||||||
)),
|
)),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
languages.extend(new_languages.iter().cloned());
|
languages.insert(language_name.clone());
|
||||||
Arc::downgrade(&node).into()
|
Arc::downgrade(&node).into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adapter_for_name(&self, name: &LanguageServerName) -> Option<Arc<CachedLspAdapter>> {
|
fn get_with_adapters<'a>(
|
||||||
self.languages.adapter_for_name(name)
|
&'a self,
|
||||||
|
root_path: ProjectPath,
|
||||||
|
adapters: IndexMap<LanguageServerName, (LspSettings, Arc<CachedLspAdapter>)>,
|
||||||
|
) -> impl Iterator<Item = LanguageServerId> + 'a {
|
||||||
|
adapters.into_iter().filter_map(move |(_, (_, adapter))| {
|
||||||
|
let root_path = root_path.clone();
|
||||||
|
let inner_node = self
|
||||||
|
.instances
|
||||||
|
.get(&root_path.worktree_id)?
|
||||||
|
.roots
|
||||||
|
.get(&root_path.path)?
|
||||||
|
.get(&adapter.name())?;
|
||||||
|
inner_node.0.id.get().copied()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn manifest_location_for_path(
|
||||||
|
&self,
|
||||||
|
path: &ProjectPath,
|
||||||
|
manifest_name: Option<&ManifestName>,
|
||||||
|
delegate: &Arc<dyn ManifestDelegate>,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> ProjectPath {
|
||||||
|
// Find out what the root location of our subproject is.
|
||||||
|
// That's where we'll look for language settings (that include a set of language servers).
|
||||||
|
self.manifest_tree.update(cx, |this, cx| {
|
||||||
|
this.root_for_path_or_worktree_root(path, manifest_name, delegate, cx)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adapters_for_language(
|
fn adapters_for_language(
|
||||||
&self,
|
&self,
|
||||||
settings_location: SettingsLocation,
|
manifest_location: &ProjectPath,
|
||||||
language_name: &LanguageName,
|
language_name: &LanguageName,
|
||||||
cx: &App,
|
cx: &App,
|
||||||
) -> IndexMap<LanguageServerName, (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>)>
|
) -> IndexMap<LanguageServerName, (LspSettings, Arc<CachedLspAdapter>)> {
|
||||||
{
|
let settings_location = SettingsLocation {
|
||||||
|
worktree_id: manifest_location.worktree_id,
|
||||||
|
path: &manifest_location.path,
|
||||||
|
};
|
||||||
let settings = AllLanguageSettings::get(Some(settings_location), cx).language(
|
let settings = AllLanguageSettings::get(Some(settings_location), cx).language(
|
||||||
Some(settings_location),
|
Some(settings_location),
|
||||||
Some(language_name),
|
Some(language_name),
|
||||||
|
@ -295,14 +277,7 @@ impl LanguageServerTree {
|
||||||
)
|
)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
Some((
|
Some((adapter.name(), (adapter_settings, adapter)))
|
||||||
adapter.name(),
|
|
||||||
(
|
|
||||||
adapter_settings,
|
|
||||||
BTreeSet::from_iter([language_name.clone()]),
|
|
||||||
adapter,
|
|
||||||
),
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
.collect::<IndexMap<_, _>>();
|
.collect::<IndexMap<_, _>>();
|
||||||
// After starting all the language servers, reorder them to reflect the desired order
|
// After starting all the language servers, reorder them to reflect the desired order
|
||||||
|
@ -315,17 +290,23 @@ impl LanguageServerTree {
|
||||||
&language_name,
|
&language_name,
|
||||||
adapters_with_settings
|
adapters_with_settings
|
||||||
.values()
|
.values()
|
||||||
.map(|(_, _, adapter)| adapter.clone())
|
.map(|(_, adapter)| adapter.clone())
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
|
||||||
adapters_with_settings
|
adapters_with_settings
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebasing a tree:
|
/// Server Tree is built up incrementally via queries for distinct paths of the worktree.
|
||||||
// - Clears it out
|
/// Results of these queries have to be invalidated when data used to build the tree changes.
|
||||||
// - Provides you with the indirect access to the old tree while you're reinitializing a new one (by querying it).
|
///
|
||||||
pub(crate) fn rebase(&mut self) -> ServerTreeRebase<'_> {
|
/// The environment of a server tree is a set of all user settings.
|
||||||
|
/// Rebasing a tree means invalidating it and building up a new one while reusing the old tree where applicable.
|
||||||
|
/// We want to reuse the old tree in order to preserve as many of the running language servers as possible.
|
||||||
|
/// E.g. if the user disables one of their language servers for Python, we don't want to shut down any language servers unaffected by this settings change.
|
||||||
|
///
|
||||||
|
/// Thus, [`ServerTreeRebase`] mimics the interface of a [`ServerTree`], except that it tries to find a matching language server in the old tree before handing out an uninitialized node.
|
||||||
|
pub(crate) fn rebase(&mut self) -> ServerTreeRebase {
|
||||||
ServerTreeRebase::new(self)
|
ServerTreeRebase::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,16 +335,16 @@ impl LanguageServerTree {
|
||||||
.roots
|
.roots
|
||||||
.entry(Arc::from(Path::new("")))
|
.entry(Arc::from(Path::new("")))
|
||||||
.or_default()
|
.or_default()
|
||||||
.entry(node.name.clone())
|
.entry(node.disposition.server_name.clone())
|
||||||
.or_insert_with(|| (node, BTreeSet::new()))
|
.or_insert_with(|| (node, BTreeSet::new()))
|
||||||
.1
|
.1
|
||||||
.insert(language_name);
|
.insert(language_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ServerTreeRebase<'a> {
|
pub(crate) struct ServerTreeRebase {
|
||||||
old_contents: BTreeMap<WorktreeId, ServersForWorktree>,
|
old_contents: BTreeMap<WorktreeId, ServersForWorktree>,
|
||||||
new_tree: &'a mut LanguageServerTree,
|
new_tree: LanguageServerTree,
|
||||||
/// All server IDs seen in the old tree.
|
/// All server IDs seen in the old tree.
|
||||||
all_server_ids: BTreeMap<LanguageServerId, LanguageServerName>,
|
all_server_ids: BTreeMap<LanguageServerId, LanguageServerName>,
|
||||||
/// Server IDs we've preserved for a new iteration of the tree. `all_server_ids - rebased_server_ids` is the
|
/// Server IDs we've preserved for a new iteration of the tree. `all_server_ids - rebased_server_ids` is the
|
||||||
|
@ -371,9 +352,9 @@ pub(crate) struct ServerTreeRebase<'a> {
|
||||||
rebased_server_ids: BTreeSet<LanguageServerId>,
|
rebased_server_ids: BTreeSet<LanguageServerId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tree> ServerTreeRebase<'tree> {
|
impl ServerTreeRebase {
|
||||||
fn new(new_tree: &'tree mut LanguageServerTree) -> Self {
|
fn new(old_tree: &LanguageServerTree) -> Self {
|
||||||
let old_contents = std::mem::take(&mut new_tree.instances);
|
let old_contents = old_tree.instances.clone();
|
||||||
let all_server_ids = old_contents
|
let all_server_ids = old_contents
|
||||||
.values()
|
.values()
|
||||||
.flat_map(|nodes| {
|
.flat_map(|nodes| {
|
||||||
|
@ -384,69 +365,68 @@ impl<'tree> ServerTreeRebase<'tree> {
|
||||||
.id
|
.id
|
||||||
.get()
|
.get()
|
||||||
.copied()
|
.copied()
|
||||||
.map(|id| (id, server.0.name.clone()))
|
.map(|id| (id, server.0.disposition.server_name.clone()))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
let new_tree = LanguageServerTree::new(
|
||||||
|
old_tree.manifest_tree.clone(),
|
||||||
|
old_tree.languages.clone(),
|
||||||
|
old_tree.toolchains.clone(),
|
||||||
|
);
|
||||||
Self {
|
Self {
|
||||||
old_contents,
|
old_contents,
|
||||||
new_tree,
|
|
||||||
all_server_ids,
|
all_server_ids,
|
||||||
|
new_tree,
|
||||||
rebased_server_ids: BTreeSet::new(),
|
rebased_server_ids: BTreeSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get<'a>(
|
pub(crate) fn walk<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
path: ProjectPath,
|
path: ProjectPath,
|
||||||
query: AdapterQuery<'_>,
|
language_name: LanguageName,
|
||||||
|
manifest_name: Option<&ManifestName>,
|
||||||
delegate: Arc<dyn ManifestDelegate>,
|
delegate: Arc<dyn ManifestDelegate>,
|
||||||
cx: &mut App,
|
cx: &'a mut App,
|
||||||
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
||||||
let settings_location = SettingsLocation {
|
let manifest =
|
||||||
worktree_id: path.worktree_id,
|
|
||||||
path: &path.path,
|
|
||||||
};
|
|
||||||
let adapters = match query {
|
|
||||||
AdapterQuery::Language(language_name) => {
|
|
||||||
self.new_tree
|
self.new_tree
|
||||||
.adapters_for_language(settings_location, language_name, cx)
|
.manifest_location_for_path(&path, manifest_name, &delegate, cx);
|
||||||
}
|
let adapters = self
|
||||||
AdapterQuery::Adapter(language_server_name) => {
|
.new_tree
|
||||||
IndexMap::from_iter(self.new_tree.adapter_for_name(language_server_name).map(
|
.adapters_for_language(&manifest, &language_name, cx);
|
||||||
|adapter| {
|
|
||||||
(
|
|
||||||
adapter.name(),
|
|
||||||
(LspSettings::default(), BTreeSet::new(), adapter),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.new_tree
|
self.new_tree
|
||||||
.get_with_adapters(path, adapters, delegate, cx)
|
.init_with_adapters(manifest, language_name, adapters, cx)
|
||||||
.filter_map(|node| {
|
.filter_map(|node| {
|
||||||
// Inspect result of the query and initialize it ourselves before
|
// Inspect result of the query and initialize it ourselves before
|
||||||
// handing it off to the caller.
|
// handing it off to the caller.
|
||||||
let disposition = node.0.upgrade()?;
|
let live_node = node.0.upgrade()?;
|
||||||
|
|
||||||
if disposition.id.get().is_some() {
|
if live_node.id.get().is_some() {
|
||||||
return Some(node);
|
return Some(node);
|
||||||
}
|
}
|
||||||
|
let disposition = &live_node.disposition;
|
||||||
let Some((existing_node, _)) = self
|
let Some((existing_node, _)) = self
|
||||||
.old_contents
|
.old_contents
|
||||||
.get(&disposition.path.worktree_id)
|
.get(&disposition.path.worktree_id)
|
||||||
.and_then(|worktree_nodes| worktree_nodes.roots.get(&disposition.path.path))
|
.and_then(|worktree_nodes| worktree_nodes.roots.get(&disposition.path.path))
|
||||||
.and_then(|roots| roots.get(&disposition.name))
|
.and_then(|roots| roots.get(&disposition.server_name))
|
||||||
.filter(|(old_node, _)| disposition.settings == old_node.settings)
|
.filter(|(old_node, _)| {
|
||||||
|
(&disposition.toolchain, &disposition.settings)
|
||||||
|
== (
|
||||||
|
&old_node.disposition.toolchain,
|
||||||
|
&old_node.disposition.settings,
|
||||||
|
)
|
||||||
|
})
|
||||||
else {
|
else {
|
||||||
return Some(node);
|
return Some(node);
|
||||||
};
|
};
|
||||||
if let Some(existing_id) = existing_node.id.get() {
|
if let Some(existing_id) = existing_node.id.get() {
|
||||||
self.rebased_server_ids.insert(*existing_id);
|
self.rebased_server_ids.insert(*existing_id);
|
||||||
disposition.id.set(*existing_id).ok();
|
live_node.id.set(*existing_id).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(node)
|
Some(node)
|
||||||
|
@ -454,11 +434,19 @@ impl<'tree> ServerTreeRebase<'tree> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns IDs of servers that are no longer referenced (and can be shut down).
|
/// Returns IDs of servers that are no longer referenced (and can be shut down).
|
||||||
pub(crate) fn finish(self) -> BTreeMap<LanguageServerId, LanguageServerName> {
|
pub(crate) fn finish(
|
||||||
|
self,
|
||||||
|
) -> (
|
||||||
|
LanguageServerTree,
|
||||||
|
BTreeMap<LanguageServerId, LanguageServerName>,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
self.new_tree,
|
||||||
self.all_server_ids
|
self.all_server_ids
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(id, _)| !self.rebased_server_ids.contains(id))
|
.filter(|(id, _)| !self.rebased_server_ids.contains(id))
|
||||||
.collect()
|
.collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn server_tree(&mut self) -> &mut LanguageServerTree {
|
pub(crate) fn server_tree(&mut self) -> &mut LanguageServerTree {
|
||||||
|
|
|
@ -84,7 +84,7 @@ use lsp::{
|
||||||
};
|
};
|
||||||
use lsp_command::*;
|
use lsp_command::*;
|
||||||
use lsp_store::{CompletionDocumentation, LspFormatTarget, OpenLspBufferHandle};
|
use lsp_store::{CompletionDocumentation, LspFormatTarget, OpenLspBufferHandle};
|
||||||
pub use manifest_tree::ManifestProviders;
|
pub use manifest_tree::ManifestProvidersStore;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
pub use prettier_store::PrettierStore;
|
pub use prettier_store::PrettierStore;
|
||||||
|
@ -1115,7 +1115,11 @@ impl Project {
|
||||||
buffer_store.clone(),
|
buffer_store.clone(),
|
||||||
worktree_store.clone(),
|
worktree_store.clone(),
|
||||||
prettier_store.clone(),
|
prettier_store.clone(),
|
||||||
toolchain_store.clone(),
|
toolchain_store
|
||||||
|
.read(cx)
|
||||||
|
.as_local_store()
|
||||||
|
.expect("Toolchain store to be local")
|
||||||
|
.clone(),
|
||||||
environment.clone(),
|
environment.clone(),
|
||||||
manifest_tree,
|
manifest_tree,
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
|
@ -1260,7 +1264,6 @@ impl Project {
|
||||||
LspStore::new_remote(
|
LspStore::new_remote(
|
||||||
buffer_store.clone(),
|
buffer_store.clone(),
|
||||||
worktree_store.clone(),
|
worktree_store.clone(),
|
||||||
Some(toolchain_store.clone()),
|
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
ssh_proto.clone(),
|
ssh_proto.clone(),
|
||||||
SSH_PROJECT_ID,
|
SSH_PROJECT_ID,
|
||||||
|
@ -1485,7 +1488,6 @@ impl Project {
|
||||||
let mut lsp_store = LspStore::new_remote(
|
let mut lsp_store = LspStore::new_remote(
|
||||||
buffer_store.clone(),
|
buffer_store.clone(),
|
||||||
worktree_store.clone(),
|
worktree_store.clone(),
|
||||||
None,
|
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
client.clone().into(),
|
client.clone().into(),
|
||||||
remote_id,
|
remote_id,
|
||||||
|
@ -3596,16 +3598,10 @@ impl Project {
|
||||||
&mut self,
|
&mut self,
|
||||||
abs_path: lsp::Url,
|
abs_path: lsp::Url,
|
||||||
language_server_id: LanguageServerId,
|
language_server_id: LanguageServerId,
|
||||||
language_server_name: LanguageServerName,
|
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Entity<Buffer>>> {
|
) -> Task<Result<Entity<Buffer>>> {
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.open_local_buffer_via_lsp(
|
lsp_store.open_local_buffer_via_lsp(abs_path, language_server_id, cx)
|
||||||
abs_path,
|
|
||||||
language_server_id,
|
|
||||||
language_server_name,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use settings::{
|
||||||
SettingsStore, parse_json_with_comments, watch_config_file,
|
SettingsStore, parse_json_with_comments, watch_config_file,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::BTreeMap,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
|
@ -518,16 +519,15 @@ impl Default for InlineBlameSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
|
||||||
pub struct BinarySettings {
|
pub struct BinarySettings {
|
||||||
pub path: Option<String>,
|
pub path: Option<String>,
|
||||||
pub arguments: Option<Vec<String>>,
|
pub arguments: Option<Vec<String>>,
|
||||||
// this can't be an FxHashMap because the extension APIs require the default SipHash
|
pub env: Option<BTreeMap<String, String>>,
|
||||||
pub env: Option<std::collections::HashMap<String, String>>,
|
|
||||||
pub ignore_system_version: Option<bool>,
|
pub ignore_system_version: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct LspSettings {
|
pub struct LspSettings {
|
||||||
pub binary: Option<BinarySettings>,
|
pub binary: Option<BinarySettings>,
|
||||||
|
|
|
@ -1099,9 +1099,9 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
||||||
let prev_read_dir_count = fs.read_dir_call_count();
|
let prev_read_dir_count = fs.read_dir_call_count();
|
||||||
|
|
||||||
let fake_server = fake_servers.next().await.unwrap();
|
let fake_server = fake_servers.next().await.unwrap();
|
||||||
let (server_id, server_name) = lsp_store.read_with(cx, |lsp_store, _| {
|
let server_id = lsp_store.read_with(cx, |lsp_store, _| {
|
||||||
let (id, status) = lsp_store.language_server_statuses().next().unwrap();
|
let (id, _) = lsp_store.language_server_statuses().next().unwrap();
|
||||||
(id, status.name.clone())
|
id
|
||||||
});
|
});
|
||||||
|
|
||||||
// Simulate jumping to a definition in a dependency outside of the worktree.
|
// Simulate jumping to a definition in a dependency outside of the worktree.
|
||||||
|
@ -1110,7 +1110,6 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
||||||
project.open_local_buffer_via_lsp(
|
project.open_local_buffer_via_lsp(
|
||||||
lsp::Url::from_file_path(path!("/the-registry/dep1/src/dep1.rs")).unwrap(),
|
lsp::Url::from_file_path(path!("/the-registry/dep1/src/dep1.rs")).unwrap(),
|
||||||
server_id,
|
server_id,
|
||||||
server_name.clone(),
|
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -11,7 +11,10 @@ use collections::BTreeMap;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Subscription, Task, WeakEntity,
|
App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Subscription, Task, WeakEntity,
|
||||||
};
|
};
|
||||||
use language::{LanguageName, LanguageRegistry, LanguageToolchainStore, Toolchain, ToolchainList};
|
use language::{
|
||||||
|
LanguageName, LanguageRegistry, LanguageToolchainStore, ManifestDelegate, Toolchain,
|
||||||
|
ToolchainList,
|
||||||
|
};
|
||||||
use rpc::{
|
use rpc::{
|
||||||
AnyProtoClient, TypedEnvelope,
|
AnyProtoClient, TypedEnvelope,
|
||||||
proto::{self, FromProto, ToProto},
|
proto::{self, FromProto, ToProto},
|
||||||
|
@ -104,9 +107,11 @@ impl ToolchainStore {
|
||||||
cx: &App,
|
cx: &App,
|
||||||
) -> Task<Option<Toolchain>> {
|
) -> Task<Option<Toolchain>> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
ToolchainStoreInner::Local(local, _) => {
|
ToolchainStoreInner::Local(local, _) => Task::ready(local.read(cx).active_toolchain(
|
||||||
local.read(cx).active_toolchain(path, language_name, cx)
|
path.worktree_id,
|
||||||
}
|
&path.path,
|
||||||
|
language_name,
|
||||||
|
)),
|
||||||
ToolchainStoreInner::Remote(remote) => {
|
ToolchainStoreInner::Remote(remote) => {
|
||||||
remote.read(cx).active_toolchain(path, language_name, cx)
|
remote.read(cx).active_toolchain(path, language_name, cx)
|
||||||
}
|
}
|
||||||
|
@ -232,9 +237,15 @@ impl ToolchainStore {
|
||||||
ToolchainStoreInner::Remote(remote) => Arc::new(RemoteStore(remote.downgrade())),
|
ToolchainStoreInner::Remote(remote) => Arc::new(RemoteStore(remote.downgrade())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn as_local_store(&self) -> Option<&Entity<LocalToolchainStore>> {
|
||||||
|
match &self.0 {
|
||||||
|
ToolchainStoreInner::Local(local, _) => Some(local),
|
||||||
|
ToolchainStoreInner::Remote(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LocalToolchainStore {
|
pub struct LocalToolchainStore {
|
||||||
languages: Arc<LanguageRegistry>,
|
languages: Arc<LanguageRegistry>,
|
||||||
worktree_store: Entity<WorktreeStore>,
|
worktree_store: Entity<WorktreeStore>,
|
||||||
project_environment: Entity<ProjectEnvironment>,
|
project_environment: Entity<ProjectEnvironment>,
|
||||||
|
@ -243,20 +254,19 @@ struct LocalToolchainStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl language::LanguageToolchainStore for LocalStore {
|
impl language::LocalLanguageToolchainStore for LocalStore {
|
||||||
async fn active_toolchain(
|
fn active_toolchain(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
worktree_id: WorktreeId,
|
worktree_id: WorktreeId,
|
||||||
path: Arc<Path>,
|
path: &Arc<Path>,
|
||||||
language_name: LanguageName,
|
language_name: LanguageName,
|
||||||
cx: &mut AsyncApp,
|
cx: &mut AsyncApp,
|
||||||
) -> Option<Toolchain> {
|
) -> Option<Toolchain> {
|
||||||
self.0
|
self.0
|
||||||
.update(cx, |this, cx| {
|
.update(cx, |this, _| {
|
||||||
this.active_toolchain(ProjectPath { worktree_id, path }, language_name, cx)
|
this.active_toolchain(worktree_id, path, language_name)
|
||||||
})
|
})
|
||||||
.ok()?
|
.ok()?
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,19 +289,18 @@ impl language::LanguageToolchainStore for RemoteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EmptyToolchainStore;
|
pub struct EmptyToolchainStore;
|
||||||
#[async_trait(?Send)]
|
impl language::LocalLanguageToolchainStore for EmptyToolchainStore {
|
||||||
impl language::LanguageToolchainStore for EmptyToolchainStore {
|
fn active_toolchain(
|
||||||
async fn active_toolchain(
|
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
_: WorktreeId,
|
_: WorktreeId,
|
||||||
_: Arc<Path>,
|
_: &Arc<Path>,
|
||||||
_: LanguageName,
|
_: LanguageName,
|
||||||
_: &mut AsyncApp,
|
_: &mut AsyncApp,
|
||||||
) -> Option<Toolchain> {
|
) -> Option<Toolchain> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct LocalStore(WeakEntity<LocalToolchainStore>);
|
pub(crate) struct LocalStore(WeakEntity<LocalToolchainStore>);
|
||||||
struct RemoteStore(WeakEntity<RemoteToolchainStore>);
|
struct RemoteStore(WeakEntity<RemoteToolchainStore>);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -349,17 +358,13 @@ impl LocalToolchainStore {
|
||||||
.flatten()?;
|
.flatten()?;
|
||||||
let worktree_id = snapshot.id();
|
let worktree_id = snapshot.id();
|
||||||
let worktree_root = snapshot.abs_path().to_path_buf();
|
let worktree_root = snapshot.abs_path().to_path_buf();
|
||||||
|
let delegate =
|
||||||
|
Arc::from(ManifestQueryDelegate::new(snapshot)) as Arc<dyn ManifestDelegate>;
|
||||||
let relative_path = manifest_tree
|
let relative_path = manifest_tree
|
||||||
.update(cx, |this, cx| {
|
.update(cx, |this, cx| {
|
||||||
this.root_for_path(
|
this.root_for_path(&path, &manifest_name, &delegate, cx)
|
||||||
path,
|
|
||||||
&mut std::iter::once(manifest_name.clone()),
|
|
||||||
Arc::new(ManifestQueryDelegate::new(snapshot)),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.ok()?
|
.ok()?
|
||||||
.remove(&manifest_name)
|
|
||||||
.unwrap_or_else(|| ProjectPath {
|
.unwrap_or_else(|| ProjectPath {
|
||||||
path: Arc::from(Path::new("")),
|
path: Arc::from(Path::new("")),
|
||||||
worktree_id,
|
worktree_id,
|
||||||
|
@ -394,21 +399,20 @@ impl LocalToolchainStore {
|
||||||
}
|
}
|
||||||
pub(crate) fn active_toolchain(
|
pub(crate) fn active_toolchain(
|
||||||
&self,
|
&self,
|
||||||
path: ProjectPath,
|
worktree_id: WorktreeId,
|
||||||
|
relative_path: &Arc<Path>,
|
||||||
language_name: LanguageName,
|
language_name: LanguageName,
|
||||||
_: &App,
|
) -> Option<Toolchain> {
|
||||||
) -> Task<Option<Toolchain>> {
|
let ancestors = relative_path.ancestors();
|
||||||
let ancestors = path.path.ancestors();
|
|
||||||
Task::ready(
|
|
||||||
self.active_toolchains
|
self.active_toolchains
|
||||||
.get(&(path.worktree_id, language_name))
|
.get(&(worktree_id, language_name))
|
||||||
.and_then(|paths| {
|
.and_then(|paths| {
|
||||||
ancestors
|
ancestors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find_map(|root_path| paths.get(root_path))
|
.find_map(|root_path| paths.get(root_path))
|
||||||
})
|
})
|
||||||
.cloned(),
|
.cloned()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct RemoteToolchainStore {
|
struct RemoteToolchainStore {
|
||||||
|
|
|
@ -171,7 +171,11 @@ impl HeadlessProject {
|
||||||
buffer_store.clone(),
|
buffer_store.clone(),
|
||||||
worktree_store.clone(),
|
worktree_store.clone(),
|
||||||
prettier_store.clone(),
|
prettier_store.clone(),
|
||||||
toolchain_store.clone(),
|
toolchain_store
|
||||||
|
.read(cx)
|
||||||
|
.as_local_store()
|
||||||
|
.expect("Toolchain store to be local")
|
||||||
|
.clone(),
|
||||||
environment,
|
environment,
|
||||||
manifest_tree,
|
manifest_tree,
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue