1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
extern crate regex;
#[macro_use] extern crate lazy_static;

use regex::{RegexBuilder, Regex, Captures};

fn reg(s: &str) -> Regex {
    RegexBuilder::new(s)
        .multi_line(true)
        .build()
        .unwrap()
}

//All of the Regexs
lazy_static!{
    static ref CODE_BLOCK: Regex = reg(r"```(\s*)([\s\S]*?)(\s*)```");

    static ref CODE_INLINE: Regex = reg(r"(`)(.*?)(`)");

    static ref LINK: Regex = reg(r"\[([^\[]+)\]\(([^\)]+)\)");

    static ref HEADING: Regex = reg(r"\n(#+\s*)(.*)");

    static ref EMPHASIS: Regex = reg(r"(\*{1,2})(.*?)(\*{1,2})");

    static ref STRIKETHROUGH: Regex = reg(r"(\~\~)(.*?)(\~\~)");

    static ref HORIZONTAL: Regex = reg(r"\n((\-{3,})|(={3,}))");

    static ref UNORDERED: Regex = reg(r"(\n\s*(\-|\+)\s.*)+");

    static ref ORDERED: Regex = reg(r"(\n\s*([0-9]+\.)\s.*)+");

    /* Markdown or HTML reserved symbols */
    static ref LT: Regex = reg(r"<");

    static ref GT: Regex = reg(r">");

    static ref AMP: Regex = reg(r"&");

    static ref AST: Regex = reg(r"\*");

    static ref UND: Regex = reg(r"_");

    static ref TIC: Regex = reg(r"`");

    static ref EQL: Regex = reg(r"=");

    static ref HYP: Regex = reg(r"-");

    static ref HASH: Regex = reg(r"#");
}

//function to replace HTML or Markdown reserved symbols
fn symbols(s: &str) -> String {
    HYP.replace_all(&EQL.replace_all(&TIC.replace_all(&UND.replace_all(&AST.replace_all(&LT.replace_all(&GT.replace_all(&HASH.replace_all(&AMP.replace_all(s, "&amp;"), "&#35;"), "&gt;"), "&lt;"), "&#42;"), "&#95;"), "&#96;"), "&#61;"), "&#45;").to_string()
}

/* The replacer functions */

fn code_block_replacer(cap: &Captures) -> String {
    format!("<pre>{}</pre>", symbols(&cap[2]))
}

fn code_inline_replacer(cap: &Captures) -> String {
    format!("<code>{}</code>", &cap[2])
}

fn link_replacer(cap: &Captures) -> String {
    format!("<a href='{}'>{}</a>", &cap[2], &cap[1])
}

fn heading_replacer(cap: &Captures) -> String {
    format!("\n<h{}>{}</h{}>", cap[1].len().to_string(), &cap[2], cap[1].len().to_string())
}

fn emphasis_replacer(cap: &Captures) -> String {
    format!("<{}>{}</{}>", if{cap[1].len()==1}{"em"}else{"strong"}, &cap[2], if{cap[1].len()==1}{"em"}else{"strong"})
}

fn rule_replacer(cap: &Captures) -> String {
    format!("\n<hr />")
}

fn unordered_replacer(cap: &Captures) -> String {
    let mut items = String::from("");
    for i in cap[0].trim().split('\n') {
        items = format!("{}<li>{}</li>", items, &i[2..]);
    }
    format!("<ul>{}</ul>", items)
}

fn ordered_replacer(cap: &Captures) -> String {
    let mut items = String::from("");
    for i in cap[0].trim().split('\n') {
        items = format!("{}<li>{}</li>", items, &i[i.find('.').unwrap()+2..]);
    }
    format!("<ol>{}</ol>", items)
}

//The main format function; call this to get markdown with the best results
pub fn replace_all(s: &String) -> String {
    replace::unordered(&replace::ordered(&replace::rules(&replace::emphasis(&replace::headings(&replace::links(&replace::code_inline(&replace::code_blocks(s))))))))
}

//Individual markdown replacement functions.
pub mod replace {
    use crate::*;

    pub fn code_blocks(s: &String) -> String {
        CODE_BLOCK.replace_all(s, &code_block_replacer).to_string()
    }

    pub fn code_inline(s: &String) -> String {
        CODE_INLINE.replace_all(s, &code_inline_replacer).to_string()
    }

    pub fn links(s: &String) -> String {
        LINK.replace_all(s, &link_replacer).to_string()
    }

    pub fn headings(s: &String) -> String {
        HEADING.replace_all(s, &heading_replacer).to_string()
    }

    pub fn emphasis(s: &String) -> String {
        EMPHASIS.replace_all(s, &emphasis_replacer).to_string()
    }

    pub fn rules(s: &String) -> String {
        HORIZONTAL.replace_all(s, &rule_replacer).to_string()
    }

    pub fn unordered(s: &String) -> String {
        UNORDERED.replace_all(s, &unordered_replacer).to_string()
    }

    pub fn ordered(s: &String) -> String {
        ORDERED.replace_all(s, &ordered_replacer).to_string()
    }
}