Add language toolchains (#19576)

This PR adds support for selecting toolchains for a given language (e.g.
Rust toolchains or Python virtual environments) with support for SSH
projects provided out of the box. For Python we piggy-back off of
[PET](https://github.com/microsoft/python-environment-tools), a library
maintained by Microsoft.
Closes #16421
Closes #7646

Release Notes:

- Added toolchain selector to the status bar (with initial support for
Python virtual environments)
This commit is contained in:
Piotr Osiewicz 2024-10-28 15:34:03 +01:00 committed by GitHub
parent 03bd95405b
commit cdddb4d360
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 2221 additions and 133 deletions

View file

@ -4,7 +4,7 @@ use crate::{
},
task_context::ContextProvider,
with_parser, CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher,
LanguageServerName, LspAdapter, PLAIN_TEXT,
LanguageServerName, LspAdapter, ToolchainLister, PLAIN_TEXT,
};
use anyhow::{anyhow, Context, Result};
use collections::{hash_map, HashMap, HashSet};
@ -75,6 +75,13 @@ impl<'a> From<&'a str> for LanguageName {
}
}
impl From<LanguageName> for String {
fn from(value: LanguageName) -> Self {
let value: &str = &value.0;
Self::from(value)
}
}
pub struct LanguageRegistry {
state: RwLock<LanguageRegistryState>,
language_server_download_dir: Option<Arc<Path>>,
@ -123,16 +130,7 @@ pub struct AvailableLanguage {
name: LanguageName,
grammar: Option<Arc<str>>,
matcher: LanguageMatcher,
load: Arc<
dyn Fn() -> Result<(
LanguageConfig,
LanguageQueries,
Option<Arc<dyn ContextProvider>>,
)>
+ 'static
+ Send
+ Sync,
>,
load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
loaded: bool,
}
@ -200,6 +198,13 @@ struct LspBinaryStatusSender {
txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(LanguageServerName, LanguageServerBinaryStatus)>>>>,
}
pub struct LoadedLanguage {
pub config: LanguageConfig,
pub queries: LanguageQueries,
pub context_provider: Option<Arc<dyn ContextProvider>>,
pub toolchain_provider: Option<Arc<dyn ToolchainLister>>,
}
impl LanguageRegistry {
pub fn new(executor: BackgroundExecutor) -> Self {
let this = Self {
@ -283,7 +288,14 @@ impl LanguageRegistry {
config.name.clone(),
config.grammar.clone(),
config.matcher.clone(),
move || Ok((config.clone(), Default::default(), None)),
move || {
Ok(LoadedLanguage {
config: config.clone(),
queries: Default::default(),
toolchain_provider: None,
context_provider: None,
})
},
)
}
@ -424,14 +436,7 @@ impl LanguageRegistry {
name: LanguageName,
grammar_name: Option<Arc<str>>,
matcher: LanguageMatcher,
load: impl Fn() -> Result<(
LanguageConfig,
LanguageQueries,
Option<Arc<dyn ContextProvider>>,
)>
+ 'static
+ Send
+ Sync,
load: impl Fn() -> Result<LoadedLanguage> + 'static + Send + Sync,
) {
let load = Arc::new(load);
let state = &mut *self.state.write();
@ -726,16 +731,18 @@ impl LanguageRegistry {
self.executor
.spawn(async move {
let language = async {
let (config, queries, provider) = (language_load)()?;
if let Some(grammar) = config.grammar.clone() {
let loaded_language = (language_load)()?;
if let Some(grammar) = loaded_language.config.grammar.clone() {
let grammar = Some(this.get_or_load_grammar(grammar).await?);
Language::new_with_id(id, config, grammar)
.with_context_provider(provider)
.with_queries(queries)
Language::new_with_id(id, loaded_language.config, grammar)
.with_context_provider(loaded_language.context_provider)
.with_toolchain_lister(loaded_language.toolchain_provider)
.with_queries(loaded_language.queries)
} else {
Ok(Language::new_with_id(id, config, None)
.with_context_provider(provider))
Ok(Language::new_with_id(id, loaded_language.config, None)
.with_context_provider(loaded_language.context_provider)
.with_toolchain_lister(loaded_language.toolchain_provider))
}
}
.await;