M0.9: trim mixed edge spaces and dots, document the name limits (#1154)

Review: " . .name. . " kept inner dots at the edges; trim spaces and dots
in one pass. docs/cli.md and safe_file_name's comment give the 100 and
200 character limits.
This commit is contained in:
Gert Pellin
2026-10-22 21:43:52 +02:00
parent ca30791fd7
commit eb07717783
3 changed files with 8 additions and 6 deletions
+3 -2
View File
@@ -208,10 +208,10 @@ pub fn info(path: &str, as_json: bool) -> CliResult<ExitCode> {
} }
/// The file name a layer exports to: the app's rule ([`figcraft_engine::cmd::file::safe_file_name`], /// The file name a layer exports to: the app's rule ([`figcraft_engine::cmd::file::safe_file_name`],
/// so `/` becomes `_` too), without leading or trailing spaces and dots. /// so `/` becomes `_` too), without leading or trailing spaces and dots, at most 100 characters.
fn sanitize(name: &str) -> String { fn sanitize(name: &str) -> String {
let s = figcraft_engine::cmd::file::safe_file_name(name); let s = figcraft_engine::cmd::file::safe_file_name(name);
let s = s.trim().trim_matches('.').trim().to_string(); let s = s.trim_matches(|c: char| c == '.' || c.is_whitespace()).to_string();
if s.is_empty() { "layer".into() } else { s.chars().take(100).collect() } if s.is_empty() { "layer".into() } else { s.chars().take(100).collect() }
} }
@@ -418,6 +418,7 @@ mod tests {
assert_eq!(sanitize("Q&A, 50% #1 [v2] {x} ~é"), "Q&A, 50% #1 [v2] {x} ~é"); assert_eq!(sanitize("Q&A, 50% #1 [v2] {x} ~é"), "Q&A, 50% #1 [v2] {x} ~é");
assert_eq!(sanitize("a\\b:c*d?e\"f<g>h|i\tj"), "a_b_c_d_e_f_g_h_i_j"); assert_eq!(sanitize("a\\b:c*d?e\"f<g>h|i\tj"), "a_b_c_d_e_f_g_h_i_j");
assert_eq!(sanitize(" .hidden. "), "hidden"); assert_eq!(sanitize(" .hidden. "), "hidden");
assert_eq!(sanitize(" . .name. . "), "name", "spaces and dots at the edges, mixed");
assert_eq!(sanitize(&"x".repeat(300)).chars().count(), 100); assert_eq!(sanitize(&"x".repeat(300)).chars().count(), 100);
} }
+3 -2
View File
@@ -1170,8 +1170,9 @@ fn export_path(name: &str) -> String {
} }
/// `name` without path separators and characters file systems reject (`/ \ : * ? " < > |` and /// `name` without path separators and characters file systems reject (`/ \ : * ? " < > |` and
/// control characters become `_`); everything else is kept. `figcraft-cli export` names its files /// control characters become `_`); everything else is kept, up to the first 200 characters.
/// by this rule too. /// `figcraft-cli export` names its files by this rule too (and keeps at most 100 characters before
/// the number and extension it adds).
pub fn safe_file_name(name: &str) -> String { pub fn safe_file_name(name: &str) -> String {
name.chars().take(200).map(|c| if c.is_control() || "/\\:*?\"<>|".contains(c) { '_' } else { c }).collect() name.chars().take(200).map(|c| if c.is_control() || "/\\:*?\"<>|".contains(c) { '_' } else { c }).collect()
} }
+2 -2
View File
@@ -53,8 +53,8 @@ page 1 "Screens": 380 nodes, 4 top-level
after the frame (`Home.png`, `Settings.png`…); with no frames, one file per top-level layer. after the frame (`Home.png`, `Settings.png`…); with no frames, one file per top-level layer.
The name is kept as it is, except for the characters file systems refuse (`/ \ : * ? " < > |` The name is kept as it is, except for the characters file systems refuse (`/ \ : * ? " < > |`
and control characters), which become `_`, and leading or trailing spaces and dots, which are and control characters), which become `_`, and leading or trailing spaces and dots, which are
dropped. The app's export replaces the same characters (there a `/` makes a folder). Two layers dropped. A name is cut at 100 characters. The app's export replaces the same characters (there a
with the same name get `Name 2`, `Name 3`… `/` makes a folder). Two layers with the same name get `Name 2`, `Name 3`…
- `<out>` has an image extension: one file with the given `--node`, or the whole page composited. - `<out>` has an image extension: one file with the given `--node`, or the whole page composited.
- `--node` takes a layer id (`12` or `0:12`) or a layer name. - `--node` takes a layer id (`12` or `0:12`) or a layer name.
- `--format fig` (or an `<out>` ending in `.fig`) writes the whole file as `.fig`, experimental: - `--format fig` (or an `<out>` ending in `.fig`) writes the whole file as `.fig`, experimental: