extension_host.rs

   1pub mod extension_settings;
   2pub mod headless_host;
   3pub mod wasm_host;
   4
   5#[cfg(test)]
   6mod extension_store_test;
   7
   8use anyhow::{Context as _, Result, anyhow, bail};
   9use async_compression::futures::bufread::GzipDecoder;
  10use async_tar::Archive;
  11use client::ExtensionProvides;
  12use client::{Client, ExtensionMetadata, GetExtensionsResponse, proto, telemetry::Telemetry};
  13use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
  14pub use extension::ExtensionManifest;
  15use extension::extension_builder::{CompileExtensionOptions, ExtensionBuilder};
  16use extension::{
  17    ExtensionContextServerProxy, ExtensionDebugAdapterProviderProxy, ExtensionEvents,
  18    ExtensionGrammarProxy, ExtensionHostProxy, ExtensionIndexedDocsProviderProxy,
  19    ExtensionLanguageProxy, ExtensionLanguageServerProxy, ExtensionSlashCommandProxy,
  20    ExtensionSnippetProxy, ExtensionThemeProxy,
  21};
  22use fs::{Fs, RemoveOptions};
  23use futures::{
  24    AsyncReadExt as _, Future, FutureExt as _, StreamExt as _,
  25    channel::{
  26        mpsc::{UnboundedSender, unbounded},
  27        oneshot,
  28    },
  29    io::BufReader,
  30    select_biased,
  31};
  32use gpui::{
  33    App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Global, Task, WeakEntity,
  34    actions,
  35};
  36use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
  37use language::{
  38    LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LoadedLanguage,
  39    QUERY_FILENAME_PREFIXES, Rope,
  40};
  41use node_runtime::NodeRuntime;
  42use project::ContextProviderWithTasks;
  43use release_channel::ReleaseChannel;
  44use remote::SshRemoteClient;
  45use semantic_version::SemanticVersion;
  46use serde::{Deserialize, Serialize};
  47use settings::Settings;
  48use std::ops::RangeInclusive;
  49use std::str::FromStr;
  50use std::{
  51    cmp::Ordering,
  52    path::{self, Path, PathBuf},
  53    sync::Arc,
  54    time::{Duration, Instant},
  55};
  56use url::Url;
  57use util::{ResultExt, paths::RemotePathBuf};
  58use wasm_host::{
  59    WasmExtension, WasmHost,
  60    wit::{is_supported_wasm_api_version, wasm_api_version_range},
  61};
  62
  63pub use extension::{
  64    ExtensionLibraryKind, GrammarManifestEntry, OldExtensionManifest, SchemaVersion,
  65};
  66pub use extension_settings::ExtensionSettings;
  67
  68pub const RELOAD_DEBOUNCE_DURATION: Duration = Duration::from_millis(200);
  69const FS_WATCH_LATENCY: Duration = Duration::from_millis(100);
  70
  71/// The current extension [`SchemaVersion`] supported by Zed.
  72const CURRENT_SCHEMA_VERSION: SchemaVersion = SchemaVersion(1);
  73
  74/// Returns the [`SchemaVersion`] range that is compatible with this version of Zed.
  75pub fn schema_version_range() -> RangeInclusive<SchemaVersion> {
  76    SchemaVersion::ZERO..=CURRENT_SCHEMA_VERSION
  77}
  78
  79/// Returns whether the given extension version is compatible with this version of Zed.
  80pub fn is_version_compatible(
  81    release_channel: ReleaseChannel,
  82    extension_version: &ExtensionMetadata,
  83) -> bool {
  84    let schema_version = extension_version.manifest.schema_version.unwrap_or(0);
  85    if CURRENT_SCHEMA_VERSION.0 < schema_version {
  86        return false;
  87    }
  88
  89    if let Some(wasm_api_version) = extension_version
  90        .manifest
  91        .wasm_api_version
  92        .as_ref()
  93        .and_then(|wasm_api_version| SemanticVersion::from_str(wasm_api_version).ok())
  94    {
  95        if !is_supported_wasm_api_version(release_channel, wasm_api_version) {
  96            return false;
  97        }
  98    }
  99
 100    true
 101}
 102
 103pub struct ExtensionStore {
 104    pub proxy: Arc<ExtensionHostProxy>,
 105    pub builder: Arc<ExtensionBuilder>,
 106    pub extension_index: ExtensionIndex,
 107    pub fs: Arc<dyn Fs>,
 108    pub http_client: Arc<HttpClientWithUrl>,
 109    pub telemetry: Option<Arc<Telemetry>>,
 110    pub reload_tx: UnboundedSender<Option<Arc<str>>>,
 111    pub reload_complete_senders: Vec<oneshot::Sender<()>>,
 112    pub installed_dir: PathBuf,
 113    pub outstanding_operations: BTreeMap<Arc<str>, ExtensionOperation>,
 114    pub index_path: PathBuf,
 115    pub modified_extensions: HashSet<Arc<str>>,
 116    pub wasm_host: Arc<WasmHost>,
 117    pub wasm_extensions: Vec<(Arc<ExtensionManifest>, WasmExtension)>,
 118    pub tasks: Vec<Task<()>>,
 119    pub ssh_clients: HashMap<String, WeakEntity<SshRemoteClient>>,
 120    pub ssh_registered_tx: UnboundedSender<()>,
 121}
 122
 123#[derive(Clone, Copy)]
 124pub enum ExtensionOperation {
 125    Upgrade,
 126    Install,
 127    Remove,
 128}
 129
 130#[derive(Clone)]
 131pub enum Event {
 132    ExtensionsUpdated,
 133    StartedReloading,
 134    ExtensionInstalled(Arc<str>),
 135    ExtensionUninstalled(Arc<str>),
 136    ExtensionFailedToLoad(Arc<str>),
 137}
 138
 139impl EventEmitter<Event> for ExtensionStore {}
 140
 141struct GlobalExtensionStore(Entity<ExtensionStore>);
 142
 143impl Global for GlobalExtensionStore {}
 144
 145#[derive(Debug, Deserialize, Serialize, Default, PartialEq, Eq)]
 146pub struct ExtensionIndex {
 147    pub extensions: BTreeMap<Arc<str>, ExtensionIndexEntry>,
 148    pub themes: BTreeMap<Arc<str>, ExtensionIndexThemeEntry>,
 149    #[serde(default)]
 150    pub icon_themes: BTreeMap<Arc<str>, ExtensionIndexIconThemeEntry>,
 151    pub languages: BTreeMap<LanguageName, ExtensionIndexLanguageEntry>,
 152}
 153
 154#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
 155pub struct ExtensionIndexEntry {
 156    pub manifest: Arc<ExtensionManifest>,
 157    pub dev: bool,
 158}
 159
 160#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
 161pub struct ExtensionIndexThemeEntry {
 162    pub extension: Arc<str>,
 163    pub path: PathBuf,
 164}
 165
 166#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
 167pub struct ExtensionIndexIconThemeEntry {
 168    pub extension: Arc<str>,
 169    pub path: PathBuf,
 170}
 171
 172#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
 173pub struct ExtensionIndexLanguageEntry {
 174    pub extension: Arc<str>,
 175    pub path: PathBuf,
 176    pub matcher: LanguageMatcher,
 177    pub hidden: bool,
 178    pub grammar: Option<Arc<str>>,
 179}
 180
 181actions!(
 182    zed,
 183    [
 184        /// Reloads all installed extensions.
 185        ReloadExtensions
 186    ]
 187);
 188
 189pub fn init(
 190    extension_host_proxy: Arc<ExtensionHostProxy>,
 191    fs: Arc<dyn Fs>,
 192    client: Arc<Client>,
 193    node_runtime: NodeRuntime,
 194    cx: &mut App,
 195) {
 196    ExtensionSettings::register(cx);
 197
 198    let store = cx.new(move |cx| {
 199        ExtensionStore::new(
 200            paths::extensions_dir().clone(),
 201            None,
 202            extension_host_proxy,
 203            fs,
 204            client.http_client(),
 205            client.http_client(),
 206            Some(client.telemetry().clone()),
 207            node_runtime,
 208            cx,
 209        )
 210    });
 211
 212    cx.on_action(|_: &ReloadExtensions, cx| {
 213        let store = cx.global::<GlobalExtensionStore>().0.clone();
 214        store.update(cx, |store, cx| drop(store.reload(None, cx)));
 215    });
 216
 217    cx.set_global(GlobalExtensionStore(store));
 218}
 219
 220impl ExtensionStore {
 221    pub fn try_global(cx: &App) -> Option<Entity<Self>> {
 222        cx.try_global::<GlobalExtensionStore>()
 223            .map(|store| store.0.clone())
 224    }
 225
 226    pub fn global(cx: &App) -> Entity<Self> {
 227        cx.global::<GlobalExtensionStore>().0.clone()
 228    }
 229
 230    pub fn new(
 231        extensions_dir: PathBuf,
 232        build_dir: Option<PathBuf>,
 233        extension_host_proxy: Arc<ExtensionHostProxy>,
 234        fs: Arc<dyn Fs>,
 235        http_client: Arc<HttpClientWithUrl>,
 236        builder_client: Arc<dyn HttpClient>,
 237        telemetry: Option<Arc<Telemetry>>,
 238        node_runtime: NodeRuntime,
 239        cx: &mut Context<Self>,
 240    ) -> Self {
 241        let work_dir = extensions_dir.join("work");
 242        let build_dir = build_dir.unwrap_or_else(|| extensions_dir.join("build"));
 243        let installed_dir = extensions_dir.join("installed");
 244        let index_path = extensions_dir.join("index.json");
 245
 246        let (reload_tx, mut reload_rx) = unbounded();
 247        let (connection_registered_tx, mut connection_registered_rx) = unbounded();
 248        let mut this = Self {
 249            proxy: extension_host_proxy.clone(),
 250            extension_index: Default::default(),
 251            installed_dir,
 252            index_path,
 253            builder: Arc::new(ExtensionBuilder::new(builder_client, build_dir)),
 254            outstanding_operations: Default::default(),
 255            modified_extensions: Default::default(),
 256            reload_complete_senders: Vec::new(),
 257            wasm_host: WasmHost::new(
 258                fs.clone(),
 259                http_client.clone(),
 260                node_runtime,
 261                extension_host_proxy,
 262                work_dir,
 263                cx,
 264            ),
 265            wasm_extensions: Vec::new(),
 266            fs,
 267            http_client,
 268            telemetry,
 269            reload_tx,
 270            tasks: Vec::new(),
 271
 272            ssh_clients: HashMap::default(),
 273            ssh_registered_tx: connection_registered_tx,
 274        };
 275
 276        // The extensions store maintains an index file, which contains a complete
 277        // list of the installed extensions and the resources that they provide.
 278        // This index is loaded synchronously on startup.
 279        let (index_content, index_metadata, extensions_metadata) =
 280            cx.background_executor().block(async {
 281                futures::join!(
 282                    this.fs.load(&this.index_path),
 283                    this.fs.metadata(&this.index_path),
 284                    this.fs.metadata(&this.installed_dir),
 285                )
 286            });
 287
 288        // Normally, there is no need to rebuild the index. But if the index file
 289        // is invalid or is out-of-date according to the filesystem mtimes, then
 290        // it must be asynchronously rebuilt.
 291        let mut extension_index = ExtensionIndex::default();
 292        let mut extension_index_needs_rebuild = true;
 293        if let Ok(index_content) = index_content {
 294            if let Some(index) = serde_json::from_str(&index_content).log_err() {
 295                extension_index = index;
 296                if let (Ok(Some(index_metadata)), Ok(Some(extensions_metadata))) =
 297                    (index_metadata, extensions_metadata)
 298                {
 299                    if index_metadata
 300                        .mtime
 301                        .bad_is_greater_than(extensions_metadata.mtime)
 302                    {
 303                        extension_index_needs_rebuild = false;
 304                    }
 305                }
 306            }
 307        }
 308
 309        // Immediately load all of the extensions in the initial manifest. If the
 310        // index needs to be rebuild, then enqueue
 311        let load_initial_extensions = this.extensions_updated(extension_index, cx);
 312        let mut reload_future = None;
 313        if extension_index_needs_rebuild {
 314            reload_future = Some(this.reload(None, cx));
 315        }
 316
 317        cx.spawn(async move |this, cx| {
 318            if let Some(future) = reload_future {
 319                future.await;
 320            }
 321            this.update(cx, |this, cx| this.auto_install_extensions(cx))
 322                .ok();
 323            this.update(cx, |this, cx| this.check_for_updates(cx)).ok();
 324        })
 325        .detach();
 326
 327        // Perform all extension loading in a single task to ensure that we
 328        // never attempt to simultaneously load/unload extensions from multiple
 329        // parallel tasks.
 330        this.tasks.push(cx.spawn(async move |this, cx| {
 331            async move {
 332                load_initial_extensions.await;
 333
 334                let mut index_changed = false;
 335                let mut debounce_timer = cx.background_spawn(futures::future::pending()).fuse();
 336                loop {
 337                    select_biased! {
 338                        _ = debounce_timer => {
 339                            if index_changed {
 340                                let index = this
 341                                    .update(cx, |this, cx| this.rebuild_extension_index(cx))?
 342                                    .await;
 343                                this.update( cx, |this, cx| this.extensions_updated(index, cx))?
 344                                    .await;
 345                                index_changed = false;
 346                            }
 347
 348                            Self::update_ssh_clients(&this, cx).await?;
 349                        }
 350                        _ = connection_registered_rx.next() => {
 351                            debounce_timer = cx
 352                                .background_executor()
 353                                .timer(RELOAD_DEBOUNCE_DURATION)
 354                                .fuse();
 355                        }
 356                        extension_id = reload_rx.next() => {
 357                            let Some(extension_id) = extension_id else { break; };
 358                            this.update( cx, |this, _| {
 359                                this.modified_extensions.extend(extension_id);
 360                            })?;
 361                            index_changed = true;
 362                            debounce_timer = cx
 363                                .background_executor()
 364                                .timer(RELOAD_DEBOUNCE_DURATION)
 365                                .fuse();
 366                        }
 367                    }
 368                }
 369
 370                anyhow::Ok(())
 371            }
 372            .map(drop)
 373            .await;
 374        }));
 375
 376        // Watch the installed extensions directory for changes. Whenever changes are
 377        // detected, rebuild the extension index, and load/unload any extensions that
 378        // have been added, removed, or modified.
 379        this.tasks.push(cx.background_spawn({
 380            let fs = this.fs.clone();
 381            let reload_tx = this.reload_tx.clone();
 382            let installed_dir = this.installed_dir.clone();
 383            async move {
 384                let (mut paths, _) = fs.watch(&installed_dir, FS_WATCH_LATENCY).await;
 385                while let Some(events) = paths.next().await {
 386                    for event in events {
 387                        let Ok(event_path) = event.path.strip_prefix(&installed_dir) else {
 388                            continue;
 389                        };
 390
 391                        if let Some(path::Component::Normal(extension_dir_name)) =
 392                            event_path.components().next()
 393                        {
 394                            if let Some(extension_id) = extension_dir_name.to_str() {
 395                                reload_tx.unbounded_send(Some(extension_id.into())).ok();
 396                            }
 397                        }
 398                    }
 399                }
 400            }
 401        }));
 402
 403        this
 404    }
 405
 406    pub fn reload(
 407        &mut self,
 408        modified_extension: Option<Arc<str>>,
 409        cx: &mut Context<Self>,
 410    ) -> impl Future<Output = ()> + use<> {
 411        let (tx, rx) = oneshot::channel();
 412        self.reload_complete_senders.push(tx);
 413        self.reload_tx
 414            .unbounded_send(modified_extension)
 415            .expect("reload task exited");
 416        cx.emit(Event::StartedReloading);
 417
 418        async move {
 419            rx.await.ok();
 420        }
 421    }
 422
 423    fn extensions_dir(&self) -> PathBuf {
 424        self.installed_dir.clone()
 425    }
 426
 427    pub fn outstanding_operations(&self) -> &BTreeMap<Arc<str>, ExtensionOperation> {
 428        &self.outstanding_operations
 429    }
 430
 431    pub fn installed_extensions(&self) -> &BTreeMap<Arc<str>, ExtensionIndexEntry> {
 432        &self.extension_index.extensions
 433    }
 434
 435    pub fn dev_extensions(&self) -> impl Iterator<Item = &Arc<ExtensionManifest>> {
 436        self.extension_index
 437            .extensions
 438            .values()
 439            .filter_map(|extension| extension.dev.then_some(&extension.manifest))
 440    }
 441
 442    pub fn extension_manifest_for_id(&self, extension_id: &str) -> Option<&Arc<ExtensionManifest>> {
 443        self.extension_index
 444            .extensions
 445            .get(extension_id)
 446            .map(|extension| &extension.manifest)
 447    }
 448
 449    /// Returns the names of themes provided by extensions.
 450    pub fn extension_themes<'a>(
 451        &'a self,
 452        extension_id: &'a str,
 453    ) -> impl Iterator<Item = &'a Arc<str>> {
 454        self.extension_index
 455            .themes
 456            .iter()
 457            .filter_map(|(name, theme)| theme.extension.as_ref().eq(extension_id).then_some(name))
 458    }
 459
 460    /// Returns the path to the theme file within an extension, if there is an
 461    /// extension that provides the theme.
 462    pub fn path_to_extension_theme(&self, theme_name: &str) -> Option<PathBuf> {
 463        let entry = self.extension_index.themes.get(theme_name)?;
 464
 465        Some(
 466            self.extensions_dir()
 467                .join(entry.extension.as_ref())
 468                .join(&entry.path),
 469        )
 470    }
 471
 472    /// Returns the names of icon themes provided by extensions.
 473    pub fn extension_icon_themes<'a>(
 474        &'a self,
 475        extension_id: &'a str,
 476    ) -> impl Iterator<Item = &'a Arc<str>> {
 477        self.extension_index
 478            .icon_themes
 479            .iter()
 480            .filter_map(|(name, icon_theme)| {
 481                icon_theme
 482                    .extension
 483                    .as_ref()
 484                    .eq(extension_id)
 485                    .then_some(name)
 486            })
 487    }
 488
 489    /// Returns the path to the icon theme file within an extension, if there is
 490    /// an extension that provides the icon theme.
 491    pub fn path_to_extension_icon_theme(
 492        &self,
 493        icon_theme_name: &str,
 494    ) -> Option<(PathBuf, PathBuf)> {
 495        let entry = self.extension_index.icon_themes.get(icon_theme_name)?;
 496
 497        let icon_theme_path = self
 498            .extensions_dir()
 499            .join(entry.extension.as_ref())
 500            .join(&entry.path);
 501        let icons_root_path = self.extensions_dir().join(entry.extension.as_ref());
 502
 503        Some((icon_theme_path, icons_root_path))
 504    }
 505
 506    pub fn fetch_extensions(
 507        &self,
 508        search: Option<&str>,
 509        provides_filter: Option<&BTreeSet<ExtensionProvides>>,
 510        cx: &mut Context<Self>,
 511    ) -> Task<Result<Vec<ExtensionMetadata>>> {
 512        let version = CURRENT_SCHEMA_VERSION.to_string();
 513        let mut query = vec![("max_schema_version", version.as_str())];
 514        if let Some(search) = search {
 515            query.push(("filter", search));
 516        }
 517
 518        let provides_filter = provides_filter.map(|provides_filter| {
 519            provides_filter
 520                .iter()
 521                .map(|provides| provides.to_string())
 522                .collect::<Vec<_>>()
 523                .join(",")
 524        });
 525        if let Some(provides_filter) = provides_filter.as_deref() {
 526            query.push(("provides", provides_filter));
 527        }
 528
 529        self.fetch_extensions_from_api("/extensions", &query, cx)
 530    }
 531
 532    pub fn fetch_extensions_with_update_available(
 533        &mut self,
 534        cx: &mut Context<Self>,
 535    ) -> Task<Result<Vec<ExtensionMetadata>>> {
 536        let schema_versions = schema_version_range();
 537        let wasm_api_versions = wasm_api_version_range(ReleaseChannel::global(cx));
 538        let extension_settings = ExtensionSettings::get_global(cx);
 539        let extension_ids = self
 540            .extension_index
 541            .extensions
 542            .iter()
 543            .filter(|(id, entry)| !entry.dev && extension_settings.should_auto_update(id))
 544            .map(|(id, _)| id.as_ref())
 545            .collect::<Vec<_>>()
 546            .join(",");
 547        let task = self.fetch_extensions_from_api(
 548            "/extensions/updates",
 549            &[
 550                ("min_schema_version", &schema_versions.start().to_string()),
 551                ("max_schema_version", &schema_versions.end().to_string()),
 552                (
 553                    "min_wasm_api_version",
 554                    &wasm_api_versions.start().to_string(),
 555                ),
 556                ("max_wasm_api_version", &wasm_api_versions.end().to_string()),
 557                ("ids", &extension_ids),
 558            ],
 559            cx,
 560        );
 561        cx.spawn(async move |this, cx| {
 562            let extensions = task.await?;
 563            this.update(cx, |this, _cx| {
 564                extensions
 565                    .into_iter()
 566                    .filter(|extension| {
 567                        this.extension_index.extensions.get(&extension.id).map_or(
 568                            true,
 569                            |installed_extension| {
 570                                installed_extension.manifest.version != extension.manifest.version
 571                            },
 572                        )
 573                    })
 574                    .collect()
 575            })
 576        })
 577    }
 578
 579    pub fn fetch_extension_versions(
 580        &self,
 581        extension_id: &str,
 582        cx: &mut Context<Self>,
 583    ) -> Task<Result<Vec<ExtensionMetadata>>> {
 584        self.fetch_extensions_from_api(&format!("/extensions/{extension_id}"), &[], cx)
 585    }
 586
 587    /// Installs any extensions that should be included with Zed by default.
 588    ///
 589    /// This can be used to make certain functionality provided by extensions
 590    /// available out-of-the-box.
 591    pub fn auto_install_extensions(&mut self, cx: &mut Context<Self>) {
 592        let extension_settings = ExtensionSettings::get_global(cx);
 593
 594        let extensions_to_install = extension_settings
 595            .auto_install_extensions
 596            .keys()
 597            .filter(|extension_id| extension_settings.should_auto_install(extension_id))
 598            .filter(|extension_id| {
 599                let is_already_installed = self
 600                    .extension_index
 601                    .extensions
 602                    .contains_key(extension_id.as_ref());
 603                !is_already_installed
 604            })
 605            .cloned()
 606            .collect::<Vec<_>>();
 607
 608        cx.spawn(async move |this, cx| {
 609            for extension_id in extensions_to_install {
 610                this.update(cx, |this, cx| {
 611                    this.install_latest_extension(extension_id.clone(), cx);
 612                })
 613                .ok();
 614            }
 615        })
 616        .detach();
 617    }
 618
 619    pub fn check_for_updates(&mut self, cx: &mut Context<Self>) {
 620        let task = self.fetch_extensions_with_update_available(cx);
 621        cx.spawn(async move |this, cx| Self::upgrade_extensions(this, task.await?, cx).await)
 622            .detach();
 623    }
 624
 625    async fn upgrade_extensions(
 626        this: WeakEntity<Self>,
 627        extensions: Vec<ExtensionMetadata>,
 628        cx: &mut AsyncApp,
 629    ) -> Result<()> {
 630        for extension in extensions {
 631            let task = this.update(cx, |this, cx| {
 632                if let Some(installed_extension) =
 633                    this.extension_index.extensions.get(&extension.id)
 634                {
 635                    let installed_version =
 636                        SemanticVersion::from_str(&installed_extension.manifest.version).ok()?;
 637                    let latest_version =
 638                        SemanticVersion::from_str(&extension.manifest.version).ok()?;
 639
 640                    if installed_version >= latest_version {
 641                        return None;
 642                    }
 643                }
 644
 645                Some(this.upgrade_extension(extension.id, extension.manifest.version, cx))
 646            })?;
 647
 648            if let Some(task) = task {
 649                task.await.log_err();
 650            }
 651        }
 652        anyhow::Ok(())
 653    }
 654
 655    fn fetch_extensions_from_api(
 656        &self,
 657        path: &str,
 658        query: &[(&str, &str)],
 659        cx: &mut Context<ExtensionStore>,
 660    ) -> Task<Result<Vec<ExtensionMetadata>>> {
 661        let url = self.http_client.build_zed_api_url(path, query);
 662        let http_client = self.http_client.clone();
 663        cx.spawn(async move |_, _| {
 664            let mut response = http_client
 665                .get(url?.as_ref(), AsyncBody::empty(), true)
 666                .await?;
 667
 668            let mut body = Vec::new();
 669            response
 670                .body_mut()
 671                .read_to_end(&mut body)
 672                .await
 673                .context("error reading extensions")?;
 674
 675            if response.status().is_client_error() {
 676                let text = String::from_utf8_lossy(body.as_slice());
 677                bail!(
 678                    "status error {}, response: {text:?}",
 679                    response.status().as_u16()
 680                );
 681            }
 682
 683            let response: GetExtensionsResponse = serde_json::from_slice(&body)?;
 684            Ok(response.data)
 685        })
 686    }
 687
 688    pub fn install_extension(
 689        &mut self,
 690        extension_id: Arc<str>,
 691        version: Arc<str>,
 692        cx: &mut Context<Self>,
 693    ) {
 694        self.install_or_upgrade_extension(extension_id, version, ExtensionOperation::Install, cx)
 695            .detach_and_log_err(cx);
 696    }
 697
 698    fn install_or_upgrade_extension_at_endpoint(
 699        &mut self,
 700        extension_id: Arc<str>,
 701        url: Url,
 702        operation: ExtensionOperation,
 703        cx: &mut Context<Self>,
 704    ) -> Task<Result<()>> {
 705        let extension_dir = self.installed_dir.join(extension_id.as_ref());
 706        let http_client = self.http_client.clone();
 707        let fs = self.fs.clone();
 708
 709        match self.outstanding_operations.entry(extension_id.clone()) {
 710            btree_map::Entry::Occupied(_) => return Task::ready(Ok(())),
 711            btree_map::Entry::Vacant(e) => e.insert(operation),
 712        };
 713        cx.notify();
 714
 715        cx.spawn(async move |this, cx| {
 716            let _finish = cx.on_drop(&this, {
 717                let extension_id = extension_id.clone();
 718                move |this, cx| {
 719                    this.outstanding_operations.remove(extension_id.as_ref());
 720                    cx.notify();
 721                }
 722            });
 723
 724            let mut response = http_client
 725                .get(url.as_ref(), Default::default(), true)
 726                .await
 727                .context("downloading extension")?;
 728
 729            fs.remove_dir(
 730                &extension_dir,
 731                RemoveOptions {
 732                    recursive: true,
 733                    ignore_if_not_exists: true,
 734                },
 735            )
 736            .await?;
 737
 738            let content_length = response
 739                .headers()
 740                .get(http_client::http::header::CONTENT_LENGTH)
 741                .and_then(|value| value.to_str().ok()?.parse::<usize>().ok());
 742
 743            let mut body = BufReader::new(response.body_mut());
 744            let mut tar_gz_bytes = Vec::new();
 745            body.read_to_end(&mut tar_gz_bytes).await?;
 746
 747            if let Some(content_length) = content_length {
 748                let actual_len = tar_gz_bytes.len();
 749                if content_length != actual_len {
 750                    bail!("downloaded extension size {actual_len} does not match content length {content_length}");
 751                }
 752            }
 753            let decompressed_bytes = GzipDecoder::new(BufReader::new(tar_gz_bytes.as_slice()));
 754            let archive = Archive::new(decompressed_bytes);
 755            archive.unpack(extension_dir).await?;
 756            this.update( cx, |this, cx| {
 757                this.reload(Some(extension_id.clone()), cx)
 758            })?
 759            .await;
 760
 761            if let ExtensionOperation::Install = operation {
 762                this.update( cx, |this, cx| {
 763                    cx.emit(Event::ExtensionInstalled(extension_id.clone()));
 764                    if let Some(events) = ExtensionEvents::try_global(cx) {
 765                        if let Some(manifest) = this.extension_manifest_for_id(&extension_id) {
 766                            events.update(cx, |this, cx| {
 767                                this.emit(
 768                                    extension::Event::ExtensionInstalled(manifest.clone()),
 769                                    cx,
 770                                )
 771                            });
 772                        }
 773                    }
 774                })
 775                .ok();
 776            }
 777
 778            anyhow::Ok(())
 779        })
 780    }
 781
 782    pub fn install_latest_extension(&mut self, extension_id: Arc<str>, cx: &mut Context<Self>) {
 783        log::info!("installing extension {extension_id} latest version");
 784
 785        let schema_versions = schema_version_range();
 786        let wasm_api_versions = wasm_api_version_range(ReleaseChannel::global(cx));
 787
 788        let Some(url) = self
 789            .http_client
 790            .build_zed_api_url(
 791                &format!("/extensions/{extension_id}/download"),
 792                &[
 793                    ("min_schema_version", &schema_versions.start().to_string()),
 794                    ("max_schema_version", &schema_versions.end().to_string()),
 795                    (
 796                        "min_wasm_api_version",
 797                        &wasm_api_versions.start().to_string(),
 798                    ),
 799                    ("max_wasm_api_version", &wasm_api_versions.end().to_string()),
 800                ],
 801            )
 802            .log_err()
 803        else {
 804            return;
 805        };
 806
 807        self.install_or_upgrade_extension_at_endpoint(
 808            extension_id,
 809            url,
 810            ExtensionOperation::Install,
 811            cx,
 812        )
 813        .detach_and_log_err(cx);
 814    }
 815
 816    pub fn upgrade_extension(
 817        &mut self,
 818        extension_id: Arc<str>,
 819        version: Arc<str>,
 820        cx: &mut Context<Self>,
 821    ) -> Task<Result<()>> {
 822        self.install_or_upgrade_extension(extension_id, version, ExtensionOperation::Upgrade, cx)
 823    }
 824
 825    fn install_or_upgrade_extension(
 826        &mut self,
 827        extension_id: Arc<str>,
 828        version: Arc<str>,
 829        operation: ExtensionOperation,
 830        cx: &mut Context<Self>,
 831    ) -> Task<Result<()>> {
 832        log::info!("installing extension {extension_id} {version}");
 833        let Some(url) = self
 834            .http_client
 835            .build_zed_api_url(
 836                &format!("/extensions/{extension_id}/{version}/download"),
 837                &[],
 838            )
 839            .log_err()
 840        else {
 841            return Task::ready(Ok(()));
 842        };
 843
 844        self.install_or_upgrade_extension_at_endpoint(extension_id, url, operation, cx)
 845    }
 846
 847    pub fn uninstall_extension(
 848        &mut self,
 849        extension_id: Arc<str>,
 850        cx: &mut Context<Self>,
 851    ) -> Task<Result<()>> {
 852        let extension_dir = self.installed_dir.join(extension_id.as_ref());
 853        let work_dir = self.wasm_host.work_dir.join(extension_id.as_ref());
 854        let fs = self.fs.clone();
 855
 856        let extension_manifest = self.extension_manifest_for_id(&extension_id).cloned();
 857
 858        match self.outstanding_operations.entry(extension_id.clone()) {
 859            btree_map::Entry::Occupied(_) => return Task::ready(Ok(())),
 860            btree_map::Entry::Vacant(e) => e.insert(ExtensionOperation::Remove),
 861        };
 862
 863        cx.spawn(async move |this, cx| {
 864            let _finish = cx.on_drop(&this, {
 865                let extension_id = extension_id.clone();
 866                move |this, cx| {
 867                    this.outstanding_operations.remove(extension_id.as_ref());
 868                    cx.notify();
 869                }
 870            });
 871
 872            fs.remove_dir(
 873                &extension_dir,
 874                RemoveOptions {
 875                    recursive: true,
 876                    ignore_if_not_exists: true,
 877                },
 878            )
 879            .await?;
 880
 881            // todo(windows)
 882            // Stop the server here.
 883            this.update(cx, |this, cx| this.reload(None, cx))?.await;
 884
 885            fs.remove_dir(
 886                &work_dir,
 887                RemoveOptions {
 888                    recursive: true,
 889                    ignore_if_not_exists: true,
 890                },
 891            )
 892            .await?;
 893
 894            this.update(cx, |_, cx| {
 895                cx.emit(Event::ExtensionUninstalled(extension_id.clone()));
 896                if let Some(events) = ExtensionEvents::try_global(cx) {
 897                    if let Some(manifest) = extension_manifest {
 898                        events.update(cx, |this, cx| {
 899                            this.emit(extension::Event::ExtensionUninstalled(manifest.clone()), cx)
 900                        });
 901                    }
 902                }
 903            })?;
 904
 905            anyhow::Ok(())
 906        })
 907    }
 908
 909    pub fn install_dev_extension(
 910        &mut self,
 911        extension_source_path: PathBuf,
 912        cx: &mut Context<Self>,
 913    ) -> Task<Result<()>> {
 914        let extensions_dir = self.extensions_dir();
 915        let fs = self.fs.clone();
 916        let builder = self.builder.clone();
 917
 918        cx.spawn(async move |this, cx| {
 919            let mut extension_manifest =
 920                ExtensionManifest::load(fs.clone(), &extension_source_path).await?;
 921            let extension_id = extension_manifest.id.clone();
 922
 923            if !this.update(cx, |this, cx| {
 924                match this.outstanding_operations.entry(extension_id.clone()) {
 925                    btree_map::Entry::Occupied(_) => return false,
 926                    btree_map::Entry::Vacant(e) => e.insert(ExtensionOperation::Remove),
 927                };
 928                cx.notify();
 929                true
 930            })? {
 931                return Ok(());
 932            }
 933
 934            let _finish = cx.on_drop(&this, {
 935                let extension_id = extension_id.clone();
 936                move |this, cx| {
 937                    this.outstanding_operations.remove(extension_id.as_ref());
 938                    cx.notify();
 939                }
 940            });
 941
 942            cx.background_spawn({
 943                let extension_source_path = extension_source_path.clone();
 944                async move {
 945                    builder
 946                        .compile_extension(
 947                            &extension_source_path,
 948                            &mut extension_manifest,
 949                            CompileExtensionOptions { release: false },
 950                        )
 951                        .await
 952                }
 953            })
 954            .await
 955            .inspect_err(|error| {
 956                util::log_err(error);
 957            })?;
 958
 959            let output_path = &extensions_dir.join(extension_id.as_ref());
 960            if let Some(metadata) = fs.metadata(output_path).await? {
 961                if metadata.is_symlink {
 962                    fs.remove_file(
 963                        output_path,
 964                        RemoveOptions {
 965                            recursive: false,
 966                            ignore_if_not_exists: true,
 967                        },
 968                    )
 969                    .await?;
 970                } else {
 971                    bail!("extension {extension_id} is already installed");
 972                }
 973            }
 974
 975            fs.create_symlink(output_path, extension_source_path)
 976                .await?;
 977
 978            this.update(cx, |this, cx| this.reload(None, cx))?.await;
 979            this.update(cx, |this, cx| {
 980                cx.emit(Event::ExtensionInstalled(extension_id.clone()));
 981                if let Some(events) = ExtensionEvents::try_global(cx) {
 982                    if let Some(manifest) = this.extension_manifest_for_id(&extension_id) {
 983                        events.update(cx, |this, cx| {
 984                            this.emit(extension::Event::ExtensionInstalled(manifest.clone()), cx)
 985                        });
 986                    }
 987                }
 988            })?;
 989
 990            Ok(())
 991        })
 992    }
 993
 994    pub fn rebuild_dev_extension(&mut self, extension_id: Arc<str>, cx: &mut Context<Self>) {
 995        let path = self.installed_dir.join(extension_id.as_ref());
 996        let builder = self.builder.clone();
 997        let fs = self.fs.clone();
 998
 999        match self.outstanding_operations.entry(extension_id.clone()) {
1000            btree_map::Entry::Occupied(_) => return,
1001            btree_map::Entry::Vacant(e) => e.insert(ExtensionOperation::Upgrade),
1002        };
1003
1004        cx.notify();
1005        let compile = cx.background_spawn(async move {
1006            let mut manifest = ExtensionManifest::load(fs, &path).await?;
1007            builder
1008                .compile_extension(
1009                    &path,
1010                    &mut manifest,
1011                    CompileExtensionOptions { release: true },
1012                )
1013                .await
1014        });
1015
1016        cx.spawn(async move |this, cx| {
1017            let result = compile.await;
1018
1019            this.update(cx, |this, cx| {
1020                this.outstanding_operations.remove(&extension_id);
1021                cx.notify();
1022            })?;
1023
1024            if result.is_ok() {
1025                this.update(cx, |this, cx| this.reload(Some(extension_id), cx))?
1026                    .await;
1027            }
1028
1029            result
1030        })
1031        .detach_and_log_err(cx)
1032    }
1033
1034    /// Updates the set of installed extensions.
1035    ///
1036    /// First, this unloads any themes, languages, or grammars that are
1037    /// no longer in the manifest, or whose files have changed on disk.
1038    /// Then it loads any themes, languages, or grammars that are newly
1039    /// added to the manifest, or whose files have changed on disk.
1040    fn extensions_updated(
1041        &mut self,
1042        mut new_index: ExtensionIndex,
1043        cx: &mut Context<Self>,
1044    ) -> Task<()> {
1045        let old_index = &self.extension_index;
1046
1047        // Determine which extensions need to be loaded and unloaded, based
1048        // on the changes to the manifest and the extensions that we know have been
1049        // modified.
1050        let mut extensions_to_unload = Vec::default();
1051        let mut extensions_to_load = Vec::default();
1052        {
1053            let mut old_keys = old_index.extensions.iter().peekable();
1054            let mut new_keys = new_index.extensions.iter().peekable();
1055            loop {
1056                match (old_keys.peek(), new_keys.peek()) {
1057                    (None, None) => break,
1058                    (None, Some(_)) => {
1059                        extensions_to_load.push(new_keys.next().unwrap().0.clone());
1060                    }
1061                    (Some(_), None) => {
1062                        extensions_to_unload.push(old_keys.next().unwrap().0.clone());
1063                    }
1064                    (Some((old_key, _)), Some((new_key, _))) => match old_key.cmp(new_key) {
1065                        Ordering::Equal => {
1066                            let (old_key, old_value) = old_keys.next().unwrap();
1067                            let (new_key, new_value) = new_keys.next().unwrap();
1068                            if old_value != new_value || self.modified_extensions.contains(old_key)
1069                            {
1070                                extensions_to_unload.push(old_key.clone());
1071                                extensions_to_load.push(new_key.clone());
1072                            }
1073                        }
1074                        Ordering::Less => {
1075                            extensions_to_unload.push(old_keys.next().unwrap().0.clone());
1076                        }
1077                        Ordering::Greater => {
1078                            extensions_to_load.push(new_keys.next().unwrap().0.clone());
1079                        }
1080                    },
1081                }
1082            }
1083            self.modified_extensions.clear();
1084        }
1085
1086        if extensions_to_load.is_empty() && extensions_to_unload.is_empty() {
1087            return Task::ready(());
1088        }
1089
1090        let reload_count = extensions_to_unload
1091            .iter()
1092            .filter(|id| extensions_to_load.contains(id))
1093            .count();
1094
1095        log::info!(
1096            "extensions updated. loading {}, reloading {}, unloading {}",
1097            extensions_to_load.len() - reload_count,
1098            reload_count,
1099            extensions_to_unload.len() - reload_count
1100        );
1101
1102        for extension_id in &extensions_to_load {
1103            if let Some(extension) = new_index.extensions.get(extension_id) {
1104                telemetry::event!(
1105                    "Extension Loaded",
1106                    extension_id,
1107                    version = extension.manifest.version
1108                );
1109            }
1110        }
1111
1112        let themes_to_remove = old_index
1113            .themes
1114            .iter()
1115            .filter_map(|(name, entry)| {
1116                if extensions_to_unload.contains(&entry.extension) {
1117                    Some(name.clone().into())
1118                } else {
1119                    None
1120                }
1121            })
1122            .collect::<Vec<_>>();
1123        let icon_themes_to_remove = old_index
1124            .icon_themes
1125            .iter()
1126            .filter_map(|(name, entry)| {
1127                if extensions_to_unload.contains(&entry.extension) {
1128                    Some(name.clone().into())
1129                } else {
1130                    None
1131                }
1132            })
1133            .collect::<Vec<_>>();
1134        let languages_to_remove = old_index
1135            .languages
1136            .iter()
1137            .filter_map(|(name, entry)| {
1138                if extensions_to_unload.contains(&entry.extension) {
1139                    Some(name.clone())
1140                } else {
1141                    None
1142                }
1143            })
1144            .collect::<Vec<_>>();
1145        let mut grammars_to_remove = Vec::new();
1146        for extension_id in &extensions_to_unload {
1147            let Some(extension) = old_index.extensions.get(extension_id) else {
1148                continue;
1149            };
1150            grammars_to_remove.extend(extension.manifest.grammars.keys().cloned());
1151            for (language_server_name, config) in extension.manifest.language_servers.iter() {
1152                for language in config.languages() {
1153                    self.proxy
1154                        .remove_language_server(&language, language_server_name);
1155                }
1156            }
1157
1158            for (server_id, _) in extension.manifest.context_servers.iter() {
1159                self.proxy.unregister_context_server(server_id.clone(), cx);
1160            }
1161            for (adapter, _) in extension.manifest.debug_adapters.iter() {
1162                self.proxy.unregister_debug_adapter(adapter.clone());
1163            }
1164            for (locator, _) in extension.manifest.debug_locators.iter() {
1165                self.proxy.unregister_debug_locator(locator.clone());
1166            }
1167        }
1168
1169        self.wasm_extensions
1170            .retain(|(extension, _)| !extensions_to_unload.contains(&extension.id));
1171        self.proxy.remove_user_themes(themes_to_remove);
1172        self.proxy.remove_icon_themes(icon_themes_to_remove);
1173        self.proxy
1174            .remove_languages(&languages_to_remove, &grammars_to_remove);
1175
1176        let mut grammars_to_add = Vec::new();
1177        let mut themes_to_add = Vec::new();
1178        let mut icon_themes_to_add = Vec::new();
1179        let mut snippets_to_add = Vec::new();
1180        for extension_id in &extensions_to_load {
1181            let Some(extension) = new_index.extensions.get(extension_id) else {
1182                continue;
1183            };
1184
1185            grammars_to_add.extend(extension.manifest.grammars.keys().map(|grammar_name| {
1186                let mut grammar_path = self.installed_dir.clone();
1187                grammar_path.extend([extension_id.as_ref(), "grammars"]);
1188                grammar_path.push(grammar_name.as_ref());
1189                grammar_path.set_extension("wasm");
1190                (grammar_name.clone(), grammar_path)
1191            }));
1192            themes_to_add.extend(extension.manifest.themes.iter().map(|theme_path| {
1193                let mut path = self.installed_dir.clone();
1194                path.extend([Path::new(extension_id.as_ref()), theme_path.as_path()]);
1195                path
1196            }));
1197            icon_themes_to_add.extend(extension.manifest.icon_themes.iter().map(
1198                |icon_theme_path| {
1199                    let mut path = self.installed_dir.clone();
1200                    path.extend([Path::new(extension_id.as_ref()), icon_theme_path.as_path()]);
1201
1202                    let mut icons_root_path = self.installed_dir.clone();
1203                    icons_root_path.extend([Path::new(extension_id.as_ref())]);
1204
1205                    (path, icons_root_path)
1206                },
1207            ));
1208            snippets_to_add.extend(extension.manifest.snippets.iter().map(|snippets_path| {
1209                let mut path = self.installed_dir.clone();
1210                path.extend([Path::new(extension_id.as_ref()), snippets_path.as_path()]);
1211                path
1212            }));
1213        }
1214
1215        self.proxy.register_grammars(grammars_to_add);
1216        let languages_to_add = new_index
1217            .languages
1218            .iter_mut()
1219            .filter(|(_, entry)| extensions_to_load.contains(&entry.extension))
1220            .collect::<Vec<_>>();
1221        for (language_name, language) in languages_to_add {
1222            let mut language_path = self.installed_dir.clone();
1223            language_path.extend([
1224                Path::new(language.extension.as_ref()),
1225                language.path.as_path(),
1226            ]);
1227            self.proxy.register_language(
1228                language_name.clone(),
1229                language.grammar.clone(),
1230                language.matcher.clone(),
1231                language.hidden,
1232                Arc::new(move || {
1233                    let config = std::fs::read_to_string(language_path.join("config.toml"))?;
1234                    let config: LanguageConfig = ::toml::from_str(&config)?;
1235                    let queries = load_plugin_queries(&language_path);
1236                    let context_provider =
1237                        std::fs::read_to_string(language_path.join("tasks.json"))
1238                            .ok()
1239                            .and_then(|contents| {
1240                                let definitions =
1241                                    serde_json_lenient::from_str(&contents).log_err()?;
1242                                Some(Arc::new(ContextProviderWithTasks::new(definitions)) as Arc<_>)
1243                            });
1244
1245                    Ok(LoadedLanguage {
1246                        config,
1247                        queries,
1248                        context_provider,
1249                        toolchain_provider: None,
1250                    })
1251                }),
1252            );
1253        }
1254
1255        let fs = self.fs.clone();
1256        let wasm_host = self.wasm_host.clone();
1257        let root_dir = self.installed_dir.clone();
1258        let proxy = self.proxy.clone();
1259        let extension_entries = extensions_to_load
1260            .iter()
1261            .filter_map(|name| new_index.extensions.get(name).cloned())
1262            .collect::<Vec<_>>();
1263        self.extension_index = new_index;
1264        cx.notify();
1265        cx.emit(Event::ExtensionsUpdated);
1266
1267        cx.spawn(async move |this, cx| {
1268            cx.background_spawn({
1269                let fs = fs.clone();
1270                async move {
1271                    for theme_path in themes_to_add.into_iter() {
1272                        proxy
1273                            .load_user_theme(theme_path, fs.clone())
1274                            .await
1275                            .log_err();
1276                    }
1277
1278                    for (icon_theme_path, icons_root_path) in icon_themes_to_add.into_iter() {
1279                        proxy
1280                            .load_icon_theme(icon_theme_path, icons_root_path, fs.clone())
1281                            .await
1282                            .log_err();
1283                    }
1284
1285                    for snippets_path in &snippets_to_add {
1286                        if let Some(snippets_contents) = fs.load(snippets_path).await.log_err() {
1287                            proxy
1288                                .register_snippet(snippets_path, &snippets_contents)
1289                                .log_err();
1290                        }
1291                    }
1292                }
1293            })
1294            .await;
1295
1296            let mut wasm_extensions = Vec::new();
1297            for extension in extension_entries {
1298                if extension.manifest.lib.kind.is_none() {
1299                    continue;
1300                };
1301
1302                let extension_path = root_dir.join(extension.manifest.id.as_ref());
1303                let wasm_extension = WasmExtension::load(
1304                    extension_path,
1305                    &extension.manifest,
1306                    wasm_host.clone(),
1307                    &cx,
1308                )
1309                .await;
1310
1311                if let Some(wasm_extension) = wasm_extension.log_err() {
1312                    wasm_extensions.push((extension.manifest.clone(), wasm_extension));
1313                } else {
1314                    this.update(cx, |_, cx| {
1315                        cx.emit(Event::ExtensionFailedToLoad(extension.manifest.id.clone()))
1316                    })
1317                    .ok();
1318                }
1319            }
1320
1321            this.update(cx, |this, cx| {
1322                this.reload_complete_senders.clear();
1323
1324                for (manifest, wasm_extension) in &wasm_extensions {
1325                    let extension = Arc::new(wasm_extension.clone());
1326
1327                    for (language_server_id, language_server_config) in &manifest.language_servers {
1328                        for language in language_server_config.languages() {
1329                            this.proxy.register_language_server(
1330                                extension.clone(),
1331                                language_server_id.clone(),
1332                                language.clone(),
1333                            );
1334                        }
1335                    }
1336
1337                    for (slash_command_name, slash_command) in &manifest.slash_commands {
1338                        this.proxy.register_slash_command(
1339                            extension.clone(),
1340                            extension::SlashCommand {
1341                                name: slash_command_name.to_string(),
1342                                description: slash_command.description.to_string(),
1343                                // We don't currently expose this as a configurable option, as it currently drives
1344                                // the `menu_text` on the `SlashCommand` trait, which is not used for slash commands
1345                                // defined in extensions, as they are not able to be added to the menu.
1346                                tooltip_text: String::new(),
1347                                requires_argument: slash_command.requires_argument,
1348                            },
1349                        );
1350                    }
1351
1352                    for (id, _context_server_entry) in &manifest.context_servers {
1353                        this.proxy
1354                            .register_context_server(extension.clone(), id.clone(), cx);
1355                    }
1356
1357                    for (provider_id, _provider) in &manifest.indexed_docs_providers {
1358                        this.proxy
1359                            .register_indexed_docs_provider(extension.clone(), provider_id.clone());
1360                    }
1361
1362                    for (debug_adapter, meta) in &manifest.debug_adapters {
1363                        let mut path = root_dir.clone();
1364                        path.push(Path::new(manifest.id.as_ref()));
1365                        if let Some(schema_path) = &meta.schema_path {
1366                            path.push(schema_path);
1367                        } else {
1368                            path.push("debug_adapter_schemas");
1369                            path.push(Path::new(debug_adapter.as_ref()).with_extension("json"));
1370                        }
1371
1372                        this.proxy.register_debug_adapter(
1373                            extension.clone(),
1374                            debug_adapter.clone(),
1375                            &path,
1376                        );
1377                    }
1378
1379                    for debug_adapter in manifest.debug_locators.keys() {
1380                        this.proxy
1381                            .register_debug_locator(extension.clone(), debug_adapter.clone());
1382                    }
1383                }
1384
1385                this.wasm_extensions.extend(wasm_extensions);
1386                this.proxy.set_extensions_loaded();
1387                this.proxy.reload_current_theme(cx);
1388                this.proxy.reload_current_icon_theme(cx);
1389
1390                if let Some(events) = ExtensionEvents::try_global(cx) {
1391                    events.update(cx, |this, cx| {
1392                        this.emit(extension::Event::ExtensionsInstalledChanged, cx)
1393                    });
1394                }
1395            })
1396            .ok();
1397        })
1398    }
1399
1400    fn rebuild_extension_index(&self, cx: &mut Context<Self>) -> Task<ExtensionIndex> {
1401        let fs = self.fs.clone();
1402        let work_dir = self.wasm_host.work_dir.clone();
1403        let extensions_dir = self.installed_dir.clone();
1404        let index_path = self.index_path.clone();
1405        let proxy = self.proxy.clone();
1406        cx.background_spawn(async move {
1407            let start_time = Instant::now();
1408            let mut index = ExtensionIndex::default();
1409
1410            fs.create_dir(&work_dir).await.log_err();
1411            fs.create_dir(&extensions_dir).await.log_err();
1412
1413            let extension_paths = fs.read_dir(&extensions_dir).await;
1414            if let Ok(mut extension_paths) = extension_paths {
1415                while let Some(extension_dir) = extension_paths.next().await {
1416                    let Ok(extension_dir) = extension_dir else {
1417                        continue;
1418                    };
1419
1420                    if extension_dir
1421                        .file_name()
1422                        .map_or(false, |file_name| file_name == ".DS_Store")
1423                    {
1424                        continue;
1425                    }
1426
1427                    Self::add_extension_to_index(
1428                        fs.clone(),
1429                        extension_dir,
1430                        &mut index,
1431                        proxy.clone(),
1432                    )
1433                    .await
1434                    .log_err();
1435                }
1436            }
1437
1438            if let Ok(index_json) = serde_json::to_string_pretty(&index) {
1439                fs.save(&index_path, &index_json.as_str().into(), Default::default())
1440                    .await
1441                    .context("failed to save extension index")
1442                    .log_err();
1443            }
1444
1445            log::info!("rebuilt extension index in {:?}", start_time.elapsed());
1446            index
1447        })
1448    }
1449
1450    async fn add_extension_to_index(
1451        fs: Arc<dyn Fs>,
1452        extension_dir: PathBuf,
1453        index: &mut ExtensionIndex,
1454        proxy: Arc<ExtensionHostProxy>,
1455    ) -> Result<()> {
1456        let mut extension_manifest = ExtensionManifest::load(fs.clone(), &extension_dir).await?;
1457        let extension_id = extension_manifest.id.clone();
1458
1459        // TODO: distinguish dev extensions more explicitly, by the absence
1460        // of a checksum file that we'll create when downloading normal extensions.
1461        let is_dev = fs
1462            .metadata(&extension_dir)
1463            .await?
1464            .context("directory does not exist")?
1465            .is_symlink;
1466
1467        if let Ok(mut language_paths) = fs.read_dir(&extension_dir.join("languages")).await {
1468            while let Some(language_path) = language_paths.next().await {
1469                let language_path = language_path?;
1470                let Ok(relative_path) = language_path.strip_prefix(&extension_dir) else {
1471                    continue;
1472                };
1473                let Ok(Some(fs_metadata)) = fs.metadata(&language_path).await else {
1474                    continue;
1475                };
1476                if !fs_metadata.is_dir {
1477                    continue;
1478                }
1479                let config = fs.load(&language_path.join("config.toml")).await?;
1480                let config = ::toml::from_str::<LanguageConfig>(&config)?;
1481
1482                let relative_path = relative_path.to_path_buf();
1483                if !extension_manifest.languages.contains(&relative_path) {
1484                    extension_manifest.languages.push(relative_path.clone());
1485                }
1486
1487                index.languages.insert(
1488                    config.name.clone(),
1489                    ExtensionIndexLanguageEntry {
1490                        extension: extension_id.clone(),
1491                        path: relative_path,
1492                        matcher: config.matcher,
1493                        hidden: config.hidden,
1494                        grammar: config.grammar,
1495                    },
1496                );
1497            }
1498        }
1499
1500        if let Ok(mut theme_paths) = fs.read_dir(&extension_dir.join("themes")).await {
1501            while let Some(theme_path) = theme_paths.next().await {
1502                let theme_path = theme_path?;
1503                let Ok(relative_path) = theme_path.strip_prefix(&extension_dir) else {
1504                    continue;
1505                };
1506
1507                let Some(theme_families) = proxy
1508                    .list_theme_names(theme_path.clone(), fs.clone())
1509                    .await
1510                    .log_err()
1511                else {
1512                    continue;
1513                };
1514
1515                let relative_path = relative_path.to_path_buf();
1516                if !extension_manifest.themes.contains(&relative_path) {
1517                    extension_manifest.themes.push(relative_path.clone());
1518                }
1519
1520                for theme_name in theme_families {
1521                    index.themes.insert(
1522                        theme_name.into(),
1523                        ExtensionIndexThemeEntry {
1524                            extension: extension_id.clone(),
1525                            path: relative_path.clone(),
1526                        },
1527                    );
1528                }
1529            }
1530        }
1531
1532        if let Ok(mut icon_theme_paths) = fs.read_dir(&extension_dir.join("icon_themes")).await {
1533            while let Some(icon_theme_path) = icon_theme_paths.next().await {
1534                let icon_theme_path = icon_theme_path?;
1535                let Ok(relative_path) = icon_theme_path.strip_prefix(&extension_dir) else {
1536                    continue;
1537                };
1538
1539                let Some(icon_theme_families) = proxy
1540                    .list_icon_theme_names(icon_theme_path.clone(), fs.clone())
1541                    .await
1542                    .log_err()
1543                else {
1544                    continue;
1545                };
1546
1547                let relative_path = relative_path.to_path_buf();
1548                if !extension_manifest.icon_themes.contains(&relative_path) {
1549                    extension_manifest.icon_themes.push(relative_path.clone());
1550                }
1551
1552                for icon_theme_name in icon_theme_families {
1553                    index.icon_themes.insert(
1554                        icon_theme_name.into(),
1555                        ExtensionIndexIconThemeEntry {
1556                            extension: extension_id.clone(),
1557                            path: relative_path.clone(),
1558                        },
1559                    );
1560                }
1561            }
1562        }
1563
1564        let extension_wasm_path = extension_dir.join("extension.wasm");
1565        if fs.is_file(&extension_wasm_path).await {
1566            extension_manifest
1567                .lib
1568                .kind
1569                .get_or_insert(ExtensionLibraryKind::Rust);
1570        }
1571
1572        index.extensions.insert(
1573            extension_id.clone(),
1574            ExtensionIndexEntry {
1575                dev: is_dev,
1576                manifest: Arc::new(extension_manifest),
1577            },
1578        );
1579
1580        Ok(())
1581    }
1582
1583    fn prepare_remote_extension(
1584        &mut self,
1585        extension_id: Arc<str>,
1586        is_dev: bool,
1587        tmp_dir: PathBuf,
1588        cx: &mut Context<Self>,
1589    ) -> Task<Result<()>> {
1590        let src_dir = self.extensions_dir().join(extension_id.as_ref());
1591        let Some(loaded_extension) = self.extension_index.extensions.get(&extension_id).cloned()
1592        else {
1593            return Task::ready(Err(anyhow!("extension no longer installed")));
1594        };
1595        let fs = self.fs.clone();
1596        cx.background_spawn(async move {
1597            const EXTENSION_TOML: &str = "extension.toml";
1598            const EXTENSION_WASM: &str = "extension.wasm";
1599            const CONFIG_TOML: &str = "config.toml";
1600
1601            if is_dev {
1602                let manifest_toml = toml::to_string(&loaded_extension.manifest)?;
1603                fs.save(
1604                    &tmp_dir.join(EXTENSION_TOML),
1605                    &Rope::from(manifest_toml),
1606                    language::LineEnding::Unix,
1607                )
1608                .await?;
1609            } else {
1610                fs.copy_file(
1611                    &src_dir.join(EXTENSION_TOML),
1612                    &tmp_dir.join(EXTENSION_TOML),
1613                    fs::CopyOptions::default(),
1614                )
1615                .await?
1616            }
1617
1618            if fs.is_file(&src_dir.join(EXTENSION_WASM)).await {
1619                fs.copy_file(
1620                    &src_dir.join(EXTENSION_WASM),
1621                    &tmp_dir.join(EXTENSION_WASM),
1622                    fs::CopyOptions::default(),
1623                )
1624                .await?
1625            }
1626
1627            for language_path in loaded_extension.manifest.languages.iter() {
1628                if fs
1629                    .is_file(&src_dir.join(language_path).join(CONFIG_TOML))
1630                    .await
1631                {
1632                    fs.create_dir(&tmp_dir.join(language_path)).await?;
1633                    fs.copy_file(
1634                        &src_dir.join(language_path).join(CONFIG_TOML),
1635                        &tmp_dir.join(language_path).join(CONFIG_TOML),
1636                        fs::CopyOptions::default(),
1637                    )
1638                    .await?
1639                }
1640            }
1641
1642            for (adapter_name, meta) in loaded_extension.manifest.debug_adapters.iter() {
1643                let schema_path = &extension::build_debug_adapter_schema_path(adapter_name, meta);
1644
1645                if fs.is_file(&src_dir.join(schema_path)).await {
1646                    match schema_path.parent() {
1647                        Some(parent) => fs.create_dir(&tmp_dir.join(parent)).await?,
1648                        None => {}
1649                    }
1650                    fs.copy_file(
1651                        &src_dir.join(schema_path),
1652                        &tmp_dir.join(schema_path),
1653                        fs::CopyOptions::default(),
1654                    )
1655                    .await?
1656                }
1657            }
1658
1659            Ok(())
1660        })
1661    }
1662
1663    async fn sync_extensions_over_ssh(
1664        this: &WeakEntity<Self>,
1665        client: WeakEntity<SshRemoteClient>,
1666        cx: &mut AsyncApp,
1667    ) -> Result<()> {
1668        let extensions = this.update(cx, |this, _cx| {
1669            this.extension_index
1670                .extensions
1671                .iter()
1672                .filter_map(|(id, entry)| {
1673                    if !entry.manifest.allow_remote_load() {
1674                        return None;
1675                    }
1676                    Some(proto::Extension {
1677                        id: id.to_string(),
1678                        version: entry.manifest.version.to_string(),
1679                        dev: entry.dev,
1680                    })
1681                })
1682                .collect()
1683        })?;
1684
1685        let response = client
1686            .update(cx, |client, _cx| {
1687                client
1688                    .proto_client()
1689                    .request(proto::SyncExtensions { extensions })
1690            })?
1691            .await?;
1692        let path_style = client.read_with(cx, |client, _| client.path_style())?;
1693
1694        for missing_extension in response.missing_extensions.into_iter() {
1695            let tmp_dir = tempfile::tempdir()?;
1696            this.update(cx, |this, cx| {
1697                this.prepare_remote_extension(
1698                    missing_extension.id.clone().into(),
1699                    missing_extension.dev,
1700                    tmp_dir.path().to_owned(),
1701                    cx,
1702                )
1703            })?
1704            .await?;
1705            let dest_dir = RemotePathBuf::new(
1706                PathBuf::from(&response.tmp_dir).join(missing_extension.clone().id),
1707                path_style,
1708            );
1709            log::info!("Uploading extension {}", missing_extension.clone().id);
1710
1711            client
1712                .update(cx, |client, cx| {
1713                    client.upload_directory(tmp_dir.path().to_owned(), dest_dir.clone(), cx)
1714                })?
1715                .await?;
1716
1717            log::info!(
1718                "Finished uploading extension {}",
1719                missing_extension.clone().id
1720            );
1721
1722            client
1723                .update(cx, |client, _cx| {
1724                    client.proto_client().request(proto::InstallExtension {
1725                        tmp_dir: dest_dir.to_proto(),
1726                        extension: Some(missing_extension),
1727                    })
1728                })?
1729                .await?;
1730        }
1731
1732        anyhow::Ok(())
1733    }
1734
1735    pub async fn update_ssh_clients(this: &WeakEntity<Self>, cx: &mut AsyncApp) -> Result<()> {
1736        let clients = this.update(cx, |this, _cx| {
1737            this.ssh_clients.retain(|_k, v| v.upgrade().is_some());
1738            this.ssh_clients.values().cloned().collect::<Vec<_>>()
1739        })?;
1740
1741        for client in clients {
1742            Self::sync_extensions_over_ssh(&this, client, cx)
1743                .await
1744                .log_err();
1745        }
1746
1747        anyhow::Ok(())
1748    }
1749
1750    pub fn register_ssh_client(&mut self, client: Entity<SshRemoteClient>, cx: &mut Context<Self>) {
1751        let connection_options = client.read(cx).connection_options();
1752        let ssh_url = connection_options.ssh_url();
1753
1754        if let Some(existing_client) = self.ssh_clients.get(&ssh_url) {
1755            if existing_client.upgrade().is_some() {
1756                return;
1757            }
1758        }
1759
1760        self.ssh_clients.insert(ssh_url, client.downgrade());
1761        self.ssh_registered_tx.unbounded_send(()).ok();
1762    }
1763}
1764
1765fn load_plugin_queries(root_path: &Path) -> LanguageQueries {
1766    let mut result = LanguageQueries::default();
1767    if let Some(entries) = std::fs::read_dir(root_path).log_err() {
1768        for entry in entries {
1769            let Some(entry) = entry.log_err() else {
1770                continue;
1771            };
1772            let path = entry.path();
1773            if let Some(remainder) = path.strip_prefix(root_path).ok().and_then(|p| p.to_str()) {
1774                if !remainder.ends_with(".scm") {
1775                    continue;
1776                }
1777                for (name, query) in QUERY_FILENAME_PREFIXES {
1778                    if remainder.starts_with(name) {
1779                        if let Some(contents) = std::fs::read_to_string(&path).log_err() {
1780                            match query(&mut result) {
1781                                None => *query(&mut result) = Some(contents.into()),
1782                                Some(r) => r.to_mut().push_str(contents.as_ref()),
1783                            }
1784                        }
1785                        break;
1786                    }
1787                }
1788            }
1789        }
1790    }
1791    result
1792}