use std::borrow::Cow;
use std::fs;
use std::path::{Component, Path, PathBuf};
use std::sync::OnceLock;
use fluidattacks_designs_domain::color::GRADIENT_01;
use gpui::{AssetSource, Result, SharedString};
#[derive(Default, Clone, Copy)]
#[non_exhaustive]
pub struct Assets;
impl Assets {
#[must_use]
pub const fn new() -> Self {
Self
}
}
fn candidates(exe: &Path) -> Vec<PathBuf> {
exe.ancestors()
.skip(2)
.take(3)
.map(|dir| dir.join("Resources"))
.collect()
}
fn resources() -> Result<PathBuf> {
static ROOT: OnceLock<Option<PathBuf>> = OnceLock::new();
let found = ROOT.get_or_init(|| {
let exe = std::env::current_exe().ok()?;
candidates(&exe)
.into_iter()
.find(|path| path.join("icons").is_dir())
});
found.clone().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::NotFound,
"no Resources holding the design system's assets at or above this \
executable, so the packaging step did not land them",
)
.into()
})
}
fn is_ours(path: &str) -> bool {
if !(path.starts_with("icons/") || path.starts_with("images/")) {
return false;
}
!Path::new(path)
.components()
.any(|part| matches!(part, Component::ParentDir | Component::RootDir))
}
fn gradient_svg(solid: &str) -> String {
let (from, to) = GRADIENT_01;
let defs = format!(
"<defs><linearGradient id=\"designs-gradient\" \
gradientTransform=\"rotate(-45)\"><stop stop-color=\"#{from:06x}\"/>\
<stop offset=\"1\" stop-color=\"#{to:06x}\"/></linearGradient></defs>"
);
solid
.replacen("<svg ", "<svg width=\"24\" height=\"24\" ", 1)
.replacen('>', &format!(">{defs}"), 1)
.replace("<path ", "<path fill=\"url(#designs-gradient)\" ")
}
fn solid_source(path: &str) -> (Cow<'_, str>, bool) {
match path.strip_prefix("icons/gradient") {
Some(rest) if rest.is_empty() || rest.starts_with('/') => {
(Cow::Owned(format!("icons/solid{rest}")), true)
}
_ => (Cow::Borrowed(path), false),
}
}
pub fn faces() -> Result<Vec<Cow<'static, [u8]>>> {
faces_in(&resources()?)
}
fn faces_in(root: &Path) -> Result<Vec<Cow<'static, [u8]>>> {
let dir = root.join("fonts");
let mut files: Vec<PathBuf> = fs::read_dir(&dir)
.into_iter()
.flatten()
.flatten()
.map(|entry| entry.path())
.filter(|path| path.extension().is_some_and(|kind| kind == "ttf"))
.collect();
files.sort();
if files.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!(
"no .ttf under {}, so the type would be the platform's",
dir.display()
),
)
.into());
}
files
.iter()
.map(|file| fs::read(file).map(Cow::Owned).map_err(Into::into))
.collect()
}
fn load_from(root: &Path, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
if !is_ours(path) {
return Ok(None);
}
let (source, gradient) = solid_source(path);
let Ok(bytes) = fs::read(root.join(source.as_ref())) else {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("no design system asset {path} under {}", root.display()),
)
.into());
};
if !gradient {
return Ok(Some(Cow::Owned(bytes)));
}
let Ok(svg) = String::from_utf8(bytes) else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("{path} is not utf-8, so no gradient can be injected"),
)
.into());
};
Ok(Some(Cow::Owned(gradient_svg(&svg).into_bytes())))
}
fn list_from(root: &Path, path: &str) -> Vec<SharedString> {
let (source, _) = solid_source(path);
if !is_ours(&source) {
return Vec::new();
}
let mut names: Vec<SharedString> = fs::read_dir(root.join(source.as_ref()))
.into_iter()
.flatten()
.flatten()
.filter_map(|entry| entry.file_name().into_string().ok())
.map(SharedString::from)
.collect();
names.sort_unstable();
names.dedup();
names
}
impl AssetSource for Assets {
fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
load_from(&resources()?, path)
}
fn list(&self, path: &str) -> Result<Vec<SharedString>> {
Ok(list_from(&resources()?, path))
}
}
#[cfg(test)]
mod tests {
use super::{candidates, gradient_svg, list_from, load_from};
use fluidattacks_designs_domain::icon::REQUIRED_ICONS;
use std::path::{Path, PathBuf};
const SOLID: &str = "<svg xmlns=\"x\" viewBox=\"0 0 512 512\"><path d=\"M0\"/></svg>";
fn resources(case: &str) -> PathBuf {
let root = std::env::temp_dir().join("designs-assets-tests").join(case);
let _ = std::fs::remove_dir_all(&root);
write(&root.join("icons/solid/gear.svg"), SOLID.as_bytes());
write(
&root.join("images/integrates/empty/addRoot.png"),
b"\x89PNG stub",
);
root
}
fn write(file: &Path, body: &[u8]) {
if let Some(parent) = file.parent() {
std::fs::create_dir_all(parent).expect("create the fixture directory");
}
std::fs::write(file, body).expect("write the fixture");
}
fn glyph_constants() -> Vec<(String, String)> {
let tokens = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("domain")
.join("src");
let sources = crate_sources(tokens);
sources
.iter()
.flat_map(|source| source.lines().filter_map(declared_glyph))
.collect()
}
fn declared_glyph(line: &str) -> Option<(String, String)> {
let rest = line.trim().strip_prefix("pub const ")?;
let (name, tail) = rest.split_once(": &str = \"")?;
let (glyph, _) = tail.split_once('"')?;
Some((name.to_owned(), glyph.to_owned()))
}
fn resolve(argument: &str, declared: &[(String, String)]) -> Option<String> {
if let Some(quoted) = argument.strip_prefix('"') {
return quoted.split_once('"').map(|(glyph, _)| glyph.to_owned());
}
declared
.iter()
.find(|(name, _)| name == argument)
.map(|(_, glyph)| glyph.clone())
}
fn named_glyphs(source: &str, declared: &[(String, String)]) -> Vec<String> {
let call = concat!("Icon", "::new(");
source
.split(call)
.skip(1)
.filter_map(|rest| rest.split_once(')').map(|(argument, _)| argument.trim()))
.filter_map(|argument| resolve(argument, declared))
.collect()
}
fn crate_sources(dir: PathBuf) -> Vec<String> {
let Ok(entries) = std::fs::read_dir(dir) else {
return Vec::new();
};
let mut sources = Vec::new();
for path in entries.flatten().map(|entry| entry.path()) {
if path.is_dir() {
sources.extend(crate_sources(path));
} else if path.extension().is_some_and(|ext| ext == "rs") {
sources.extend(std::fs::read_to_string(path));
}
}
sources
}
#[test]
fn required_icons_covers_every_glyph_the_widgets_name() {
let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
let sources = crate_sources(dir);
assert!(
sources.len() > 1,
"the scan found no sources, so it is not reading the crate"
);
let declared = glyph_constants();
assert!(
!declared.is_empty(),
"no token constants were read, so glyphs named through one go unchecked"
);
let missing: Vec<String> = sources
.iter()
.flat_map(|source| named_glyphs(source, &declared))
.filter(|glyph| {
!REQUIRED_ICONS
.iter()
.any(|&(_, listed)| listed == glyph.as_str())
})
.collect();
assert!(
missing.is_empty(),
"add these to REQUIRED_ICONS: {missing:?}"
);
}
#[test]
fn resources_resolves_for_a_bundle_a_binary_and_an_example() {
assert_eq!(
candidates(Path::new("/A/mrq.app/Contents/MacOS/mrq")).first(),
Some(&PathBuf::from("/A/mrq.app/Contents/Resources"))
);
for exe in [
"/repo/target/debug/mrq",
"/repo/target/debug/examples/gallery",
] {
assert!(
candidates(Path::new(exe)).contains(&PathBuf::from("/repo/target/Resources")),
"{exe} never looks in target/Resources"
);
}
}
#[test]
fn both_namespaces_resolve_from_resources() {
let root = resources("namespaces");
for path in [
"icons/solid/gear.svg",
"images/integrates/empty/addRoot.png",
] {
assert!(load_from(&root, path).expect("ok").is_some(), "{path}");
}
}
#[test]
fn a_missing_asset_is_an_error_naming_where_it_looked() {
let root = resources("missing");
let error = load_from(&root, "icons/solid/nonesuch.svg").expect_err("a miss must fail");
assert!(error.to_string().contains("icons/solid/nonesuch.svg"));
assert!(error.to_string().contains(&root.display().to_string()));
}
#[test]
fn a_foreign_namespace_is_absent_rather_than_broken() {
let root = resources("foreign");
assert!(load_from(&root, "elsewhere/thing.png")
.expect("ok")
.is_none());
}
#[test]
fn a_path_climbing_out_of_resources_is_refused() {
let root = resources("escape");
for path in ["icons/../../etc/passwd", "icons/gradient/../../../secret"] {
assert!(load_from(&root, path).expect("ok").is_none(), "{path}");
}
}
#[test]
fn a_glyph_whose_name_contains_dots_is_served() {
let root = resources("dots");
write(&root.join("icons/solid/v1..2.svg"), SOLID.as_bytes());
assert!(load_from(&root, "icons/solid/v1..2.svg")
.expect("ok")
.is_some());
}
#[test]
fn every_face_in_resources_is_read_in_a_stable_order() {
let root = resources("faces");
write(&root.join("fonts/Zeta-Bold.ttf"), b"ttf");
write(&root.join("fonts/Alpha-Regular.ttf"), b"ttf");
write(&root.join("fonts/notes.txt"), b"not a face");
let faces = super::faces_in(&root).expect("faces");
assert_eq!(faces.len(), 2, "only the faces, and both of them");
}
#[test]
fn a_resources_directory_without_a_face_fails() {
let root = resources("no-faces");
let error = super::faces_in(&root).expect_err("an empty directory must fail");
assert!(error.to_string().contains("no .ttf"));
}
#[test]
fn listing_walks_the_resources_directory() {
let root = resources("listing");
assert!(list_from(&root, "icons/solid").contains(&"gear.svg".into()));
assert!(list_from(&root, "images/integrates").contains(&"empty".into()));
}
#[test]
fn listing_gradients_reports_the_solid_set() {
let root = resources("gradient-list");
for path in ["icons/gradient", "icons/gradient/"] {
assert!(
list_from(&root, path).contains(&"gear.svg".into()),
"{path} listed nothing"
);
}
}
#[test]
fn gradient_derives_from_the_solid_glyph() {
let root = resources("gradient");
let bytes = load_from(&root, "icons/gradient/gear.svg")
.expect("ok")
.expect("some");
let svg = String::from_utf8(bytes.to_vec()).expect("utf-8");
assert!(svg.contains("url(#designs-gradient)"));
}
#[test]
fn a_namespace_that_merely_starts_with_gradient_is_left_alone() {
let (source, gradient) = super::solid_source("icons/gradientfoo/x.svg");
assert_eq!(source, "icons/gradientfoo/x.svg");
assert!(!gradient);
}
#[test]
fn gradient_bounds_the_raster_and_fills_every_path() {
let svg = gradient_svg(SOLID);
assert!(svg.starts_with("<svg width=\"24\" height=\"24\" "));
assert!(svg.contains("<path fill=\"url(#designs-gradient)\" d="));
}
#[test]
fn gradient_defs_land_inside_the_svg_element() {
assert!(gradient_svg(SOLID).contains("512\"><defs><linearGradient"));
}
#[test]
fn gradient_fill_tracks_the_palette() {
let svg = gradient_svg(SOLID);
assert!(svg.contains("stop-color=\"#f32637\""));
assert!(svg.contains("stop-color=\"#b8075d\""));
}
}