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 <noreply@anthropic.com>
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.
|
/// Returns `None` for simple (dash-only) linetypes or unknown names.
|
||||||
pub fn complex_lt(name: &str) -> Option<&'static ComplexLt> {
|
pub fn complex_lt(name: &str) -> Option<&'static ComplexLt> {
|
||||||
COMPLEX_CATALOG
|
COMPLEX_CATALOG
|
||||||
.get_or_init(|| parse_complex(LIN_SOURCE))
|
.get_or_init(|| parse_complex(lin_source()))
|
||||||
.get(&name.to_ascii_uppercase())
|
.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");
|
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 ────────────────────────────────────────────────
|
// ── Pattern art extraction ────────────────────────────────────────────────
|
||||||
|
|
||||||
/// Extract the ASCII-art portion of a LIN description.
|
/// 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.
|
/// Add all standard OpenCADStudio linetypes to `doc`, skipping existing ones.
|
||||||
pub fn populate_document(doc: &mut CadDocument) {
|
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
|
/// 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();
|
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] {
|
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 ───────────────────────────────────────────────────────
|
// ── Geometry helper ───────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in new issue
Block a user