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