use std::path::PathBuf;
use super::heading_analyzer::HeadingConfig;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum TableFallback {
#[default]
Markdown,
Html,
Ascii,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum CleanupPreset {
Minimal,
#[default]
Default,
Aggressive,
}
#[derive(Debug, Clone, Default)]
pub struct CleanupOptions {
pub normalize_strings: bool,
pub clean_lines: bool,
pub filter_structure: bool,
pub final_normalize: bool,
pub remove_pua: bool,
pub detect_mojibake: bool,
pub preserve_frontmatter: bool,
}
impl CleanupOptions {
pub fn from_preset(preset: CleanupPreset) -> Self {
match preset {
CleanupPreset::Minimal => Self {
normalize_strings: true,
final_normalize: true,
..Default::default()
},
CleanupPreset::Default => Self {
normalize_strings: true,
clean_lines: true,
final_normalize: true,
preserve_frontmatter: true,
..Default::default()
},
CleanupPreset::Aggressive => Self {
normalize_strings: true,
clean_lines: true,
filter_structure: true,
final_normalize: true,
remove_pua: true,
detect_mojibake: true,
preserve_frontmatter: true,
},
}
}
pub fn minimal() -> Self {
Self::from_preset(CleanupPreset::Minimal)
}
pub fn standard() -> Self {
Self::from_preset(CleanupPreset::Default)
}
pub fn aggressive() -> Self {
Self::from_preset(CleanupPreset::Aggressive)
}
}
#[derive(Debug, Clone)]
pub struct RenderOptions {
pub image_dir: Option<PathBuf>,
pub image_path_prefix: String,
pub table_fallback: TableFallback,
pub max_heading_level: u8,
pub include_frontmatter: bool,
pub preserve_line_breaks: bool,
pub include_empty_paragraphs: bool,
pub list_marker: char,
pub use_atx_headers: bool,
pub paragraph_spacing: bool,
pub escape_special_chars: bool,
pub cleanup: Option<CleanupOptions>,
pub heading_config: Option<HeadingConfig>,
pub revision_handling: RevisionHandling,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum RevisionHandling {
#[default]
AcceptAll,
RejectAll,
ShowMarkup,
}
impl Default for RenderOptions {
fn default() -> Self {
Self {
image_dir: None,
image_path_prefix: String::new(),
table_fallback: TableFallback::Markdown,
max_heading_level: 4,
include_frontmatter: false,
preserve_line_breaks: false,
include_empty_paragraphs: false,
list_marker: '-',
use_atx_headers: true,
paragraph_spacing: true,
escape_special_chars: true,
cleanup: None,
heading_config: None,
revision_handling: RevisionHandling::AcceptAll,
}
}
}
impl RenderOptions {
pub fn new() -> Self {
Self::default()
}
pub fn with_image_dir(mut self, dir: impl Into<PathBuf>) -> Self {
self.image_dir = Some(dir.into());
self
}
pub fn with_image_prefix(mut self, prefix: impl Into<String>) -> Self {
self.image_path_prefix = prefix.into();
self
}
pub fn with_table_fallback(mut self, fallback: TableFallback) -> Self {
self.table_fallback = fallback;
self
}
pub fn with_frontmatter(mut self, include: bool) -> Self {
self.include_frontmatter = include;
self
}
pub fn with_cleanup(mut self) -> Self {
self.cleanup = Some(CleanupOptions::standard());
self
}
pub fn with_cleanup_preset(mut self, preset: CleanupPreset) -> Self {
self.cleanup = Some(CleanupOptions::from_preset(preset));
self
}
pub fn with_cleanup_options(mut self, options: CleanupOptions) -> Self {
self.cleanup = Some(options);
self
}
pub fn with_max_heading(mut self, level: u8) -> Self {
self.max_heading_level = level.clamp(1, 6);
self
}
pub fn with_preserve_breaks(mut self, preserve: bool) -> Self {
self.preserve_line_breaks = preserve;
self
}
pub fn with_heading_analysis(mut self) -> Self {
self.heading_config = Some(HeadingConfig::default());
self
}
pub fn with_heading_config(mut self, config: HeadingConfig) -> Self {
self.heading_config = Some(config);
self
}
pub fn with_revision_handling(mut self, handling: RevisionHandling) -> Self {
self.revision_handling = handling;
self
}
pub fn with_show_revisions(mut self) -> Self {
self.revision_handling = RevisionHandling::ShowMarkup;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_options() {
let opts = RenderOptions::default();
assert!(opts.image_dir.is_none());
assert!(!opts.include_frontmatter);
assert_eq!(opts.table_fallback, TableFallback::Markdown);
assert_eq!(opts.max_heading_level, 4);
}
#[test]
fn test_builder_pattern() {
let opts = RenderOptions::new()
.with_image_dir("assets")
.with_frontmatter(true)
.with_cleanup();
assert_eq!(opts.image_dir, Some(PathBuf::from("assets")));
assert!(opts.include_frontmatter);
assert!(opts.cleanup.is_some());
}
#[test]
fn test_cleanup_presets() {
let minimal = CleanupOptions::minimal();
assert!(minimal.normalize_strings);
assert!(!minimal.clean_lines);
let aggressive = CleanupOptions::aggressive();
assert!(aggressive.normalize_strings);
assert!(aggressive.clean_lines);
assert!(aggressive.filter_structure);
assert!(aggressive.remove_pua);
}
#[test]
fn test_max_heading_clamp() {
let opts = RenderOptions::new().with_max_heading(10);
assert_eq!(opts.max_heading_level, 6);
let opts = RenderOptions::new().with_max_heading(0);
assert_eq!(opts.max_heading_level, 1);
}
}