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