let mut html:String = "".to_owned();
let mut current_line_type: Option<LineType> = None;
+ let mut heading_stack: Vec<u8> = Vec::new();
for line in lines {
- let mut line_type = LineType::Text;
+ let mut line_type = LineType::Blank;
if line.char_indices().count() > 2 {
let mut end = line.len();
if line.char_indices().count() > 3 {
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);
+ html.push_str(&get_heading_wrapper(&mut heading_stack, &line_type));
+ html.push_str(&get_full_line_content(&line_type, line));
}
current_line_type = Some(line_type);
},
html.push_str(get_line_closer(line));
}
}
+ html.push_str(&close_heading_wrapper(&mut heading_stack));
html
}
fn is_block(line_type: &LineType) -> bool {
return match line_type {
- LineType::PreformattedText => true,
- LineType::ListItem => true,
- LineType::Quote => true,
+ LineType::PreformattedText | LineType::ListItem | LineType::Quote => true,
_ => false,
}
}
fn get_partial_line_content(line_type: &LineType, line: &str) -> String {
+ let encoded_line = line.replace("<", "<").replace(">", ">");
return match line_type {
- LineType::ListItem => format!("<li>{}</li>", line[2..].trim()),
- LineType::Quote => line[1..].trim().to_string(),
- LineType::PreformattedText => format!("{}\n", line),
+ LineType::ListItem => format!("<li>{}</li>", encoded_line[2..].trim()),
+ LineType::Quote => encoded_line[1..].trim().to_string(),
+ LineType::PreformattedText => format!("{}\n", encoded_line),
_ => "".to_string(),
}
}
fn get_full_line_content(line_type: &LineType, line: &str) -> String {
+ let encoded_line = line.replace("<", "<").replace(">", ">");
match line_type {
- LineType::Text => format!("<p>{}</p>\n", line.trim()),
+ LineType::Text => format!("<p>{}</p>\n", encoded_line.trim()),
LineType::Blank => "<br/>\n".to_string(),
LineType::Link => {
let url = get_link_address(line);
format!("<div><a href=\"{}\">{}</a></div>\n", url.replace(".gmi", ".html"), 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()),
+ LineType::Heading1 => format!("<h1>{}</h1>\n", encoded_line[1..].trim()),
+ LineType::Heading2 => format!("<h2>{}</h2>\n", encoded_line[2..].trim()),
+ LineType::Heading3 => format!("<h3>{}</h3>\n", encoded_line[3..].trim()),
_ => "".to_string(),
}
}
+fn get_heading_wrapper(heading_stack: &mut Vec<u8>, line_type: &LineType) -> String {
+ let mut string = String::new();
+ let current_heading: u8 = match line_type {
+ LineType::Heading1 => 1,
+ LineType::Heading2 => 2,
+ LineType::Heading3 => 3,
+ _ => 255
+ };
+
+ if current_heading < 255 {
+ while let Some(open_heading) = heading_stack.pop() {
+ // You just encountered a more important heading.
+ // Put it back. Desist.
+ if open_heading < current_heading {
+ heading_stack.push(open_heading);
+ break;
+ }
+
+ string.push_str("</div>");
+
+ if open_heading == current_heading {
+ break;
+ }
+ }
+ heading_stack.push(current_heading);
+ string.push_str(&format!("<div class=\"h{}\">", current_heading));
+ }
+
+ return string;
+}
+
+fn close_heading_wrapper(heading_stack: &mut Vec<u8>) -> String {
+ let mut string = String::new();
+ while let Some(_open_heading) = heading_stack.pop() {
+ string.push_str("</div>");
+ }
+ return string;
+}
+
fn get_line_opener(line_type: &LineType) -> &'static str {
match line_type {
LineType::ListItem => "<ul>",