pub mod code_handler;
#[cfg(feature = "plotly-html-handler")]
pub mod plotly_html_handler;
#[cfg(feature = "plotly-svg-handler")]
pub mod plotly_svg_handler;
use crate::preprocessor::config::{PlotlyOutputType, PreprocessorConfig};
use anyhow::Result;
use log::{error, warn};
use mdbook_preprocessor::book::Chapter;
use pulldown_cmark::{CodeBlockKind, Event, Parser, Tag, TagEnd};
use std::path::Path;
const PULLDOWN_CMARK_OPTIONS: pulldown_cmark::Options = pulldown_cmark::Options::all();
pub fn handle(chapter: &mut Chapter, config: &PreprocessorConfig, book_path: &Path) {
let events = Parser::new_ext(&chapter.content, PULLDOWN_CMARK_OPTIONS);
let mut code = String::with_capacity(10);
let mut in_target_code = false;
let mut new_events = Vec::with_capacity(10);
let mut code_sequence = 0;
if config.output_type == PlotlyOutputType::PlotlyHtml {
new_events.push(plotly_html_handler::inject_header(
config.offline_js_sources,
));
new_events.push(Event::HardBreak);
}
for event in events {
match event {
Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(ref lang))) => {
if matches!(lang.as_ref(), "plotly" | "plot") {
in_target_code = true;
code.clear();
} else {
new_events.push(event);
}
code_sequence += 1;
}
Event::Text(ref text) => {
if in_target_code {
code.push_str(text);
} else {
new_events.push(event);
}
}
Event::End(TagEnd::CodeBlock) => {
if !in_target_code {
new_events.push(event);
continue;
}
in_target_code = false;
let ready_code = std::mem::take(&mut code);
match handle_plotly(ready_code, config, book_path) {
Ok(event) => {
new_events.push(Event::HardBreak);
new_events.push(event);
new_events.push(Event::HardBreak);
}
Err(message) => warn!(
"An error occurred during processing in {} at sequence {}:\n{}",
chapter.name, code_sequence, message
),
}
}
_ => new_events.push(event),
}
}
let mut new_content = String::with_capacity(chapter.content.len());
if let Err(e) = pulldown_cmark_to_cmark::cmark_with_options(
new_events.into_iter(),
&mut new_content,
pulldown_cmark_to_cmark::Options::default(),
) {
error!(
"Processing failed during cmark. {} Chapter will use the original content. \nInterError: {:#?}",
chapter.name, e
);
} else {
chapter.content = new_content;
}
}
#[allow(unused)]
pub fn handle_plotly<'a>(
code: String,
config: &'a PreprocessorConfig,
book_path: &'a Path,
) -> Result<Event<'static>> {
let plot = code_handler::handle(code, &config.input_type)?;
let result = match config.output_type {
#[cfg(feature = "plotly-html-handler")]
PlotlyOutputType::PlotlyHtml => plotly_html_handler::handle(plot),
#[cfg(feature = "plotly-svg-handler")]
PlotlyOutputType::PlotlySvg => plotly_svg_handler::handle(plot, book_path),
};
Ok(result)
}