ferencd@0: mod list; ferencd@0: mod header; ferencd@0: mod blockquote; ferencd@0: ferencd@0: use base64::{engine::general_purpose, Engine as _}; ferencd@0: ferencd@0: use crate::list::close_opened_lists; ferencd@0: use crate::list::deal_with_list; ferencd@0: use crate::list::insert_list_entry; ferencd@0: ferencd@0: use crate::header::header; ferencd@0: use crate::header::format_header; ferencd@0: use crate::header::handle_as_header; ferencd@0: ferencd@0: use crate::blockquote::deal_with_blockquote; ferencd@0: ferencd@0: use std::{env, process}; ferencd@0: use std::fs::{File}; ferencd@0: use std::io::{self, BufRead, BufReader, Read, Write}; ferencd@0: use std::path::{Path, PathBuf}; ferencd@0: ferencd@0: // The output is wrapped in a Result to allow matching on errors ferencd@0: // Returns an Iterator to the Reader of the lines of the file. ferencd@0: fn read_lines

(filename: P) -> io::Result>> ferencd@0: where P: AsRef, { ferencd@0: let file = File::open(filename)?; ferencd@0: Ok(io::BufReader::new(file).lines()) ferencd@0: } ferencd@0: ferencd@0: // returns the current working directory ferencd@0: fn get_current_working_dir() -> std::io::Result { ferencd@0: env::current_dir() ferencd@0: } ferencd@0: ferencd@0: // ferencd@0: // bold_it - whether a bold_italic was started (true) or not (false), goes out, comes in ferencd@0: // bold - whether the bold tag was activated or not ferencd@0: // italic - whether the italic tag was activated or not ferencd@0: fn interpret_line(p :&str, bold_it:&mut bool, bold:&mut bool, italic:&mut bool) -> String ferencd@0: { ferencd@0: let s = p.trim(); ferencd@0: ferencd@0: // first check: is this a header? ferencd@0: let hsize = [6,5,4,3,2,1]; ferencd@0: for hs in hsize { ferencd@0: if header(s, hs) { ferencd@0: return format_header(s.to_string(), hs, 0, bold_it, bold, italic); ferencd@0: } ferencd@0: } ferencd@0: ferencd@0: let mut t = s.to_string(); ferencd@0: ferencd@0: handle_tag(&mut t, bold_it, "***", "", ""); ferencd@0: handle_tag(&mut t, bold, "**", "", ""); ferencd@0: handle_tag(&mut t, italic, "*", "", ""); ferencd@0: ferencd@0: // image? ferencd@0: let mut imgsp = t.find("!["); ferencd@0: if imgsp != None { ferencd@0: while imgsp != None { ferencd@0: let mut res:String = String::new(); ferencd@0: res = res + &t.as_str()[..imgsp.unwrap()]; ferencd@0: let imgep = t.find("]("); ferencd@0: if imgep != None { ferencd@0: let tag = &t[imgsp.unwrap() + 2..imgep.unwrap()]; ferencd@0: let closep = t.find(")"); ferencd@0: if closep != None { ferencd@0: println!("{} {}", imgep.unwrap() + 2, closep.unwrap()); ferencd@0: let imgpath = &t[imgep.unwrap() + 2..closep.unwrap()]; ferencd@0: // grab the image ferencd@0: let f = File::open(imgpath).expect("Not found image"); ferencd@0: let mut reader = BufReader::new(f); ferencd@0: let mut buffer = Vec::new(); ferencd@0: ferencd@0: // Read file into vector. ferencd@0: reader.read_to_end(&mut buffer).expect("Cannot read file"); ferencd@0: let encoded =general_purpose::STANDARD.encode(&buffer); ferencd@0: res = res + "\""" + &t[closep.unwrap()+1..]; ferencd@0: } else { ferencd@0: println!("Invalid image tag, missing close parenthesis"); ferencd@0: process::exit(0x0100); ferencd@0: } ferencd@0: } else { ferencd@0: println!("Invalid image tag, missing close tag: {}", t); ferencd@0: process::exit(0x0100); ferencd@0: } ferencd@0: imgsp = t.find("!["); ferencd@0: t = res; ferencd@0: imgsp = t.find("!["); ferencd@0: } ferencd@0: } ferencd@0: return t.to_string(); ferencd@0: } ferencd@0: ferencd@0: // handles the tag in the given string ferencd@0: fn handle_tag(t: &mut String, mdtag_flag: &mut bool, mdtag: &str, open_tag: &str, close_tag: &str) { ferencd@0: loop { ferencd@0: if let Some(_s3) = t.find(mdtag) { ferencd@0: if !*mdtag_flag { ferencd@0: *t = t.replacen(mdtag, open_tag, 1); ferencd@0: *mdtag_flag = true; ferencd@0: } else { ferencd@0: *t = t.replacen(mdtag, close_tag, 1); ferencd@0: *mdtag_flag = false; ferencd@0: } ferencd@0: } else { ferencd@0: break; ferencd@0: } ferencd@0: } ferencd@0: } ferencd@0: ferencd@0: // will replace the last occurence of `w` (what) with `ww` (with what) in `s` ferencd@0: fn replace_last(s:String, w:String, ww:String) -> String { ferencd@0: let i = s.rfind(w.as_str()); ferencd@0: if i.is_some() { ferencd@0: let p1 = &s[..i.unwrap()].to_string(); ferencd@0: let p2 = &s[i.unwrap() + w.len()..].to_string(); ferencd@0: let result = p1.to_owned() + &ww + p2; ferencd@0: return result; ferencd@0: } ferencd@0: return s; ferencd@0: } ferencd@0: ferencd@0: // close all the open tags ferencd@0: fn close_opened_tags(mut html_lines: &mut Vec, mut olist_count: &mut i8, mut olist_space_count: &mut i8, mut ulist_count: &mut i8, mut ulist_space_count: &mut i8) ferencd@0: { ferencd@0: // usually lists end with an empty line ferencd@0: close_opened_lists(&mut html_lines, &mut olist_count, &mut olist_space_count, ""); ferencd@0: close_opened_lists(&mut html_lines, &mut ulist_count, &mut ulist_space_count, ""); ferencd@0: html_lines.push("

