+pub fn parse(source: &str) -> String {
+
+ let lines = source.split("\n");
+ let mut is_preformatted = false;
+
+ let mut html:String = "".to_owned();
+ let mut current_line_type: Option<LineType> = None;
+
+ for line in lines {
+ let line_type = identify_line(&(line[..3]), is_preformatted);
+ match line_type {
+ LineType::PreformattedToggle => is_preformatted = !is_preformatted,
+ _ => {
+ // Close previous block if needed
+ if let Some(line) = ¤t_line_type {
+ if line != &line_type && is_block(line) {
+ html.push_str(get_line_closer(line));
+ }
+ }
+
+ // Blocks
+ if is_block(&line_type) {
+ if let Some(line) = ¤t_line_type {
+ if line != &line_type {
+ html.push_str(get_line_opener(&line_type));
+ }
+ } else {
+ html.push_str(get_line_opener(&line_type));
+ }
+
+ let line_content = get_partial_line_content(&line_type, line);
+ html.push_str(&line_content);
+ } else {
+ let line_content = get_full_line_content(&line_type, line);
+ html.push_str(&line_content);
+ }
+ current_line_type = Some(line_type);
+ },
+ }
+ }
+ if let Some(line) = ¤t_line_type {
+ if is_block(line) {
+ html.push_str(get_line_closer(line));
+ }
+ }
+ html
+}
+
+fn is_block(line_type: &LineType) -> bool {
+ return match line_type {
+ LineType::PreformattedText => true,
+ LineType::ListItem => true,
+ LineType::Quote => true,
+ _ => false,
+ }
+}
+
+fn get_partial_line_content(line_type: &LineType, line: &str) -> String {
+ return match line_type {
+ LineType::ListItem => format!("<li>{}</li>", line[2..].trim()),
+ LineType::Quote => line[1..].trim().to_string(),
+ LineType::PreformattedText => format!("{}\n", line),
+ _ => "".to_string(),
+ }
+}
+
+fn get_full_line_content(line_type: &LineType, line: &str) -> String {
+ match line_type {
+ LineType::Text => format!("<p>{}</p>\n", line.trim()),
+ LineType::Blank => "<br/>\n".to_string(),
+ LineType::Link => format!("<div><a href=\"{}\">{}</a></div>\n", get_link_address(line), get_link_content(line)),
+ LineType::Heading1 => format!("<h1>{}</h1>\n", line[1..].trim()),
+ LineType::Heading2 => format!("<h2>{}</h2>\n", line[2..].trim()),
+ LineType::Heading3 => format!("<h3>{}</h3>\n", line[3..].trim()),
+ _ => "".to_string(),
+ }
+}
+
+fn get_line_opener(line_type: &LineType) -> &'static str {
+ match line_type {
+ LineType::ListItem => "<ul>",
+ LineType::Quote => "<blockquote>",
+ LineType::PreformattedText => "<pre>",
+ _ => "",
+ }
+}
+
+fn get_line_closer(line_type: &LineType) -> &'static str {
+ match line_type {
+ LineType::ListItem => "</ul>\n",
+ LineType::Quote => "</blockquote>\n",
+ LineType::PreformattedText => "</pre>\n",
+ _ => "",
+ }
+}
+
+fn get_link_content(line: &str) -> &str {
+ let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect();
+ if components.len() > 1 {
+ return components[1].trim()
+ }
+ components[0].trim()
+}
+
+fn get_link_address(line: &str) -> &str {
+ let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect();
+ components[0].trim()
+}
+
+fn identify_line(line: &str, is_preformatted: bool) -> LineType {
+ if line.starts_with("```") {
+ return LineType::PreformattedToggle;
+ }
+ if is_preformatted {
+ return LineType::PreformattedText;
+ }
+ if line.is_empty() {
+ return LineType::Blank;
+ }
+ if line.starts_with("=>") {
+ return LineType::Link;
+ }
+ if line.starts_with("* ") {
+ return LineType::ListItem;
+ }
+ if line.starts_with(">") {
+ return LineType::Quote;
+ }
+ if line.starts_with("###") {
+ return LineType::Heading3;
+ }
+ if line.starts_with("##") {
+ return LineType::Heading2;
+ }
+ if line.starts_with("#") {
+ return LineType::Heading1;
+ }
+
+ LineType::Text
+}
+
+#[derive(PartialEq, Eq)]
+enum LineType {
+ Text,
+ Blank,
+ Link,
+ PreformattedToggle,
+ PreformattedText,
+ Heading1,
+ Heading2,
+ Heading3,
+ ListItem,
+ Quote
+}