fix(textimport): preserve leading empty Tagged Text paragraphs

Preserve paragraph breaks after a ParaStyle tag starts the story so leading empty paragraphs and their styles survive Tagged Text import.

Validated individually and after #638 with all six cargo xtask ci gates (1,278 tests passed, four existing tests ignored, 15 WASM compilation checks), six independent paragraph/header/Unicode probes, and an actual export-to-placement command smoke test.

Refs #641
This commit is contained in:
Jason Brashear
2026-10-12 18:21:52 -05:00
committed by GitHub
parent cc5b4a1f0f
commit 91263c912f
+15 -1
View File
@@ -99,6 +99,7 @@ pub fn import(bytes: &[u8]) -> Result<Imported, ImportError> {
let chars: Vec<char> = text.chars().collect();
// Paragraphs: (style, runs of (text, format)).
let mut paras: Vec<(String, Vec<(String, CharFormat)>)> = vec![(String::new(), Vec::new())];
let mut started = false;
let mut fmt = CharFormat::default();
let mut para_styles: Vec<String> = Vec::new();
let mut char_styles: Vec<String> = Vec::new();
@@ -151,6 +152,7 @@ pub fn import(bytes: &[u8]) -> Result<Imported, ImportError> {
}
}
"ParaStyle" => {
started = true;
let v = value.trim().to_string();
if !v.is_empty() && !para_styles.contains(&v) {
para_styles.push(v.clone());
@@ -187,7 +189,7 @@ pub fn import(bytes: &[u8]) -> Result<Imported, ImportError> {
}
let style = paras.last().map(|p| p.0.clone()).unwrap_or_default();
// Header lines before any text don't start paragraphs.
if paras.len() == 1 && paras[0].1.is_empty() {
if !started && paras.len() == 1 && paras.first().is_some_and(|p| p.1.is_empty()) {
i += 1;
continue;
}
@@ -243,6 +245,18 @@ mod tests {
assert_eq!(import("<ASCII-WIN>\r\n<ParaStyle:Body>A<0xD83D>B<0xDE00>C".as_bytes()).unwrap().story.text, "ABC");
}
#[test]
fn tagged_text_keeps_a_leading_empty_paragraph() {
let doc = Document::new(&designcraft_doc::build::NewDocument::default());
let mut story = Story::new(StoryId(0));
story.insert(0, "\nText");
story.paras[0].style = "Head".into();
story.paras[1].style = "Body".into();
let back = import(tagged_text(&doc, &story).as_bytes()).unwrap();
assert_eq!(back.story.text, story.text);
assert_eq!(back.story.paras, story.paras);
}
#[test]
fn tagged_text_round_trips() {
let src = "<ASCII-WIN>\r\n<Version:7>\r\n<ParaStyle:Head>Caf<0x00E9> \\<1\\>\r\n<ParaStyle:Body>A <CharStyle:Em>word<CharStyle:> and <cSize:18.000000>big<cSize:> text";