hmd 0.4.13

Custom Markdown Engine for my personal blog.
Documentation
use crate::consts::*;
use crate::utils::*;
use crate::markdown::predicates::get_type;
use crate::markdown;


#[derive(Clone, Debug, PartialEq)]
pub enum LineType {
    Paragraph,
    Header,
    ThematicBreak,
    CodeFence,
    TableDelimiter,
    FencedCode,
    RenderedTable,
    Blockquote(usize),
    UnorderedList,
    Tag,
    Toc,
    OrderedList,
    Empty
}


#[derive(Clone)]
pub struct Line {
    pub content: Vec<u16>,
    pub indent: usize,
    pub line_type: LineType
}


impl Line {

    pub fn from_raw(raw: &Vec<u16>) -> Line {

        let mut indent = 0;
        let mut index = 0;

        while index < raw.len() {

            if raw[index] == U16_SPACE {
                indent += 1;
            }

            else if raw[index] == U16_TAB {
                indent += 4;
            }

            else {
                break;
            }

            index += 1;
        }

        Line {
            content: raw[index..].to_vec(),
            indent,
            line_type: LineType::Paragraph
        }
    }

    pub fn into_raw(&self) -> Vec<u16> {

        vec![vec![U16_SPACE;self.indent], self.content.clone()].concat()
    }

    pub fn render(&self) -> Vec<u16> {

        match self.line_type {
            LineType::Paragraph => self.render_paragraph(),
            LineType::Header => self.render_header(),
            LineType::ThematicBreak => vec![U16_LESS_THAN, U16_SMALL_H, U16_SMALL_R, U16_SPACE, U16_SLASH, U16_GREATER_THAN],
            LineType::Empty => vec![],
            LineType::FencedCode => self.render_fenced_code(),
            LineType::Blockquote(_) => self.render_as_it_is(),
            LineType::OrderedList => self.render_as_it_is(),
            LineType::Tag => self.render_as_it_is(),
            LineType::Toc => self.render_toc(),
            LineType::UnorderedList => self.render_as_it_is(),
            LineType::RenderedTable => self.render_as_it_is(),
            _ => panic!("{:?}", self.line_type)
        }

    }

    fn render_toc(&self) -> Vec<u16> {
        markdown::render(&String::from_utf16_lossy(&self.content)).unwrap().encode_utf16().collect()
    }

    fn render_paragraph(&self) -> Vec<u16> {

        vec![
            into_v16("<p>"),
            self.content.clone(),
            into_v16("</p>")
        ].concat()
    }

    fn render_as_it_is(&self) -> Vec<u16> {
        self.content.clone()
    }

    fn render_header(&self) -> Vec<u16> {

        let (sharps, sharps_removed) = take_and_drop_while(&self.content, U16_SHARP);
        let indents_removed = drop_while(&sharps_removed, U16_SPACE);

        vec![
            into_v16(&format!("<h{} id=\"", sharps.len())),
            remove_special_characters(&indents_removed),
            into_v16("\">"),
            indents_removed,
            into_v16(&format!("</h{}>", sharps.len()))
        ].concat()
    }

    fn render_fenced_code(&self) -> Vec<u16> {

        vec![
            into_v16("<pre><code>"),
            self.content.clone(),
            into_v16("</code></pre>")
        ].concat()
    }

}


pub fn code_to_lines(code: &Vec<u16>) -> Vec<Line> {

    code.split(
        |c|
        *c == U16_NEWLINE
    ).map(
        |ln| {
            let mut untyped = Line::from_raw(&ln.to_vec());

            let line_type = get_type(&untyped);
            untyped.line_type = line_type;

            untyped
        }
    ).collect::<Vec<Line>>()
}


pub fn render_lines(lines: &Vec<Line>) -> Vec<u16> {

    let mut result = Vec::with_capacity(lines.len() * 2);

    for ln in lines.iter() {
        result.push(ln.render());
        result.push(vec![U16_NEWLINE]);
    }

    result.concat()
}