diff --git a/crates/engine/src/script.rs b/crates/engine/src/script.rs index 4a66ff87f..bcc4f8fe9 100644 --- a/crates/engine/src/script.rs +++ b/crates/engine/src/script.rs @@ -26,7 +26,8 @@ pub struct Step { pub fn parse(text: &str) -> Result, String> { // Windows tools save "UTF-8 with BOM"; `trim` keeps U+FEFF, which then became part of the // first command id. - let t = text.trim_start_matches('\u{feff}').trim(); + let body = text.trim_start_matches('\u{feff}'); + let t = body.trim(); if t.starts_with('[') { let v: Value = serde_json::from_str(t).map_err(|e| format!("script: {e}"))?; return v @@ -38,7 +39,8 @@ pub fn parse(text: &str) -> Result, String> { .collect(); } let mut out = Vec::new(); - for (n, line) in t.lines().enumerate() { + // Number lines from the untrimmed text so leading blank lines still count. + for (n, line) in body.lines().enumerate() { let l = line.trim(); if l.is_empty() || l.starts_with('#') || l.starts_with("//") { continue; @@ -185,6 +187,12 @@ impl crate::Session { mod tests { use super::*; + #[test] + fn leading_blank_lines_keep_line_numbers() { + let e = parse("\n\n# c\nfile.new\nframe.create {bad").unwrap_err(); + assert!(e.contains("line 5"), "{e}"); + } + #[test] fn parses_all_forms() { let a = parse(r#"[{"command": "file.new"}, {"command": "frame.create", "params": {"rect": [0, 0, 10, 10]}}]"#).unwrap();