extension_host.rs

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