Last active
March 22, 2020 04:56
-
-
Save colbyhall/dac667f66bb6e61baa4b88c94ce7be29 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fs; | |
use std::io::prelude::*; | |
const EXTENSION: &str = "md"; | |
const HEADER: &str = | |
" | |
<!doctype htmls> | |
<html> | |
<head> | |
<meta chaset=\"utf8\"> | |
<title>Test 123</title> | |
<link rel=\"stylesheet\" href=\"blog.css\"> | |
</head> | |
<body> | |
"; | |
const FOOTER: &str = | |
" | |
</body> | |
</html> | |
"; | |
fn consume_and_count_char_repeated(line: &str, c: char) -> (usize, &str) { | |
let mut size = 0; | |
for it in line.chars() { | |
if it != c { | |
break; | |
} | |
size += it.len_utf8(); | |
} | |
(size, &line[size..]) | |
} | |
fn parse_and_output_header(out_file: &mut fs::File, line: &str) { | |
let orig = line; | |
let (num_header_tag, line) = consume_and_count_char_repeated(line, '#'); | |
if line.starts_with(' ') { | |
writeln!(out_file, "<h{}>{}</h{}>", num_header_tag, line.trim_start().trim_end(), num_header_tag).unwrap(); | |
} else { | |
output_line_as_p(out_file, orig); | |
} | |
} | |
fn parse_and_output_star<'a>(out_file: &mut fs::File, line: &'a str) -> &'a str { | |
let orig_line = line; | |
// @NOTE(CHall): count stars at beginning. if there are too many just print out the first and return a slice 1 char ahead | |
let (start_stars_count, line) = consume_and_count_char_repeated(line, '*'); | |
if start_stars_count > 3 { | |
write!(out_file, "*").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): try to find end stars. if we can't print out first star and return a slice 1 char ahead | |
let end_stars_index = line.find('*'); | |
if end_stars_index.is_none() { | |
// @NOTE(CHall): this isnt the best solution. but it works | |
write!(out_file, "*").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): count the end chars. if theyre is less of them than stars at the begging | |
// just print out the first star and return a slace 1 char ahead | |
let end_stars_index = end_stars_index.unwrap(); | |
let at_end_stars = &line[end_stars_index..]; | |
let (end_stars_count, _) = consume_and_count_char_repeated(at_end_stars, '*'); | |
if end_stars_count < start_stars_count { | |
write!(out_file, "*").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): Switch on start stars count. not end stars because there could be more than start stars | |
let between_stars = &line[..end_stars_index]; | |
match start_stars_count { | |
1 => { | |
write!(out_file, "<i>").unwrap(); | |
parse_and_output_raw_text(out_file, &between_stars); | |
write!(out_file, "</i>").unwrap(); | |
}, | |
2 => { | |
write!(out_file, "<b>").unwrap(); | |
parse_and_output_raw_text(out_file, &between_stars); | |
write!(out_file, "</b>").unwrap(); | |
}, | |
3 => { | |
write!(out_file, "<i><b>").unwrap(); | |
parse_and_output_raw_text(out_file, &between_stars); | |
write!(out_file, "</b></i>").unwrap(); | |
} | |
_ => panic!("Invalid codepath") | |
} | |
&at_end_stars[start_stars_count..] | |
} | |
fn parse_and_output_inline_code<'a>(out_file: &mut fs::File, line: &'a str) -> &'a str { | |
let orig_line = line; | |
// @TODO(CHall): count tilde at beginning. if over 1 just return a slice 1 char forward | |
let (start_tilde_count, line) = consume_and_count_char_repeated(line, '`'); | |
if start_tilde_count > 1 { | |
write!(out_file, "`").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): find end tilde index. if invalid return a slice 1 char forward | |
let end_tilde_index = line.find('`'); | |
if end_tilde_index.is_none() { | |
write!(out_file, "`").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): count tilde at end. if over 1 return a slice 1 char forward | |
let end_tilde_index = end_tilde_index.unwrap(); | |
let at_end_tilde = &line[end_tilde_index..]; | |
write!(out_file, "<span class=\"inline_code\">{}</span>", &line[..end_tilde_index]).unwrap(); | |
&at_end_tilde[1..] | |
} | |
fn parse_and_output_inline_link<'a>(out_file: &mut fs::File, line: &'a str) -> &'a str { | |
assert!(line.starts_with('[')); | |
let orig_line = line; | |
// @NOTE(CHall): find last bracket. if we couldnt return a slice 1 char forward | |
let line = &line[1..]; | |
let end_bracket_index = line.find(']'); | |
if end_bracket_index.is_none() { | |
write!(out_file, "[").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): make sure there is text to put in the hyperlink. if we couldnt return a slice 1 char forward | |
let end_bracket_index = end_bracket_index.unwrap(); | |
let text = &line[..end_bracket_index]; | |
if text.len() <= 0 { | |
write!(out_file, "[").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): if we couldnt find a first paren return a slice 1 char forward | |
let line = &line[end_bracket_index + 1..].trim_start(); | |
if !line.starts_with('(') { | |
write!(out_file, "[").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): if we couldnt find an end paren return a slice 1 char forward | |
let line = &line[1..]; | |
let end_paren_index = line.find(')'); | |
if end_paren_index.is_none() { | |
write!(out_file, "[").unwrap(); | |
return &orig_line[1..]; | |
} | |
// @NOTE(CHall): if the link is empty return a slice 1 char forward | |
let end_paren_index = end_paren_index.unwrap(); | |
let link = &line[..end_paren_index]; | |
if link.len() <= 0 { | |
write!(out_file, "[").unwrap(); | |
return &orig_line[1..]; | |
} | |
write!(out_file, "<a href=\"{}\">", link).unwrap(); | |
parse_and_output_raw_text(out_file, text); | |
write!(out_file, "</a>").unwrap(); | |
&line[end_paren_index + 1..] | |
} | |
fn parse_and_output_raw_text(out_file: &mut fs::File, line: &str) { | |
let mut mut_line = line; // @TODO(CHall): Should i just pass in a mut line? | |
// @NOTE(CHall): run through line char by char. switch on char for special inline voodoo. | |
// voodoo returns a new str to run through | |
loop { | |
let c = mut_line.chars().next(); | |
if c.is_none() { break; } | |
let c = c.unwrap(); | |
match c { | |
'*' => mut_line = parse_and_output_star(out_file, mut_line), | |
'`' => mut_line = parse_and_output_inline_code(out_file, mut_line), | |
'[' => mut_line = parse_and_output_inline_link(out_file, mut_line), | |
_ => { | |
write!(out_file, "{}", c).unwrap(); | |
mut_line = &mut_line[c.len_utf8()..]; | |
} | |
} | |
} | |
} | |
fn output_line_as_p(out_file: &mut fs::File, line: &str) { | |
write!(out_file, "<p>").unwrap(); | |
parse_and_output_raw_text(out_file, line); | |
writeln!(out_file, "</p>").unwrap(); | |
} | |
fn output_newline(out_file: &mut fs::File) { | |
writeln!(out_file, "<br>").unwrap(); | |
} | |
fn parse_and_output_code_block<'a>(out_file: &mut fs::File, rest_of_file: &'a str) -> &'a str{ | |
let line = rest_of_file.lines().next().unwrap(); | |
let (start_tilde_count, rest_of_file) = consume_and_count_char_repeated(rest_of_file, '`'); | |
if start_tilde_count != 3 { | |
output_line_as_p(out_file, line); | |
return &rest_of_file[line.len()..]; | |
} | |
let end_tilde_index = rest_of_file.find('`'); | |
if end_tilde_index.is_none() { | |
output_line_as_p(out_file, line); | |
return &rest_of_file[line.len()..]; | |
} | |
let end_tilde_index = end_tilde_index.unwrap(); | |
let at_end_tilde = &rest_of_file[end_tilde_index..]; | |
let (end_tilde_count, _) = consume_and_count_char_repeated(at_end_tilde, '`'); | |
if end_tilde_count < 3 { | |
output_line_as_p(out_file, line); | |
return &rest_of_file[line.len()..]; | |
} | |
// @TODO(CHall): parse on given code type which is in line | |
let line = rest_of_file.lines().next().unwrap(); | |
let out_code = &rest_of_file[line.len()..end_tilde_index].trim_start(); | |
writeln!(out_file, "<span class=\"code_block\">{}</span>", out_code).unwrap(); | |
&at_end_tilde[3..] | |
} | |
fn main() -> std::io::Result<()> { | |
let home_dir = fs::read_dir(".")?; | |
for entry in home_dir { | |
let entry = entry?; | |
let file_type = entry.file_type()?; | |
if file_type.is_file() { | |
let entry_path = entry.path(); | |
let extension = entry_path.extension(); | |
if extension.is_none() { continue; } | |
if extension.unwrap() != EXTENSION { continue; } | |
let loaded_file = fs::read_to_string( entry_path.as_path())?; | |
let mut out_file_path = entry_path.clone(); | |
out_file_path.set_extension("html"); | |
let mut out_file = fs::File::create(out_file_path.as_path())?; | |
write!(out_file, "{}", HEADER)?; | |
let mut mut_loaded_file: &str = &loaded_file; | |
loop { | |
let line = mut_loaded_file.lines().next(); | |
if line.is_none() { break; } | |
let line = line.unwrap(); | |
write!(out_file, " ")?; | |
if line.len() <= 0 || line.trim().is_empty() { | |
output_newline(&mut out_file); | |
continue; | |
} | |
match line.chars().next().unwrap() { | |
'#' => { | |
parse_and_output_header(&mut out_file, line); | |
mut_loaded_file = &mut_loaded_file[line.len()..]; | |
mut_loaded_file = &mut_loaded_file.trim_start(); | |
}, | |
'`' => mut_loaded_file = parse_and_output_code_block(&mut out_file, mut_loaded_file), | |
_ => { | |
output_line_as_p(&mut out_file, line); | |
mut_loaded_file = &mut_loaded_file[line.len()..]; | |
mut_loaded_file = &mut_loaded_file.trim_start(); | |
}, | |
} | |
} | |
write!(out_file, "{}", FOOTER)?; | |
} | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment