Mercurial > md2html
view src/main.rs @ 0:9875208e49a0 tip
First entry
| author | ferencd |
|---|---|
| date | Thu, 16 Feb 2023 15:22:52 +0100 |
| parents | |
| children |
line wrap: on
line source
mod list; mod header; mod blockquote; use base64::{engine::general_purpose, Engine as _}; use crate::list::close_opened_lists; use crate::list::deal_with_list; use crate::list::insert_list_entry; use crate::header::header; use crate::header::format_header; use crate::header::handle_as_header; use crate::blockquote::deal_with_blockquote; use std::{env, process}; use std::fs::{File}; use std::io::{self, BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; // The output is wrapped in a Result to allow matching on errors // Returns an Iterator to the Reader of the lines of the file. fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> where P: AsRef<Path>, { let file = File::open(filename)?; Ok(io::BufReader::new(file).lines()) } // returns the current working directory fn get_current_working_dir() -> std::io::Result<PathBuf> { env::current_dir() } // // bold_it - whether a bold_italic was started (true) or not (false), goes out, comes in // bold - whether the bold tag was activated or not // italic - whether the italic tag was activated or not fn interpret_line(p :&str, bold_it:&mut bool, bold:&mut bool, italic:&mut bool) -> String { let s = p.trim(); // first check: is this a header? let hsize = [6,5,4,3,2,1]; for hs in hsize { if header(s, hs) { return format_header(s.to_string(), hs, 0, bold_it, bold, italic); } } let mut t = s.to_string(); handle_tag(&mut t, bold_it, "***", "<strong><em>", "</strong></em>"); handle_tag(&mut t, bold, "**", "<strong>", "</strong>"); handle_tag(&mut t, italic, "*", "<em>", "</em>"); // image? let mut imgsp = t.find("!["); if imgsp != None { while imgsp != None { let mut res:String = String::new(); res = res + &t.as_str()[..imgsp.unwrap()]; let imgep = t.find("]("); if imgep != None { let tag = &t[imgsp.unwrap() + 2..imgep.unwrap()]; let closep = t.find(")"); if closep != None { println!("{} {}", imgep.unwrap() + 2, closep.unwrap()); let imgpath = &t[imgep.unwrap() + 2..closep.unwrap()]; // grab the image let f = File::open(imgpath).expect("Not found image"); let mut reader = BufReader::new(f); let mut buffer = Vec::new(); // Read file into vector. reader.read_to_end(&mut buffer).expect("Cannot read file"); let encoded =general_purpose::STANDARD.encode(&buffer); res = res + "<img src=\"data:image/png;base64, " + &encoded + "\"" + " alt=\"" + tag + "\">" + &t[closep.unwrap()+1..]; } else { println!("Invalid image tag, missing close parenthesis"); process::exit(0x0100); } } else { println!("Invalid image tag, missing close tag: {}", t); process::exit(0x0100); } imgsp = t.find("!["); t = res; imgsp = t.find("!["); } } return t.to_string(); } // handles the tag in the given string fn handle_tag(t: &mut String, mdtag_flag: &mut bool, mdtag: &str, open_tag: &str, close_tag: &str) { loop { if let Some(_s3) = t.find(mdtag) { if !*mdtag_flag { *t = t.replacen(mdtag, open_tag, 1); *mdtag_flag = true; } else { *t = t.replacen(mdtag, close_tag, 1); *mdtag_flag = false; } } else { break; } } } // will replace the last occurence of `w` (what) with `ww` (with what) in `s` fn replace_last(s:String, w:String, ww:String) -> String { let i = s.rfind(w.as_str()); if i.is_some() { let p1 = &s[..i.unwrap()].to_string(); let p2 = &s[i.unwrap() + w.len()..].to_string(); let result = p1.to_owned() + &ww + p2; return result; } return s; } // close all the open tags fn close_opened_tags(mut html_lines: &mut Vec<String>, mut olist_count: &mut i8, mut olist_space_count: &mut i8, mut ulist_count: &mut i8, mut ulist_space_count: &mut i8) { // usually lists end with an empty line close_opened_lists(&mut html_lines, &mut olist_count, &mut olist_space_count, "</ol>"); close_opened_lists(&mut html_lines, &mut ulist_count, &mut ulist_space_count, "</ul>"); html_lines.push("<p>".to_string()); } // // Main // fn main() { let cwd = get_current_working_dir().unwrap(); let tmp = cwd.to_str(); let filename = tmp.unwrap().to_owned() + &"/amalgamated.md".to_string(); // File hosts must exist in current path before this produces output if let Ok(lines) = read_lines(filename.clone()) { // will be written to the html file let mut html_lines:Vec<String> = Vec::new(); let mut bold_it:bool = false; // whether the bold_italic tag was activated or not let mut bold : bool = false; // whether the bold tag was activated or not let mut italic : bool = false; // whether the italic tag was activated or not let mut blockquote : i8 = 0; // whether we have started a blockqoute tag or not. Tells us the nesting level of blockquotes let mut olist_count : i8 = 0; // whether we have an ordered list started, also counts the nested ones let mut olist_space_count:i8 = 0;// the previous stage of the ordered lists let mut ulist_count : i8 = 0; // whether we have an ordered list started, also counts the nested ones let mut ulist_space_count:i8 = 0;// the previous stage of the ordered lists // create the html lines for line in lines { if let Ok(lcheck) = line { // taking a copy for further operations let mut cline:String = lcheck.to_string(); let tip = cline.clone(); let orig_ip = cline.clone(); let trimmed_line = tip.trim(); if cline.is_empty() { close_opened_tags(&mut html_lines, &mut olist_count, &mut olist_space_count, &mut ulist_count, &mut ulist_space_count); continue; } // is this a blockquote? deal_with_blockquote(&mut html_lines, &mut blockquote, &mut cline); // ordered list checker let ol_start_checker = |tip: &str, idx: isize | -> bool { tip.chars().nth(idx.try_into().unwrap()).unwrap().is_numeric() }; deal_with_list(&mut html_lines, &mut olist_count, &mut olist_space_count, &orig_ip, trimmed_line, ol_start_checker, "<ol>", "</ol>", '.'); // unordered list checker let ul_start_checker = |tip: &str, idx: isize | -> bool { if idx == 2 { return false; } let c = tip.chars().nth(idx.try_into().unwrap()).unwrap(); match c { '*'|'-'|'+'=>true, _=>false } }; deal_with_list(&mut html_lines, &mut ulist_count, &mut ulist_space_count, &orig_ip, trimmed_line, ul_start_checker, "<ul>", "</ul>", ' '); // paragraph first check: is this a ===== line, denoting that the previous line was a h1 header if handle_as_header(&cline, &mut html_lines, 1, &mut bold_it, &mut bold, &mut italic) { continue; } // paragraph second check: is this a ---- line, denoting that the previous line was a h2 header if !handle_as_header(&cline, &mut html_lines, 2, &mut bold_it, &mut bold, &mut italic) { // it was not a header, must be a normal line let mut inted = interpret_line(cline.as_str(), &mut bold_it, &mut bold, &mut italic) + "\n"; insert_list_entry(&mut olist_count, trimmed_line, &mut inted, ol_start_checker, '.'); insert_list_entry(&mut ulist_count, trimmed_line, &mut inted, ul_start_checker,' '); html_lines.push(inted); } } } // closing all the opened tags close_opened_tags(&mut html_lines, &mut olist_count, &mut olist_space_count, &mut ulist_count, &mut ulist_space_count); // joining the lines let mut full_html_line:String = Default::default(); for html_line in html_lines { full_html_line += &html_line; } // did we encountered an unclosed bold_it if bold_it { full_html_line = replace_last(full_html_line, "<strong><em>".to_string(), "***".to_string()); } if bold { full_html_line = replace_last(full_html_line, "<strong>".to_string(), "**".to_string()); } if italic { full_html_line = replace_last(full_html_line, "<em>".to_string(), "*".to_string()); } // create a html file let mut file = File::create("blaa.html").expect("Cannot create file"); file.write_all(full_html_line.as_bytes()).expect("Cannot write to file"); } else { println!("{} not found", filename.to_string()); return; } }
