annotate src/main.rs @ 0:9875208e49a0 tip

First entry
author ferencd
date Thu, 16 Feb 2023 15:22:52 +0100
parents
children
rev   line source
ferencd@0 1 mod list;
ferencd@0 2 mod header;
ferencd@0 3 mod blockquote;
ferencd@0 4
ferencd@0 5 use base64::{engine::general_purpose, Engine as _};
ferencd@0 6
ferencd@0 7 use crate::list::close_opened_lists;
ferencd@0 8 use crate::list::deal_with_list;
ferencd@0 9 use crate::list::insert_list_entry;
ferencd@0 10
ferencd@0 11 use crate::header::header;
ferencd@0 12 use crate::header::format_header;
ferencd@0 13 use crate::header::handle_as_header;
ferencd@0 14
ferencd@0 15 use crate::blockquote::deal_with_blockquote;
ferencd@0 16
ferencd@0 17 use std::{env, process};
ferencd@0 18 use std::fs::{File};
ferencd@0 19 use std::io::{self, BufRead, BufReader, Read, Write};
ferencd@0 20 use std::path::{Path, PathBuf};
ferencd@0 21
ferencd@0 22 // The output is wrapped in a Result to allow matching on errors
ferencd@0 23 // Returns an Iterator to the Reader of the lines of the file.
ferencd@0 24 fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
ferencd@0 25 where P: AsRef<Path>, {
ferencd@0 26 let file = File::open(filename)?;
ferencd@0 27 Ok(io::BufReader::new(file).lines())
ferencd@0 28 }
ferencd@0 29
ferencd@0 30 // returns the current working directory
ferencd@0 31 fn get_current_working_dir() -> std::io::Result<PathBuf> {
ferencd@0 32 env::current_dir()
ferencd@0 33 }
ferencd@0 34
ferencd@0 35 //
ferencd@0 36 // bold_it - whether a bold_italic was started (true) or not (false), goes out, comes in
ferencd@0 37 // bold - whether the bold tag was activated or not
ferencd@0 38 // italic - whether the italic tag was activated or not
ferencd@0 39 fn interpret_line(p :&str, bold_it:&mut bool, bold:&mut bool, italic:&mut bool) -> String
ferencd@0 40 {
ferencd@0 41 let s = p.trim();
ferencd@0 42
ferencd@0 43 // first check: is this a header?
ferencd@0 44 let hsize = [6,5,4,3,2,1];
ferencd@0 45 for hs in hsize {
ferencd@0 46 if header(s, hs) {
ferencd@0 47 return format_header(s.to_string(), hs, 0, bold_it, bold, italic);
ferencd@0 48 }
ferencd@0 49 }
ferencd@0 50
ferencd@0 51 let mut t = s.to_string();
ferencd@0 52
ferencd@0 53 handle_tag(&mut t, bold_it, "***", "<strong><em>", "</strong></em>");
ferencd@0 54 handle_tag(&mut t, bold, "**", "<strong>", "</strong>");
ferencd@0 55 handle_tag(&mut t, italic, "*", "<em>", "</em>");
ferencd@0 56
ferencd@0 57 // image?
ferencd@0 58 let mut imgsp = t.find("![");
ferencd@0 59 if imgsp != None {
ferencd@0 60 while imgsp != None {
ferencd@0 61 let mut res:String = String::new();
ferencd@0 62 res = res + &t.as_str()[..imgsp.unwrap()];
ferencd@0 63 let imgep = t.find("](");
ferencd@0 64 if imgep != None {
ferencd@0 65 let tag = &t[imgsp.unwrap() + 2..imgep.unwrap()];
ferencd@0 66 let closep = t.find(")");
ferencd@0 67 if closep != None {
ferencd@0 68 println!("{} {}", imgep.unwrap() + 2, closep.unwrap());
ferencd@0 69 let imgpath = &t[imgep.unwrap() + 2..closep.unwrap()];
ferencd@0 70 // grab the image
ferencd@0 71 let f = File::open(imgpath).expect("Not found image");
ferencd@0 72 let mut reader = BufReader::new(f);
ferencd@0 73 let mut buffer = Vec::new();
ferencd@0 74
ferencd@0 75 // Read file into vector.
ferencd@0 76 reader.read_to_end(&mut buffer).expect("Cannot read file");
ferencd@0 77 let encoded =general_purpose::STANDARD.encode(&buffer);
ferencd@0 78 res = res + "<img src=\"data:image/png;base64, " + &encoded + "\"" + " alt=\"" + tag + "\">" + &t[closep.unwrap()+1..];
ferencd@0 79 } else {
ferencd@0 80 println!("Invalid image tag, missing close parenthesis");
ferencd@0 81 process::exit(0x0100);
ferencd@0 82 }
ferencd@0 83 } else {
ferencd@0 84 println!("Invalid image tag, missing close tag: {}", t);
ferencd@0 85 process::exit(0x0100);
ferencd@0 86 }
ferencd@0 87 imgsp = t.find("![");
ferencd@0 88 t = res;
ferencd@0 89 imgsp = t.find("![");
ferencd@0 90 }
ferencd@0 91 }
ferencd@0 92 return t.to_string();
ferencd@0 93 }
ferencd@0 94
ferencd@0 95 // handles the tag in the given string
ferencd@0 96 fn handle_tag(t: &mut String, mdtag_flag: &mut bool, mdtag: &str, open_tag: &str, close_tag: &str) {
ferencd@0 97 loop {
ferencd@0 98 if let Some(_s3) = t.find(mdtag) {
ferencd@0 99 if !*mdtag_flag {
ferencd@0 100 *t = t.replacen(mdtag, open_tag, 1);
ferencd@0 101 *mdtag_flag = true;
ferencd@0 102 } else {
ferencd@0 103 *t = t.replacen(mdtag, close_tag, 1);
ferencd@0 104 *mdtag_flag = false;
ferencd@0 105 }
ferencd@0 106 } else {
ferencd@0 107 break;
ferencd@0 108 }
ferencd@0 109 }
ferencd@0 110 }
ferencd@0 111
ferencd@0 112 // will replace the last occurence of `w` (what) with `ww` (with what) in `s`
ferencd@0 113 fn replace_last(s:String, w:String, ww:String) -> String {
ferencd@0 114 let i = s.rfind(w.as_str());
ferencd@0 115 if i.is_some() {
ferencd@0 116 let p1 = &s[..i.unwrap()].to_string();
ferencd@0 117 let p2 = &s[i.unwrap() + w.len()..].to_string();
ferencd@0 118 let result = p1.to_owned() + &ww + p2;
ferencd@0 119 return result;
ferencd@0 120 }
ferencd@0 121 return s;
ferencd@0 122 }
ferencd@0 123
ferencd@0 124 // close all the open tags
ferencd@0 125 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)
ferencd@0 126 {
ferencd@0 127 // usually lists end with an empty line
ferencd@0 128 close_opened_lists(&mut html_lines, &mut olist_count, &mut olist_space_count, "</ol>");
ferencd@0 129 close_opened_lists(&mut html_lines, &mut ulist_count, &mut ulist_space_count, "</ul>");
ferencd@0 130 html_lines.push("<p>".to_string());
ferencd@0 131 }
ferencd@0 132
ferencd@0 133 //
ferencd@0 134 // Main
ferencd@0 135 //
ferencd@0 136 fn main() {
ferencd@0 137 let cwd = get_current_working_dir().unwrap();
ferencd@0 138 let tmp = cwd.to_str();
ferencd@0 139 let filename = tmp.unwrap().to_owned() + &"/amalgamated.md".to_string();
ferencd@0 140 // File hosts must exist in current path before this produces output
ferencd@0 141 if let Ok(lines) = read_lines(filename.clone()) {
ferencd@0 142 // will be written to the html file
ferencd@0 143 let mut html_lines:Vec<String> = Vec::new();
ferencd@0 144 let mut bold_it:bool = false; // whether the bold_italic tag was activated or not
ferencd@0 145 let mut bold : bool = false; // whether the bold tag was activated or not
ferencd@0 146 let mut italic : bool = false; // whether the italic tag was activated or not
ferencd@0 147 let mut blockquote : i8 = 0; // whether we have started a blockqoute tag or not. Tells us the nesting level of blockquotes
ferencd@0 148 let mut olist_count : i8 = 0; // whether we have an ordered list started, also counts the nested ones
ferencd@0 149 let mut olist_space_count:i8 = 0;// the previous stage of the ordered lists
ferencd@0 150 let mut ulist_count : i8 = 0; // whether we have an ordered list started, also counts the nested ones
ferencd@0 151 let mut ulist_space_count:i8 = 0;// the previous stage of the ordered lists
ferencd@0 152
ferencd@0 153 // create the html lines
ferencd@0 154 for line in lines {
ferencd@0 155 if let Ok(lcheck) = line {
ferencd@0 156 // taking a copy for further operations
ferencd@0 157 let mut cline:String = lcheck.to_string();
ferencd@0 158 let tip = cline.clone();
ferencd@0 159 let orig_ip = cline.clone();
ferencd@0 160 let trimmed_line = tip.trim();
ferencd@0 161
ferencd@0 162 if cline.is_empty() {
ferencd@0 163 close_opened_tags(&mut html_lines, &mut olist_count, &mut olist_space_count, &mut ulist_count, &mut ulist_space_count);
ferencd@0 164 continue;
ferencd@0 165 }
ferencd@0 166
ferencd@0 167 // is this a blockquote?
ferencd@0 168 deal_with_blockquote(&mut html_lines, &mut blockquote, &mut cline);
ferencd@0 169
ferencd@0 170 // ordered list checker
ferencd@0 171 let ol_start_checker = |tip: &str, idx: isize | -> bool { tip.chars().nth(idx.try_into().unwrap()).unwrap().is_numeric() };
ferencd@0 172 deal_with_list(&mut html_lines, &mut olist_count, &mut olist_space_count, &orig_ip, trimmed_line, ol_start_checker, "<ol>", "</ol>", '.');
ferencd@0 173
ferencd@0 174 // unordered list checker
ferencd@0 175 let ul_start_checker = |tip: &str, idx: isize | -> bool {
ferencd@0 176 if idx == 2 {
ferencd@0 177 return false;
ferencd@0 178 }
ferencd@0 179 let c = tip.chars().nth(idx.try_into().unwrap()).unwrap();
ferencd@0 180 match c {
ferencd@0 181 '*'|'-'|'+'=>true,
ferencd@0 182 _=>false
ferencd@0 183 }
ferencd@0 184 };
ferencd@0 185 deal_with_list(&mut html_lines, &mut ulist_count, &mut ulist_space_count, &orig_ip, trimmed_line, ul_start_checker, "<ul>", "</ul>", ' ');
ferencd@0 186
ferencd@0 187 // paragraph first check: is this a ===== line, denoting that the previous line was a h1 header
ferencd@0 188 if handle_as_header(&cline, &mut html_lines, 1, &mut bold_it, &mut bold, &mut italic) {
ferencd@0 189 continue;
ferencd@0 190 }
ferencd@0 191
ferencd@0 192 // paragraph second check: is this a ---- line, denoting that the previous line was a h2 header
ferencd@0 193 if !handle_as_header(&cline, &mut html_lines, 2, &mut bold_it, &mut bold, &mut italic) {
ferencd@0 194 // it was not a header, must be a normal line
ferencd@0 195 let mut inted = interpret_line(cline.as_str(), &mut bold_it, &mut bold, &mut italic) + "\n";
ferencd@0 196 insert_list_entry(&mut olist_count, trimmed_line, &mut inted, ol_start_checker, '.');
ferencd@0 197 insert_list_entry(&mut ulist_count, trimmed_line, &mut inted, ul_start_checker,' ');
ferencd@0 198 html_lines.push(inted);
ferencd@0 199 }
ferencd@0 200 }
ferencd@0 201 }
ferencd@0 202
ferencd@0 203 // closing all the opened tags
ferencd@0 204 close_opened_tags(&mut html_lines, &mut olist_count, &mut olist_space_count, &mut ulist_count, &mut ulist_space_count);
ferencd@0 205
ferencd@0 206 // joining the lines
ferencd@0 207 let mut full_html_line:String = Default::default();
ferencd@0 208 for html_line in html_lines {
ferencd@0 209 full_html_line += &html_line;
ferencd@0 210 }
ferencd@0 211
ferencd@0 212 // did we encountered an unclosed bold_it
ferencd@0 213 if bold_it {
ferencd@0 214 full_html_line = replace_last(full_html_line, "<strong><em>".to_string(), "***".to_string());
ferencd@0 215 }
ferencd@0 216 if bold {
ferencd@0 217 full_html_line = replace_last(full_html_line, "<strong>".to_string(), "**".to_string());
ferencd@0 218 }
ferencd@0 219 if italic {
ferencd@0 220 full_html_line = replace_last(full_html_line, "<em>".to_string(), "*".to_string());
ferencd@0 221 }
ferencd@0 222
ferencd@0 223 // create a html file
ferencd@0 224 let mut file = File::create("blaa.html").expect("Cannot create file");
ferencd@0 225 file.write_all(full_html_line.as_bytes()).expect("Cannot write to file");
ferencd@0 226 }
ferencd@0 227 else {
ferencd@0 228 println!("{} not found", filename.to_string());
ferencd@0 229 return;
ferencd@0 230 }
ferencd@0 231 }