Last active
June 9, 2022 05:47
-
-
Save jesselawson/b5dea9e1abdff2d80f207f9dcfd732b8 to your computer and use it in GitHub Desktop.
Fifth Checkpoint, Getting Started with Rust by Building a Tiny Markdown Compiler (https://jesselawson.org/tutorials)
This file contains 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
// Code for the Fifth Checkpoint | |
// Tutorial: https://jesselawson.org/rust/get-started-with-rust-by-building-a-tiny-markdown-compiler/ | |
// | |
// The purpose of this checkpoint is to ensure that you have a complete copy | |
// of the code in the tutorial up to the checkpoint. I want you to tinker and | |
// explore, but to keep up with the rest of the tutorial, make sure your | |
// code matches this checkpoint. | |
use std::path::Path; | |
use std::fs::File; | |
use std::io::{BufRead, BufReader}; | |
use std::io::Write; | |
fn parse_markdown_file(_filename: &str) { | |
print_short_banner(); | |
println!("[ INFO ] Starting parser!"); | |
// Create a path variable from the filename | |
let input_filename = Path::new(_filename); | |
// Try to open the file | |
let file = File::open(&input_filename).expect("[ ERROR ] Failed to open file!"); | |
// Create a place to store all our tokens | |
let mut tokens: Vec<String> = Vec::new(); | |
// Read the file line-by-line | |
let reader = BufReader::new(file); | |
let mut ptag: bool = false; // keep track of paragraph enclosures | |
let mut htag: bool = false; | |
for line in reader.lines() { | |
let line_contents = line.unwrap(); | |
let mut first_char: Vec<char> = line_contents.chars().take(1).collect(); | |
// Now check the first character to for headings | |
let mut s = String::new(); | |
let slice = &line_contents.to_string(); | |
match first_char.pop() { | |
Some('#') => { | |
if ptag { | |
ptag = false; | |
s.push_str("</p>\n"); // adding \n for instructional clarity | |
} | |
if htag { | |
htag = false; | |
s.push_str("</h1>\n"); // close it if we're already open | |
} | |
htag = true; | |
s.push_str("<h1>"); | |
s.push_str(&slice[2..]); // Get all but the first two characters | |
}, | |
_ => { | |
if htag { | |
htag = false; | |
s.push_str("</h1>\n"); | |
} | |
if !ptag { | |
ptag = true; | |
s.push_str("<p>"); | |
} | |
s.push_str(&slice); | |
} | |
}; | |
// At the very end, check if any of the tag bools are still open. If so, | |
// close them. | |
if htag { | |
htag = false; | |
s.push_str("</h1>\n"); | |
} | |
if ptag { | |
ptag = false; | |
s.push_str("</p>\n"); | |
} | |
// Don't push blank lines | |
if s != "<p></p>\n" { | |
tokens.push(s); | |
} | |
} | |
// Create an output file based on the input file, minus ".md" | |
let _output_filename = &_filename[.._filename.len()-3]; | |
let mut output_filename = String::from(_output_filename); | |
output_filename.push_str(".html"); | |
let mut outfile = File::create(output_filename.to_string()) | |
.expect("[ ERROR ] Could not create output file!"); | |
for line in &tokens { | |
outfile.write_all(line.as_bytes()) | |
.expect("[ ERROR ] Could not write to output file!"); | |
} | |
} | |
fn get_title() -> String { | |
let mut the_title = String::from(env!("CARGO_PKG_NAME")); | |
the_title.push_str(" (v"); | |
the_title.push_str(env!("CARGO_PKG_VERSION")); | |
the_title.push_str("), "); | |
the_title.push_str(env!("CARGO_PKG_DESCRIPTION")); | |
return the_title; | |
} | |
fn print_short_banner() { | |
println!("{}", get_title()); | |
} | |
fn print_long_banner() { | |
print_short_banner(); | |
println!("Written by: {}\nHomepage: {}\nUsage: tinymd <somefile>.md\n", | |
env!("CARGO_PKG_AUTHORS"), | |
env!("CARGO_PKG_HOMEPAGE") | |
); | |
} | |
fn usage() { | |
print_long_banner(); | |
} | |
fn main() { | |
let args: Vec<String> = std::env::args().collect(); | |
match args.len() { | |
2 => parse_markdown_file(&args[1]), | |
_ => { | |
println!("[ ERROR ] No input file specified!"); | |
usage(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment