1253 lines · 43.6 KB · Rust
RawDownload
use crate::{    CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher,    LanguageServerName, LspAdapter, PLAIN_TEXT, ToolchainLister,    language_settings::{        AllLanguageSettingsContent, LanguageSettingsContent, all_language_settings,    },    task_context::ContextProvider,    with_parser,};use anyhow::{Context as _, Result, anyhow};use collections::{FxHashMap, HashMap, HashSet, hash_map}; use futures::{    Future,    channel::{mpsc, oneshot},};use globset::GlobSet;use gpui::{App, BackgroundExecutor, SharedString};use lsp::LanguageServerId;use parking_lot::{Mutex, RwLock};use postage::watch;use schemars::JsonSchema;use serde::{Deserialize, Serialize};use smallvec::SmallVec;use std::{    borrow::{Borrow, Cow},    cell::LazyCell,    ffi::OsStr,    ops::Not,    path::{Path, PathBuf},    sync::Arc,};use sum_tree::Bias;use text::{Point, Rope};use theme::Theme;use unicase::UniCase;use util::{ResultExt, maybe, post_inc}; #[derive(    Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,)]pub struct LanguageName(SharedString); impl LanguageName {    pub fn new(s: &str) -> Self {        Self(SharedString::new(s))    }     pub fn from_proto(s: String) -> Self {        Self(SharedString::from(s))    }    pub fn to_proto(self) -> String {        self.0.to_string()    }    pub fn lsp_id(&self) -> String {        match self.0.as_ref() {            "Plain Text" => "plaintext".to_string(),            language_name => language_name.to_lowercase(),        }    }} impl From<LanguageName> for SharedString {    fn from(value: LanguageName) -> Self {        value.0    }} impl From<SharedString> for LanguageName {    fn from(value: SharedString) -> Self {        LanguageName(value)    }} impl AsRef<str> for LanguageName {    fn as_ref(&self) -> &str {        self.0.as_ref()    }} impl Borrow<str> for LanguageName {    fn borrow(&self) -> &str {        self.0.as_ref()    }} impl std::fmt::Display for LanguageName {    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {        write!(f, "{}", self.0)    }} impl<'a> From<&'a str> for LanguageName {    fn from(str: &'a str) -> LanguageName {        LanguageName(SharedString::new(str))    }} 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>>,    executor: BackgroundExecutor,    lsp_binary_status_tx: BinaryStatusSender,} struct LanguageRegistryState {    next_language_server_id: usize,    languages: Vec<Arc<Language>>,    language_settings: AllLanguageSettingsContent,    available_languages: Vec<AvailableLanguage>,    grammars: HashMap<Arc<str>, AvailableGrammar>,    lsp_adapters: HashMap<LanguageName, Vec<Arc<CachedLspAdapter>>>,    all_lsp_adapters: HashMap<LanguageServerName, Arc<CachedLspAdapter>>,    available_lsp_adapters:        HashMap<LanguageServerName, Arc<dyn Fn() -> Arc<CachedLspAdapter> + 'static + Send + Sync>>,    loading_languages: HashMap<LanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>,    subscription: (watch::Sender<()>, watch::Receiver<()>),    theme: Option<Arc<Theme>>,    version: usize,    reload_count: usize,     #[cfg(any(test, feature = "test-support"))]    fake_server_entries: HashMap<LanguageServerName, FakeLanguageServerEntry>,} #[cfg(any(test, feature = "test-support"))]pub struct FakeLanguageServerEntry {    pub capabilities: lsp::ServerCapabilities,    pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,    pub tx: futures::channel::mpsc::UnboundedSender<lsp::FakeLanguageServer>,    pub _server: Option<lsp::FakeLanguageServer>,} #[derive(Clone, Debug, PartialEq, Eq)]pub enum BinaryStatus {    None,    CheckingForUpdate,    Downloading,    Failed { error: String },} #[derive(Clone)]pub struct AvailableLanguage {    id: LanguageId,    name: LanguageName,    grammar: Option<Arc<str>>,    matcher: LanguageMatcher,    hidden: bool,    load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,    loaded: bool,} impl AvailableLanguage {    pub fn name(&self) -> LanguageName {        self.name.clone()    }     pub fn matcher(&self) -> &LanguageMatcher {        &self.matcher    }     pub fn hidden(&self) -> bool {        self.hidden    }} #[derive(Copy, Clone, Default)]enum LanguageMatchPrecedence {    #[default]    Undetermined,    PathOrContent(usize),    UserConfigured(usize),} enum AvailableGrammar {    Native(tree_sitter::Language),    Loaded(#[allow(unused)] PathBuf, tree_sitter::Language),    Loading(        #[allow(unused)] PathBuf,        Vec<oneshot::Sender<Result<tree_sitter::Language, Arc<anyhow::Error>>>>,    ),    Unloaded(PathBuf),    LoadFailed(Arc<anyhow::Error>),} #[derive(Debug)]pub struct LanguageNotFound; impl std::fmt::Display for LanguageNotFound {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        write!(f, "language not found")    }} pub const QUERY_FILENAME_PREFIXES: &[(    &str,    fn(&mut LanguageQueries) -> &mut Option<Cow<'static, str>>,)] = &[    ("highlights", |q| &mut q.highlights),    ("brackets", |q| &mut q.brackets),    ("outline", |q| &mut q.outline),    ("indents", |q| &mut q.indents),    ("embedding", |q| &mut q.embedding),    ("injections", |q| &mut q.injections),    ("overrides", |q| &mut q.overrides),    ("redactions", |q| &mut q.redactions),    ("runnables", |q| &mut q.runnables),    ("debug_variables", |q| &mut q.debug_variables),    ("textobjects", |q| &mut q.text_objects),]; /// Tree-sitter language queries for a given language.#[derive(Debug, Default)]pub struct LanguageQueries {    pub highlights: Option<Cow<'static, str>>,    pub brackets: Option<Cow<'static, str>>,    pub indents: Option<Cow<'static, str>>,    pub outline: Option<Cow<'static, str>>,    pub embedding: Option<Cow<'static, str>>,    pub injections: Option<Cow<'static, str>>,    pub overrides: Option<Cow<'static, str>>,    pub redactions: Option<Cow<'static, str>>,    pub runnables: Option<Cow<'static, str>>,    pub text_objects: Option<Cow<'static, str>>,    pub debug_variables: Option<Cow<'static, str>>,} #[derive(Clone, Default)]struct BinaryStatusSender {    txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(SharedString, BinaryStatus)>>>>,} 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 {            state: RwLock::new(LanguageRegistryState {                next_language_server_id: 0,                languages: Vec::new(),                available_languages: Vec::new(),                grammars: Default::default(),                language_settings: Default::default(),                loading_languages: Default::default(),                lsp_adapters: Default::default(),                all_lsp_adapters: Default::default(),                available_lsp_adapters: HashMap::default(),                subscription: watch::channel(),                theme: Default::default(),                version: 0,                reload_count: 0,                 #[cfg(any(test, feature = "test-support"))]                fake_server_entries: Default::default(),            }),            language_server_download_dir: None,            lsp_binary_status_tx: Default::default(),            executor,        };        this.add(PLAIN_TEXT.clone());        this    }     #[cfg(any(test, feature = "test-support"))]    pub fn test(executor: BackgroundExecutor) -> Self {        let mut this = Self::new(executor);        this.language_server_download_dir = Some(Path::new("/the-download-dir").into());        this    }     /// Clears out all of the loaded languages and reload them from scratch.    pub fn reload(&self) {        self.state.write().reload();    }     /// Reorders the list of language servers for the given language.    ///    /// Uses the provided list of ordered [`CachedLspAdapters`] as the desired order.    ///    /// Any existing language servers not present in `ordered_lsp_adapters` will be    /// appended to the end.    pub fn reorder_language_servers(        &self,        language: &LanguageName,        ordered_lsp_adapters: Vec<Arc<CachedLspAdapter>>,    ) {        self.state            .write()            .reorder_language_servers(language, ordered_lsp_adapters);    }     /// Removes the specified languages and grammars from the registry.    pub fn remove_languages(        &self,        languages_to_remove: &[LanguageName],        grammars_to_remove: &[Arc<str>],    ) {        self.state            .write()            .remove_languages(languages_to_remove, grammars_to_remove)    }     pub fn remove_lsp_adapter(&self, language_name: &LanguageName, name: &LanguageServerName) {        let mut state = self.state.write();        if let Some(adapters) = state.lsp_adapters.get_mut(language_name) {            adapters.retain(|adapter| &adapter.name != name)        }        state.version += 1;        state.reload_count += 1;        *state.subscription.0.borrow_mut() = ();    }     #[cfg(any(feature = "test-support", test))]    pub fn register_test_language(&self, config: LanguageConfig) {        self.register_language(            config.name.clone(),            config.grammar.clone(),            config.matcher.clone(),            config.hidden,            Arc::new(move || {                Ok(LoadedLanguage {                    config: config.clone(),                    queries: Default::default(),                    toolchain_provider: None,                    context_provider: None,                })            }),        )    }     /// Registers an available language server adapter.    ///    /// The language server is registered under the language server name, but    /// not bound to a particular language.    ///    /// When a language wants to load this particular language server, it will    /// invoke the `load` function.    pub fn register_available_lsp_adapter(        &self,        name: LanguageServerName,        load: impl Fn() -> Arc<dyn LspAdapter> + 'static + Send + Sync,    ) {        self.state.write().available_lsp_adapters.insert(            name,            Arc::new(move || {                let lsp_adapter = load();                CachedLspAdapter::new(lsp_adapter)            }),        );    }     /// Loads the language server adapter for the language server with the given name.    pub fn load_available_lsp_adapter(        &self,        name: &LanguageServerName,    ) -> Option<Arc<CachedLspAdapter>> {        let state = self.state.read();        let load_lsp_adapter = state.available_lsp_adapters.get(name)?;         Some(load_lsp_adapter())    }     pub fn register_lsp_adapter(        &self,        language_name: LanguageName,        adapter: Arc<dyn LspAdapter>,    ) -> Arc<CachedLspAdapter> {        let cached = CachedLspAdapter::new(adapter);        let mut state = self.state.write();        state            .lsp_adapters            .entry(language_name)            .or_default()            .push(cached.clone());        state            .all_lsp_adapters            .insert(cached.name.clone(), cached.clone());         cached    }     pub fn get_or_register_lsp_adapter(        &self,        language_name: LanguageName,        server_name: LanguageServerName,        build_adapter: impl FnOnce() -> Arc<dyn LspAdapter> + 'static,    ) -> Arc<CachedLspAdapter> {        let registered = self            .state            .write()            .lsp_adapters            .entry(language_name.clone())            .or_default()            .iter()            .find(|cached_adapter| cached_adapter.name == server_name)            .cloned();         if let Some(found) = registered {            found        } else {            let adapter = build_adapter();            self.register_lsp_adapter(language_name, adapter)        }    }     /// Register a fake language server and adapter    /// The returned channel receives a new instance of the language server every time it is started    #[cfg(any(feature = "test-support", test))]    pub fn register_fake_lsp(        &self,        language_name: impl Into<LanguageName>,        mut adapter: crate::FakeLspAdapter,    ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {        let language_name = language_name.into();        let adapter_name = LanguageServerName(adapter.name.into());        let capabilities = adapter.capabilities.clone();        let initializer = adapter.initializer.take();        let adapter = CachedLspAdapter::new(Arc::new(adapter));        {            let mut state = self.state.write();            state                .lsp_adapters                .entry(language_name.clone())                .or_default()                .push(adapter.clone());            state.all_lsp_adapters.insert(adapter.name(), adapter);        }         self.register_fake_language_server(adapter_name, capabilities, initializer)    }     /// Register a fake lsp adapter (without the language server)    /// The returned channel receives a new instance of the language server every time it is started    #[cfg(any(feature = "test-support", test))]    pub fn register_fake_lsp_adapter(        &self,        language_name: impl Into<LanguageName>,        adapter: crate::FakeLspAdapter,    ) {        let language_name = language_name.into();        let mut state = self.state.write();        let cached_adapter = CachedLspAdapter::new(Arc::new(adapter));        state            .lsp_adapters            .entry(language_name.clone())            .or_default()            .push(cached_adapter.clone());        state            .all_lsp_adapters            .insert(cached_adapter.name(), cached_adapter);    }     /// Register a fake language server (without the adapter)    /// The returned channel receives a new instance of the language server every time it is started    #[cfg(any(feature = "test-support", test))]    pub fn register_fake_language_server(        &self,        lsp_name: LanguageServerName,        capabilities: lsp::ServerCapabilities,        initializer: Option<Box<dyn Fn(&mut lsp::FakeLanguageServer) + Send + Sync>>,    ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {        let (servers_tx, servers_rx) = futures::channel::mpsc::unbounded();        self.state.write().fake_server_entries.insert(            lsp_name,            FakeLanguageServerEntry {                tx: servers_tx,                capabilities,                initializer,                _server: None,            },        );        servers_rx    }     /// Adds a language to the registry, which can be loaded if needed.    pub fn register_language(        &self,        name: LanguageName,        grammar_name: Option<Arc<str>>,        matcher: LanguageMatcher,        hidden: bool,        load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,    ) {        let state = &mut *self.state.write();         for existing_language in &mut state.available_languages {            if existing_language.name == name {                existing_language.grammar = grammar_name;

Lines 1–500 of 1253.