diff --git a/crates/fonts/src/shx/mod.rs b/crates/fonts/src/shx/mod.rs index 559621b70..016fe9821 100644 --- a/crates/fonts/src/shx/mod.rs +++ b/crates/fonts/src/shx/mod.rs @@ -41,8 +41,8 @@ use cadcraft_geom::Vec2; pub use compile::compile; pub use table::{ - FontProvider, add_drawing_dir, clear_registered, drawing_dirs, find, font_map, generation, register, search_path, set_font_dirs, set_font_map, - set_provider, set_search_path, + FontProvider, add_drawing_dir, clear_registered, drawing_dirs, find, font_map, generation, installed, register, search_path, set_font_dirs, + set_font_map, set_provider, set_search_path, }; pub use text::ShxText; pub(crate) use text::{shape, width}; diff --git a/crates/fonts/src/shx/table.rs b/crates/fonts/src/shx/table.rs index 859ff0d3c..efcca16b6 100644 --- a/crates/fonts/src/shx/table.rs +++ b/crates/fonts/src/shx/table.rs @@ -238,6 +238,32 @@ pub fn find(name: &str) -> Option> { #[cfg(not(target_arch = "wasm32"))] const MAX_DIR_ENTRIES: usize = 10_000; +/// The SHX fonts in the user's font folders ([`set_font_dirs`]) and the registered ones, by file +/// stem, sorted without repeats (for font lists). Not read: only their names are listed. +pub fn installed() -> Vec { + let (dirs, mut out): (Vec, Vec) = { + let t = table(); + (t.font_dirs.clone(), t.registered.keys().map(|k| k.trim_end_matches(".shx").to_string()).collect()) + }; + #[cfg(not(target_arch = "wasm32"))] + for d in &dirs { + let Ok(entries) = std::fs::read_dir(d) else { continue }; + for e in entries.take(MAX_DIR_ENTRIES).filter_map(Result::ok) { + let p = e.path(); + if p.extension().is_some_and(|x| x.eq_ignore_ascii_case("shx")) + && let Some(stem) = p.file_stem().and_then(|s| s.to_str()) + { + out.push(stem.to_string()); + } + } + } + #[cfg(target_arch = "wasm32")] + let _ = dirs; + out.sort_by_key(|n| n.to_lowercase()); + out.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + out +} + /// The file `name` (a lower-case key) in the first of `dirs` that has it, whatever the case of /// its name: lower-case, upper-case, else any other case found in the directory (`Simplex.shx` /// on a case-sensitive file system). diff --git a/crates/fonts/tests/shx_font_folders.rs b/crates/fonts/tests/shx_font_folders.rs index a1fa69ed8..a911b9382 100644 --- a/crates/fonts/tests/shx_font_folders.rs +++ b/crates/fonts/tests/shx_font_folders.rs @@ -20,6 +20,9 @@ fn shx_fonts_in_the_users_font_folders_are_found() { assert!(shx::find("cadcraft-top.shx").is_some_and(|f| f.has_shape(65))); assert!(shx::find("CADCRAFT-DEEP").is_some(), "in a folder under the font folder"); assert!(ttf::available("cadcraft-deep.shx")); + // Font lists name them. + let names = shx::installed(); + assert!(names.iter().any(|n| n == "cadcraft-top") && names.iter().any(|n| n == "cadcraft-deep"), "{names:?}"); // A file added later is found after Look for Fonts Again. std::fs::write(dir.join("cadcraft-later.shx"), &bytes).unwrap(); @@ -28,5 +31,6 @@ fn shx_fonts_in_the_users_font_folders_are_found() { ttf::set_font_dirs::<&str>(&[]); assert!(shx::find("cadcraft-top.shx").is_none()); + assert!(!shx::installed().iter().any(|n| n.starts_with("cadcraft-"))); let _ = std::fs::remove_dir_all(&dir); }