use crate::config::Config;
use crate::diagnostics::Diagnostics;
use crate::error::{Error, Result};
use crate::formatters;
use crate::preprocessor;
pub fn format(content: &str, config: &Config) -> Result<(String, Diagnostics)> {
let (protected_content, code_blocks) = formatters::extract_code_blocks_early(content);
let (preprocessed, diagnostics) = preprocessor::preprocess(&protected_content);
let events = parse_markdown(&preprocessed);
let formatted = apply_formatters(&events, config)?;
let final_content = formatters::restore_code_blocks_early(&formatted, &code_blocks, config);
Ok((final_content, diagnostics))
}
fn parse_markdown(content: &str) -> Vec<pulldown_cmark::Event<'_>> {
use pulldown_cmark::{Options, Parser};
let mut options = Options::empty();
options.insert(Options::ENABLE_TABLES);
options.insert(Options::ENABLE_FOOTNOTES);
options.insert(Options::ENABLE_STRIKETHROUGH);
options.insert(Options::ENABLE_TASKLISTS);
options.insert(Options::ENABLE_HEADING_ATTRIBUTES);
let parser = Parser::new_ext(content, options);
parser.collect()
}
fn apply_formatters(events: &[pulldown_cmark::Event<'_>], config: &Config) -> Result<String> {
use pulldown_cmark_to_cmark::cmark;
let mut buf = String::new();
cmark(events.iter(), &mut buf)
.map_err(|e| Error::FormattingError(format!("Failed to format markdown: {e}")))?;
let formatted = formatters::apply_all(&buf, config);
Ok(formatted)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_formatting() {
let input = "# Hello\n\nWorld";
let config = Config::default();
let result = format(input, &config);
assert!(result.is_ok());
}
#[test]
fn test_parse_markdown() {
let input = "# Heading\n\nParagraph";
let events = parse_markdown(input);
assert!(!events.is_empty());
}
}