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

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