forked from 1b-agent/opencadstudio-upstream
feat(resources): load the user's own hatch patterns and linetypes
*.pat files in <config>/patterns and *.lin files in <config>/linetypes are read after the bundled catalogs, next to the fonts folder SHX files already resolve from. Fixes #1725 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
b5b505ee9d
commit
893dcee6a7
2 files changed
+44
-4
No files matched your search
+10
-2
@@ -69,7 +69,7 @@ static COMPLEX_CATALOG: OnceLock<HashMap<String, ComplexLt>> = OnceLock::new();
|
||||
/// Returns `None` for simple (dash-only) linetypes or unknown names.
|
||||
pub fn complex_lt(name: &str) -> Option<&'static ComplexLt> {
|
||||
COMPLEX_CATALOG
|
||||
.get_or_init(|| parse_complex(LIN_SOURCE))
|
||||
.get_or_init(|| parse_complex(lin_source()))
|
||||
.get(&name.to_ascii_uppercase())
|
||||
}
|
||||
|
||||
@@ -232,6 +232,14 @@ pub fn resolve_complex_lt(document: &CadDocument, name: &str) -> Option<ComplexL
|
||||
|
||||
const LIN_SOURCE: &str = include_str!("../../assets/linetypes/OpenCADStudio.lin");
|
||||
|
||||
/// The bundled linetypes followed by the user's own `.lin` files.
|
||||
fn lin_source() -> &'static str {
|
||||
static SOURCE: OnceLock<String> = OnceLock::new();
|
||||
SOURCE.get_or_init(|| {
|
||||
format!("{LIN_SOURCE}\n{}", crate::io::patterns::user_definitions("linetypes", "lin"))
|
||||
})
|
||||
}
|
||||
|
||||
// ── Pattern art extraction ────────────────────────────────────────────────
|
||||
|
||||
/// Extract the ASCII-art portion of a LIN description.
|
||||
@@ -257,7 +265,7 @@ pub fn extract_pattern(desc: &str) -> String {
|
||||
|
||||
/// Add all standard OpenCADStudio linetypes to `doc`, skipping existing ones.
|
||||
pub fn populate_document(doc: &mut CadDocument) {
|
||||
populate_document_from_source(doc, LIN_SOURCE);
|
||||
populate_document_from_source(doc, lin_source());
|
||||
}
|
||||
|
||||
/// Add the linetypes of a caller-supplied `.lin` source, embedded shapes and
|
||||
|
||||
+34
-2
@@ -39,9 +39,41 @@ pub struct PatternDef {
|
||||
|
||||
static CATALOG: OnceLock<Vec<PatternDef>> = OnceLock::new();
|
||||
|
||||
/// All parsed patterns, in file order.
|
||||
/// All parsed patterns, in file order: the bundled catalog, then the user's
|
||||
/// own `.pat` files.
|
||||
pub fn catalog() -> &'static [PatternDef] {
|
||||
CATALOG.get_or_init(|| parse(PAT_SRC))
|
||||
CATALOG.get_or_init(|| parse(&format!("{PAT_SRC}\n{}", user_definitions("patterns", "pat"))))
|
||||
}
|
||||
|
||||
/// The text of every `*.<ext>` file in `<config>/<folder>`, where users drop
|
||||
/// their own hatch patterns and linetypes. Bundled names come first, so a
|
||||
/// user file adds definitions rather than replacing the built-in ones.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) fn user_definitions(folder: &str, ext: &str) -> String {
|
||||
let Some(dir) = crate::config::config_dir().map(|dir| dir.join(folder)) else {
|
||||
return String::new();
|
||||
};
|
||||
let Ok(entries) = std::fs::read_dir(dir) else {
|
||||
return String::new();
|
||||
};
|
||||
let mut paths: Vec<_> = entries
|
||||
.filter_map(Result::ok)
|
||||
.map(|entry| entry.path())
|
||||
.filter(|path| path.extension().is_some_and(|e| e.eq_ignore_ascii_case(ext)))
|
||||
.collect();
|
||||
paths.sort();
|
||||
paths
|
||||
.iter()
|
||||
.filter_map(|path| std::fs::read(path).ok())
|
||||
.map(|bytes| String::from_utf8_lossy(&bytes).into_owned())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
/// The web build has no user folder.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub(crate) fn user_definitions(_folder: &str, _ext: &str) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
// ── Geometry helper ───────────────────────────────────────────────────────
|
||||
|
||||
Reference in new issue
Block a user