From b2d8abdd1cffb1f5e3c80716ff79dcad8064f07c Mon Sep 17 00:00:00 2001 From: Johnstocker Date: Sat, 10 Oct 2026 23:33:49 +0700 Subject: [PATCH] fonts: extra font folders from EFFECTCRAFT_FONT_DIRS A tool can hand EffectCraft its own font library (a path list) without installing the fonts system-wide; the folders are scanned like the system ones. Co-Authored-By: Claude Opus 5.5 --- crates/text/src/fonts.rs | 15 +++++++++++++++ docs/agents.md | 2 ++ 2 files changed, 17 insertions(+) diff --git a/crates/text/src/fonts.rs b/crates/text/src/fonts.rs index 2a2c08e8..cb2b2ad2 100644 --- a/crates/text/src/fonts.rs +++ b/crates/text/src/fonts.rs @@ -94,10 +94,17 @@ impl DirectorySource { dirs.push(h.join(".fonts")); } } + dirs.extend(extra_dirs(std::env::var_os("EFFECTCRAFT_FONT_DIRS").as_deref())); Self { dirs } } } +/// Extra font folders from `EFFECTCRAFT_FONT_DIRS` (a path list, `:`-separated, `;` on Windows), so a +/// tool can hand EffectCraft its own font library without installing the fonts system-wide. +fn extra_dirs(var: Option<&std::ffi::OsStr>) -> Vec { + var.map(|v| std::env::split_paths(v).filter(|p| !p.as_os_str().is_empty()).collect()).unwrap_or_default() +} + fn walk(dir: &std::path::Path, depth: u32, out: &mut Vec) { let Ok(rd) = std::fs::read_dir(dir) else { return }; for e in rd.flatten() { @@ -824,6 +831,14 @@ fn system_fallback(c: char, style: &str) -> Option { mod tests { use super::*; + #[test] + fn extra_font_dirs_come_from_a_path_list() { + assert!(extra_dirs(None).is_empty()); + let v = std::env::join_paths(["/a/fonts", "/b/more"]).unwrap_or_default(); + assert_eq!(extra_dirs(Some(&v)), vec![PathBuf::from("/a/fonts"), PathBuf::from("/b/more")]); + assert!(extra_dirs(Some(std::ffi::OsStr::new(""))).is_empty()); + } + #[test] fn bundled_families_and_resolution() { let fams = families(); diff --git a/docs/agents.md b/docs/agents.md index c631bc05..6a3b9e85 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -495,6 +495,8 @@ styles, origin (`bundled`, `system`, `user`) and own-language name (`{"query":"g by name; `{"rescan":true}` first picks up fonts installed since launch). Pass a listed `family` and one of its `styles` to `layer.setText {"font", "style"}`; `text.fontFeatures` says which OpenType options a font draws with its own glyphs. +A tool with its own font library can hand it over without installing it: folders listed in +`EFFECTCRAFT_FONT_DIRS` (a path list, `:`-separated, `;` on Windows) are scanned like the system font folders. In expressions, `text.sourceText.style` / `getStyleAt(i, t)` read styles and the setters (`setFontSize(v, start?, count?)`, `setFillColor`, `setText`, `setJustification`…) return a