diff options
Diffstat (limited to 'src/typeset.rs')
-rw-r--r-- | src/typeset.rs | 229 |
1 files changed, 0 insertions, 229 deletions
diff --git a/src/typeset.rs b/src/typeset.rs deleted file mode 100644 index 9522e69..0000000 --- a/src/typeset.rs +++ /dev/null @@ -1,229 +0,0 @@ -use crate::parser::parse_scenario_snippet; -use crate::Bindings; -use crate::PartialStep; -use crate::ScenarioStep; -use crate::StepKind; -use crate::SubplotError; -use crate::{DiagramMarkup, DotMarkup, PikchrMarkup, PlantumlMarkup}; -use crate::{Warning, Warnings}; - -use pandoc_ast::Attr; -use pandoc_ast::Block; -use pandoc_ast::Inline; -use pandoc_ast::Target; - -/// Typeset an error as a Pandoc AST Block element. -pub fn error(err: SubplotError) -> Block { - let msg = format!("ERROR: {}", err); - Block::Para(error_msg(&msg)) -} - -/// Typeset an error message a vector of inlines. -pub fn error_msg(msg: &str) -> Vec<Inline> { - vec![Inline::Strong(vec![inlinestr(msg)])] -} - -/// Typeset a string as an inline element. -pub fn inlinestr(s: &str) -> Inline { - Inline::Str(String::from(s)) -} - -/// Typeset a code block tagged as a file. -pub fn file_block(attr: &Attr, text: &str) -> Block { - let filename = inlinestr(&attr.0); - let filename = Inline::Strong(vec![filename]); - let intro = Block::Para(vec![inlinestr("File:"), space(), filename]); - let mut cbattrs = attr.clone(); - if cbattrs.1.iter().any(|s| s == "noNumberLines") { - // If the block says "noNumberLines" we remove that class - cbattrs.1.retain(|s| s != "noNumberLines"); - } else if cbattrs.1.iter().all(|s| s != "numberLines") { - // Otherwise if it doesn't say numberLines we add that in. - cbattrs.1.push("numberLines".to_string()); - } - // If this was an `example`, convert that class to `file` - if cbattrs.1.iter().any(|s| s == "example") { - cbattrs.1.retain(|s| s != "example"); - cbattrs.1.push("file".into()); - } - let codeblock = Block::CodeBlock(cbattrs, text.to_string()); - let noattr = ("".to_string(), vec![], vec![]); - Block::Div(noattr, vec![intro, codeblock]) -} - -/// Typeset a scenario snippet as a Pandoc AST Block. -/// -/// Typesetting here means producing the Pandoc abstract syntax tree -/// nodes that result in the desired output, when Pandoc processes -/// them. -/// -/// The snippet is given as a text string, which is parsed. It need -/// not be a complete scenario, but it should consist of complete steps. -pub fn scenario_snippet(bindings: &Bindings, snippet: &str, warnings: &mut Warnings) -> Block { - let lines = parse_scenario_snippet(snippet); - let mut steps = vec![]; - let mut prevkind: Option<StepKind> = None; - - for line in lines { - let (this, thiskind) = step(bindings, line, prevkind, warnings); - steps.push(this); - prevkind = thiskind; - } - Block::LineBlock(steps) -} - -// Typeset a single scenario step as a sequence of Pandoc AST Inlines. -fn step( - bindings: &Bindings, - text: &str, - prevkind: Option<StepKind>, - warnings: &mut Warnings, -) -> (Vec<Inline>, Option<StepKind>) { - let step = ScenarioStep::new_from_str(text, prevkind); - if step.is_err() { - return ( - error_msg(&format!("Could not parse step: {}", text)), - prevkind, - ); - } - let step = step.unwrap(); - - let m = match bindings.find("", &step) { - Ok(m) => m, - Err(e) => { - let w = Warning::UnknownBinding(format!("{}", e)); - warnings.push(w.clone()); - return (error_msg(&format!("{}", w)), prevkind); - } - }; - - let mut inlines = vec![keyword(&step, prevkind), space()]; - - for part in m.parts() { - match part { - PartialStep::UncapturedText(s) => inlines.push(uncaptured(s.text())), - PartialStep::CapturedText { text, .. } => inlines.push(captured(text)), - } - } - - (inlines, Some(step.kind())) -} - -// Typeset first word, which is assumed to be a keyword, of a scenario -// step. -fn keyword(step: &ScenarioStep, prevkind: Option<StepKind>) -> Inline { - let actual = inlinestr(&format!("{}", step.kind())); - let and = inlinestr("and"); - let keyword = if let Some(prevkind) = prevkind { - if prevkind == step.kind() { - and - } else { - actual - } - } else { - actual - }; - Inline::Emph(vec![keyword]) -} - -// Typeset a space between words. -fn space() -> Inline { - Inline::Space -} - -// Typeset an uncaptured part of a step. -fn uncaptured(s: &str) -> Inline { - inlinestr(s) -} - -// Typeset a captured part of a step. -fn captured(s: &str) -> Inline { - Inline::Strong(vec![inlinestr(s)]) -} - -/// Typeset a link as a note. -pub fn link_as_note(attr: Attr, text: Vec<Inline>, target: Target) -> Inline { - let (url, _) = target.clone(); - let url = Inline::Code(attr.clone(), url); - let link = Inline::Link(attr.clone(), vec![url], target); - let note = Inline::Note(vec![Block::Para(vec![link])]); - let mut text = text; - text.push(note); - Inline::Span(attr, text) -} - -/// Take a pikchr diagram, render it as SVG, and return an AST block element. -/// -/// The `Block` will contain the SVG data. This allows the diagram to -/// be rendered without referencing external entities. -/// -/// If the code block which contained the pikchr contains other classes, they -/// can be added to the SVG for use in later typesetting etc. -pub fn pikchr_to_block(pikchr: &str, class: Option<&str>, warnings: &mut Warnings) -> Block { - match PikchrMarkup::new(pikchr, class).as_svg() { - Ok(svg) => typeset_svg(svg), - Err(err) => { - warnings.push(Warning::Pikchr(format!("{}", err))); - error(err) - } - } -} - -// Take a dot diagram, render it as SVG, and return an AST Block -// element. The Block will contain the SVG data. This allows the -// diagram to be rendered without referending external entities. -pub fn dot_to_block(dot: &str, warnings: &mut Warnings) -> Block { - match DotMarkup::new(dot).as_svg() { - Ok(svg) => typeset_svg(svg), - Err(err) => { - warnings.push(Warning::Dot(format!("{}", err))); - error(err) - } - } -} - -// Take a PlantUML diagram, render it as SVG, and return an AST Block -// element. The Block will contain the SVG data. This allows the -// diagram to be rendered without referending external entities. -pub fn plantuml_to_block(markup: &str, warnings: &mut Warnings) -> Block { - match PlantumlMarkup::new(markup).as_svg() { - Ok(svg) => typeset_svg(svg), - Err(err) => { - warnings.push(Warning::Plantuml(format!("{}", err))); - error(err) - } - } -} - -/// Typeset a project roadmap expressed as textual YAML, and render it -/// as an SVG image. -pub fn roadmap_to_block(yaml: &str, warnings: &mut Warnings) -> Block { - match roadmap::from_yaml(yaml) { - Ok(ref mut roadmap) => { - roadmap.set_missing_statuses(); - let width = 50; - match roadmap.format_as_dot(width) { - Ok(dot) => dot_to_block(&dot, warnings), - Err(e) => Block::Para(vec![inlinestr(&e.to_string())]), - } - } - Err(e) => Block::Para(vec![inlinestr(&e.to_string())]), - } -} - -// Typeset an SVG, represented as a byte vector, as a Pandoc AST Block -// element. -fn typeset_svg(svg: Vec<u8>) -> Block { - let url = svg_as_data_url(svg); - let attr = ("".to_string(), vec![], vec![]); - let img = Inline::Image(attr, vec![], (url, "".to_string())); - Block::Para(vec![img]) -} - -// Convert an SVG, represented as a byte vector, into a data: URL, -// which can be inlined so the image can be rendered without -// referencing external files. -fn svg_as_data_url(svg: Vec<u8>) -> String { - let svg = base64::encode(&svg); - format!("data:image/svg+xml;base64,{}", svg) -} |