//! Parse markdown text. //! //! Extended from cursive::utils::markup::markdown to add code styles //! TODO: Bring in the full power of termimad (e.g. md tables) in a View; //! implementation of those features (.e.g automatic wrapping within each table //! cell) might be easier in this setting anyway. // TODO use ColorStyle::secondary() etc. over specific enums use cursive::theme::{Effect, PaletteColor, Style}; use cursive::utils::markup::{StyledIndexedSpan, StyledString}; use cursive::utils::span::{IndexedCow, IndexedSpan}; use pulldown_cmark::{self, CowStr, Event, Options, Tag}; pub type Markdown = StyledString; /// Parses the given string as markdown text. /// **Note**: Assumes preprocessing has taken place pub fn parse(input: S) -> StyledString where S: Into, { let input = input.into(); let spans = parse_spans(&input); //let output = build_output(&spans); StyledString::with_spans(input, spans) } pub fn preprocess(input: String) -> String { input .as_str() .trim() .replace("", "**[") .replace("", "]**") } /// Preview markdown of the given length /// **Note**: Assumes preprocessing has taken place pub fn preview(width: usize, input: &StyledString) -> StyledString { let mut w = 0; let mut new_spans = Vec::new(); for span in input.spans_raw() { // Filter newlines if span.width == 0 { w += 1; new_spans.push(IndexedSpan { content: IndexedCow::Owned(" ".to_owned()), width: 1, ..*span }); } else { w += span.width; new_spans.push(span.clone()); } if w > width { break; } } let mut prev = StyledString::with_spans(input.source(), new_spans); prev.append_plain("..."); prev } /// Parse the given markdown text into a list of spans. /// This is a shortcut for `Parser::new(preprocessed_input).collect()`. fn parse_spans(input: &str) -> Vec { Parser::new(input).collect() } /// Cheat my way through cursive's obscure crap //fn build_output(spans: Vec) -> String { //spans.iter().fold("", |mut o, s| { //o += s.content.to_string(); //}) //} /// Iterator that parse a markdown text and outputs styled spans. pub struct Parser<'a> { first: bool, item: Option, in_list: bool, after_code_block: bool, stack: Vec