".to_string()); ferencd@0: } ferencd@0: ferencd@0: // ferencd@0: // Main ferencd@0: // ferencd@0: fn main() { ferencd@0: let cwd = get_current_working_dir().unwrap(); ferencd@0: let tmp = cwd.to_str(); ferencd@0: let filename = tmp.unwrap().to_owned() + &"/amalgamated.md".to_string(); ferencd@0: // File hosts must exist in current path before this produces output ferencd@0: if let Ok(lines) = read_lines(filename.clone()) { ferencd@0: // will be written to the html file ferencd@0: let mut html_lines:Vec = Vec::new(); ferencd@0: let mut bold_it:bool = false; // whether the bold_italic tag was activated or not ferencd@0: let mut bold : bool = false; // whether the bold tag was activated or not ferencd@0: let mut italic : bool = false; // whether the italic tag was activated or not ferencd@0: let mut blockquote : i8 = 0; // whether we have started a blockqoute tag or not. Tells us the nesting level of blockquotes ferencd@0: let mut olist_count : i8 = 0; // whether we have an ordered list started, also counts the nested ones ferencd@0: let mut olist_space_count:i8 = 0;// the previous stage of the ordered lists ferencd@0: let mut ulist_count : i8 = 0; // whether we have an ordered list started, also counts the nested ones ferencd@0: let mut ulist_space_count:i8 = 0;// the previous stage of the ordered lists ferencd@0: ferencd@0: // create the html lines ferencd@0: for line in lines { ferencd@0: if let Ok(lcheck) = line { ferencd@0: // taking a copy for further operations ferencd@0: let mut cline:String = lcheck.to_string(); ferencd@0: let tip = cline.clone(); ferencd@0: let orig_ip = cline.clone(); ferencd@0: let trimmed_line = tip.trim(); ferencd@0: ferencd@0: if cline.is_empty() { ferencd@0: close_opened_tags(&mut html_lines, &mut olist_count, &mut olist_space_count, &mut ulist_count, &mut ulist_space_count); ferencd@0: continue; ferencd@0: } ferencd@0: ferencd@0: // is this a blockquote? ferencd@0: deal_with_blockquote(&mut html_lines, &mut blockquote, &mut cline); ferencd@0: ferencd@0: // ordered list checker ferencd@0: let ol_start_checker = |tip: &str, idx: isize | -> bool { tip.chars().nth(idx.try_into().unwrap()).unwrap().is_numeric() }; ferencd@0: deal_with_list(&mut html_lines, &mut olist_count, &mut olist_space_count, &orig_ip, trimmed_line, ol_start_checker, "

    ", "
