Add infrastructure for loading icon themes from extensions (#23203)
This PR adds the supporting infrastructure to support loading icon themes defined by extensions. Here's an example icon theme: ```json { "name": "My Icon Theme", "author": "Me <me@example.com>", "themes": [ { "name": "My Icon Theme", "appearance": "dark", "file_icons": { "gleam": { "path": "./icons/file_type_gleam.svg" }, "toml": { "path": "./icons/file_type_toml.svg" } } } ] } ``` The icon paths are resolved relative to the root of the extension directory. Release Notes: - N/A
This commit is contained in:
parent
3b8a5c9647
commit
f53915c711
11 changed files with 303 additions and 10 deletions
|
@ -560,6 +560,21 @@ fn populate_defaults(manifest: &mut ExtensionManifest, extension_path: &Path) ->
|
|||
}
|
||||
}
|
||||
|
||||
let icon_themes_dir = extension_path.join("icon_themes");
|
||||
if icon_themes_dir.exists() {
|
||||
for entry in fs::read_dir(&icon_themes_dir).context("failed to list icon themes dir")? {
|
||||
let entry = entry?;
|
||||
let icon_theme_path = entry.path();
|
||||
if icon_theme_path.extension() == Some("json".as_ref()) {
|
||||
let relative_icon_theme_path =
|
||||
icon_theme_path.strip_prefix(extension_path)?.to_path_buf();
|
||||
if !manifest.icon_themes.contains(&relative_icon_theme_path) {
|
||||
manifest.icon_themes.push(relative_icon_theme_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let snippets_json_path = extension_path.join("snippets.json");
|
||||
if snippets_json_path.exists() {
|
||||
manifest.snippets = Some(snippets_json_path);
|
||||
|
|
|
@ -103,6 +103,21 @@ pub trait ExtensionThemeProxy: Send + Sync + 'static {
|
|||
fn load_user_theme(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<()>>;
|
||||
|
||||
fn reload_current_theme(&self, cx: &mut AppContext);
|
||||
|
||||
fn list_icon_theme_names(
|
||||
&self,
|
||||
icon_theme_path: PathBuf,
|
||||
fs: Arc<dyn Fs>,
|
||||
) -> Task<Result<Vec<String>>>;
|
||||
|
||||
fn remove_icon_themes(&self, icon_themes: Vec<SharedString>);
|
||||
|
||||
fn load_icon_theme(
|
||||
&self,
|
||||
icon_theme_path: PathBuf,
|
||||
icons_root_dir: PathBuf,
|
||||
fs: Arc<dyn Fs>,
|
||||
) -> Task<Result<()>>;
|
||||
}
|
||||
|
||||
impl ExtensionThemeProxy for ExtensionHostProxy {
|
||||
|
@ -137,6 +152,39 @@ impl ExtensionThemeProxy for ExtensionHostProxy {
|
|||
|
||||
proxy.reload_current_theme(cx)
|
||||
}
|
||||
|
||||
fn list_icon_theme_names(
|
||||
&self,
|
||||
icon_theme_path: PathBuf,
|
||||
fs: Arc<dyn Fs>,
|
||||
) -> Task<Result<Vec<String>>> {
|
||||
let Some(proxy) = self.theme_proxy.read().clone() else {
|
||||
return Task::ready(Ok(Vec::new()));
|
||||
};
|
||||
|
||||
proxy.list_icon_theme_names(icon_theme_path, fs)
|
||||
}
|
||||
|
||||
fn remove_icon_themes(&self, icon_themes: Vec<SharedString>) {
|
||||
let Some(proxy) = self.theme_proxy.read().clone() else {
|
||||
return;
|
||||
};
|
||||
|
||||
proxy.remove_icon_themes(icon_themes)
|
||||
}
|
||||
|
||||
fn load_icon_theme(
|
||||
&self,
|
||||
icon_theme_path: PathBuf,
|
||||
icons_root_dir: PathBuf,
|
||||
fs: Arc<dyn Fs>,
|
||||
) -> Task<Result<()>> {
|
||||
let Some(proxy) = self.theme_proxy.read().clone() else {
|
||||
return Task::ready(Ok(()));
|
||||
};
|
||||
|
||||
proxy.load_icon_theme(icon_theme_path, icons_root_dir, fs)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ExtensionGrammarProxy: Send + Sync + 'static {
|
||||
|
|
|
@ -70,6 +70,8 @@ pub struct ExtensionManifest {
|
|||
#[serde(default)]
|
||||
pub themes: Vec<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub icon_themes: Vec<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub languages: Vec<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub grammars: BTreeMap<Arc<str>, GrammarManifestEntry>,
|
||||
|
@ -199,6 +201,7 @@ fn manifest_from_old_manifest(
|
|||
themes.dedup();
|
||||
themes
|
||||
},
|
||||
icon_themes: Vec::new(),
|
||||
languages: {
|
||||
let mut languages = manifest_json.languages.into_values().collect::<Vec<_>>();
|
||||
languages.sort();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue