diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main.rs	Thu Feb 16 15:22:52 2023 +0100
@@ -0,0 +1,231 @@
+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;
+    }
+}