", '.'); ferencd@0: ferencd@0: // unordered list checker ferencd@0: let ul_start_checker = |tip: &str, idx: isize | -> bool { ferencd@0: if idx == 2 { ferencd@0: return false; ferencd@0: } ferencd@0: let c = tip.chars().nth(idx.try_into().unwrap()).unwrap(); ferencd@0: match c { ferencd@0: '*'|'-'|'+'=>true, ferencd@0: _=>false ferencd@0: } ferencd@0: }; ferencd@0: deal_with_list(&mut html_lines, &mut ulist_count, &mut ulist_space_count, &orig_ip, trimmed_line, ul_start_checker, "", ' '); ferencd@0: ferencd@0: // paragraph first check: is this a ===== line, denoting that the previous line was a h1 header ferencd@0: if handle_as_header(&cline, &mut html_lines, 1, &mut bold_it, &mut bold, &mut italic) { ferencd@0: continue; ferencd@0: } ferencd@0: ferencd@0: // paragraph second check: is this a ---- line, denoting that the previous line was a h2 header ferencd@0: if !handle_as_header(&cline, &mut html_lines, 2, &mut bold_it, &mut bold, &mut italic) { ferencd@0: // it was not a header, must be a normal line ferencd@0: let mut inted = interpret_line(cline.as_str(), &mut bold_it, &mut bold, &mut italic) + "\n"; ferencd@0: insert_list_entry(&mut olist_count, trimmed_line, &mut inted, ol_start_checker, '.'); ferencd@0: insert_list_entry(&mut ulist_count, trimmed_line, &mut inted, ul_start_checker,' '); ferencd@0: html_lines.push(inted); ferencd@0: } ferencd@0: } ferencd@0: } ferencd@0: ferencd@0: // closing all the opened tags ferencd@0: close_opened_tags(&mut html_lines, &mut olist_count, &mut olist_space_count, &mut ulist_count, &mut ulist_space_count); ferencd@0: ferencd@0: // joining the lines ferencd@0: let mut full_html_line:String = Default::default(); ferencd@0: for html_line in html_lines { ferencd@0: full_html_line += &html_line; ferencd@0: } ferencd@0: ferencd@0: // did we encountered an unclosed bold_it ferencd@0: if bold_it { ferencd@0: full_html_line = replace_last(full_html_line, "".to_string(), "***".to_string()); ferencd@0: } ferencd@0: if bold { ferencd@0: full_html_line = replace_last(full_html_line, "".to_string(), "**".to_string()); ferencd@0: } ferencd@0: if italic { ferencd@0: full_html_line = replace_last(full_html_line, "".to_string(), "*".to_string()); ferencd@0: } ferencd@0: ferencd@0: // create a html file ferencd@0: let mut file = File::create("blaa.html").expect("Cannot create file"); ferencd@0: file.write_all(full_html_line.as_bytes()).expect("Cannot write to file"); ferencd@0: } ferencd@0: else { ferencd@0: println!("{} not found", filename.to_string()); ferencd@0: return; ferencd@0: } ferencd@0: }