//! 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. // Figure out why the hell cursive needs to keep around the input string? // 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}; use std::borrow::Cow; use unicode_width::UnicodeWidthStr; use super::entities::is_entity; /// Parses the given string as markdown text. pub fn parse(input: S) -> StyledString where S: Into, { let input = preprocess(input.into()); let spans = parse_spans(&input); //let output = build_output(&spans); StyledString::with_spans(input, spans) } /// Preview markdown. Largely heuristic. pub fn preview(size: usize, input: S) -> StyledString where S: Into, { // DO the initial parsing here too, not just in `parse` let generous_size = (size as f32) * 1.2; let generous_size = generous_size.ceil(); let generous_size = generous_size as usize; let mut input = input.into(); input.truncate(generous_size); let input = preprocess(input); let spans = parse_spans(&input) .into_iter() // Filter out newlines .map(|ix_span| match ix_span { IndexedSpan { width: 0, .. } => IndexedSpan { content: IndexedCow::Owned(" ".to_owned()), width: 1, ..ix_span }, is => is, }) .collect(); let mut prev = StyledString::with_spans(input, spans); prev.append_plain("..."); prev } fn preprocess(input: String) -> String { // TODO handle other stackexchange oddities here ENTITIES // TODO then benchmark input .as_str() .trim() .replace("", "**[") .replace("", "]**") } /// Parse the given markdown text into a list of spans. /// Assumes preprocessing has taken place /// 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