Automatically install the HTML extension (#10867)

This PR makes it so the HTML extension will be installed in Zed by
default.

We feel we should keep HTML available out-of-the-box, but we want to do
so while still keeping it as an extension (as opposed to built-in to Zed
natively). There may be a world where we bundle the extension in with
the Zed binary itself, but installing it on startup gets us 99% of the
way there.

The approach for making HTML available by default is quite general, and
could be applied to any extension that we choose (likely other languages
that we want to come out-of-the-box, but that could then be moved to
extensions).

If you do not want the HTML extension in Zed, you can disable the
auto-installation in your `settings.json` and then uninstall the
extension:

```json
{
  "auto_install_extensions": {
    "html": false
  }
}
```

Release Notes:

- Added auto-installation for the HTML extension on startup.
- This can be disabled by adding `{ "auto_install_extensions": { "html":
false } }` to your settings.
This commit is contained in:
Marshall Bowers 2024-04-22 18:02:22 -04:00 committed by GitHub
parent c96a96b3ce
commit 63c529552c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 61 additions and 1 deletions

View file

@ -5,14 +5,29 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
use std::sync::Arc;
use util::merge_non_null_json_value_into;
#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
pub struct ExtensionSettings {
/// The extensions that should be automatically installed by Zed.
///
/// This is used to make functionality provided by extensions (e.g., language support)
/// available out-of-the-box.
#[serde(default)]
pub auto_install_extensions: HashMap<Arc<str>, bool>,
#[serde(default)]
pub auto_update_extensions: HashMap<Arc<str>, bool>,
}
impl ExtensionSettings {
/// Returns whether the given extension should be auto-installed.
pub fn should_auto_install(&self, extension_id: &str) -> bool {
self.auto_install_extensions
.get(extension_id)
.copied()
.unwrap_or(true)
}
pub fn should_auto_update(&self, extension_id: &str) -> bool {
self.auto_update_extensions
.get(extension_id)
@ -27,6 +42,10 @@ impl Settings for ExtensionSettings {
type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _cx: &mut AppContext) -> Result<Self> {
Ok(sources.user.cloned().unwrap_or_default())
let mut merged = serde_json::Value::Null;
for value in [sources.default].into_iter().chain(sources.user) {
merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged);
}
Ok(serde_json::from_value(merged)?)
}
}

View file

@ -291,6 +291,8 @@ impl ExtensionStore {
if let Some(future) = reload_future {
future.await;
}
this.update(&mut cx, |this, cx| this.auto_install_extensions(cx))
.ok();
this.update(&mut cx, |this, cx| this.check_for_updates(cx))
.ok();
})
@ -480,6 +482,38 @@ impl ExtensionStore {
self.fetch_extensions_from_api(&format!("/extensions/{extension_id}"), &[], cx)
}
/// Installs any extensions that should be included with Zed by default.
///
/// This can be used to make certain functionality provided by extensions
/// available out-of-the-box.
pub fn auto_install_extensions(&mut self, cx: &mut ModelContext<Self>) {
let extension_settings = ExtensionSettings::get_global(cx);
let extensions_to_install = extension_settings
.auto_install_extensions
.keys()
.filter(|extension_id| extension_settings.should_auto_install(extension_id))
.filter(|extension_id| {
let is_already_installed = self
.extension_index
.extensions
.contains_key(extension_id.as_ref());
!is_already_installed
})
.cloned()
.collect::<Vec<_>>();
cx.spawn(move |this, mut cx| async move {
for extension_id in extensions_to_install {
this.update(&mut cx, |this, cx| {
this.install_latest_extension(extension_id.clone(), cx);
})
.ok();
}
})
.detach();
}
pub fn check_for_updates(&mut self, cx: &mut ModelContext<Self>) {
let task = self.fetch_extensions_with_update_available(cx);
cx.spawn(move |this, mut cx| async move {