Strip comments and header metadata on ODT export
Each file is now cleaned before conversion: HTML comments are removed and everything above the configurable Draft marker (default "### Rough Draft:") is dropped. A "# Title:" line becomes the chapter heading and a "# Slug:" line becomes an italic caption beneath it. - new preprocess module (strip_comments + header parse) with tests - Chapter gains a slug rendered via a Chapter_20_Caption style, italic at both paragraph-style and character-run level - draft_marker config setting + top-bar field - export title priority: override > # Title: > first # heading > filename Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+22
@@ -19,6 +19,8 @@ use zip::write::SimpleFileOptions;
|
||||
/// One chapter to export.
|
||||
pub struct Chapter {
|
||||
pub title: String,
|
||||
/// Optional caption shown beneath the chapter title (from the `# Slug:` line).
|
||||
pub slug: Option<String>,
|
||||
pub markdown: String,
|
||||
}
|
||||
|
||||
@@ -387,6 +389,10 @@ fn styles_xml() -> String {
|
||||
<style:text-properties fo:font-size="14pt" fo:font-weight="bold"/>
|
||||
</style:style>
|
||||
{headings}
|
||||
<style:style style:name="Chapter_20_Caption" style:display-name="Chapter Caption" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.2in"/>
|
||||
<style:text-properties fo:font-style="italic" fo:font-size="12pt" fo:color="#666666"/>
|
||||
</style:style>
|
||||
<style:style style:name="Quotations" style:family="paragraph" style:parent-style-name="Standard" style:class="html">
|
||||
<style:paragraph-properties fo:margin-left="0.4in" fo:margin-right="0.4in" fo:margin-top="0.05in" fo:margin-bottom="0.05in"/>
|
||||
<style:text-properties fo:font-style="italic"/>
|
||||
@@ -448,6 +454,15 @@ fn content_xml(chapters: &[Chapter]) -> String {
|
||||
"<text:h text:style-name=\"Heading_20_1\" text:outline-level=\"1\">{}</text:h>",
|
||||
esc(&chapter.title)
|
||||
));
|
||||
if let Some(slug) = chapter.slug.as_deref().map(str::trim).filter(|s| !s.is_empty()) {
|
||||
// Italic at both the paragraph-style and character-run level so the
|
||||
// caption stays italic regardless of how a reader applies styles.
|
||||
body.push_str(&format!(
|
||||
"<text:p text:style-name=\"Chapter_20_Caption\">\
|
||||
<text:span text:style-name=\"T_italic\">{}</text:span></text:p>",
|
||||
esc(slug)
|
||||
));
|
||||
}
|
||||
body.push_str(&markdown_to_body(&chapter.markdown, 1));
|
||||
}
|
||||
|
||||
@@ -549,10 +564,12 @@ Done.";
|
||||
let chapters = vec![
|
||||
Chapter {
|
||||
title: "Chapter One".to_string(),
|
||||
slug: Some("the opening".to_string()),
|
||||
markdown: "Hello **world**.\n\n## Scene\n\nText.".to_string(),
|
||||
},
|
||||
Chapter {
|
||||
title: "Chapter Two".to_string(),
|
||||
slug: None,
|
||||
markdown: "- a\n- b\n".to_string(),
|
||||
},
|
||||
];
|
||||
@@ -576,5 +593,10 @@ Done.";
|
||||
.unwrap();
|
||||
assert!(content.contains(">Chapter One</text:h>"));
|
||||
assert!(content.contains(">Chapter Two</text:h>"));
|
||||
// The slug renders as an italic caption paragraph under the first chapter.
|
||||
assert!(content.contains(
|
||||
"<text:p text:style-name=\"Chapter_20_Caption\">\
|
||||
<text:span text:style-name=\"T_italic\">the opening</text:span></text:p>"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user