]> git.r.bdr.sh - rbdr/page/blob - src/gemini_parser.rs
Add a gemini parser
[rbdr/page] / src / gemini_parser.rs
1 pub fn parse(source: &str) -> String {
2
3 let lines = source.split("\n");
4 let mut is_preformatted = false;
5
6 let mut html:String = "".to_owned();
7 let mut current_line_type: Option<LineType> = None;
8
9 for line in lines {
10 let line_type = identify_line(&(line[..3]), is_preformatted);
11 match line_type {
12 LineType::PreformattedToggle => is_preformatted = !is_preformatted,
13 _ => {
14 // Close previous block if needed
15 if let Some(line) = &current_line_type {
16 if line != &line_type && is_block(line) {
17 html.push_str(get_line_closer(line));
18 }
19 }
20
21 // Blocks
22 if is_block(&line_type) {
23 if let Some(line) = &current_line_type {
24 if line != &line_type {
25 html.push_str(get_line_opener(&line_type));
26 }
27 } else {
28 html.push_str(get_line_opener(&line_type));
29 }
30
31 let line_content = get_partial_line_content(&line_type, line);
32 html.push_str(&line_content);
33 } else {
34 let line_content = get_full_line_content(&line_type, line);
35 html.push_str(&line_content);
36 }
37 current_line_type = Some(line_type);
38 },
39 }
40 }
41 if let Some(line) = &current_line_type {
42 if is_block(line) {
43 html.push_str(get_line_closer(line));
44 }
45 }
46 html
47 }
48
49 fn is_block(line_type: &LineType) -> bool {
50 return match line_type {
51 LineType::PreformattedText => true,
52 LineType::ListItem => true,
53 LineType::Quote => true,
54 _ => false,
55 }
56 }
57
58 fn get_partial_line_content(line_type: &LineType, line: &str) -> String {
59 return match line_type {
60 LineType::ListItem => format!("<li>{}</li>", line[2..].trim()),
61 LineType::Quote => line[1..].trim().to_string(),
62 LineType::PreformattedText => format!("{}\n", line),
63 _ => "".to_string(),
64 }
65 }
66
67 fn get_full_line_content(line_type: &LineType, line: &str) -> String {
68 match line_type {
69 LineType::Text => format!("<p>{}</p>\n", line.trim()),
70 LineType::Blank => "<br/>\n".to_string(),
71 LineType::Link => format!("<div><a href=\"{}\">{}</a></div>\n", get_link_address(line), get_link_content(line)),
72 LineType::Heading1 => format!("<h1>{}</h1>\n", line[1..].trim()),
73 LineType::Heading2 => format!("<h2>{}</h2>\n", line[2..].trim()),
74 LineType::Heading3 => format!("<h3>{}</h3>\n", line[3..].trim()),
75 _ => "".to_string(),
76 }
77 }
78
79 fn get_line_opener(line_type: &LineType) -> &'static str {
80 match line_type {
81 LineType::ListItem => "<ul>",
82 LineType::Quote => "<blockquote>",
83 LineType::PreformattedText => "<pre>",
84 _ => "",
85 }
86 }
87
88 fn get_line_closer(line_type: &LineType) -> &'static str {
89 match line_type {
90 LineType::ListItem => "</ul>\n",
91 LineType::Quote => "</blockquote>\n",
92 LineType::PreformattedText => "</pre>\n",
93 _ => "",
94 }
95 }
96
97 fn get_link_content(line: &str) -> &str {
98 let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect();
99 if components.len() > 1 {
100 return components[1].trim()
101 }
102 components[0].trim()
103 }
104
105 fn get_link_address(line: &str) -> &str {
106 let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect();
107 components[0].trim()
108 }
109
110 fn identify_line(line: &str, is_preformatted: bool) -> LineType {
111 if line.starts_with("```") {
112 return LineType::PreformattedToggle;
113 }
114 if is_preformatted {
115 return LineType::PreformattedText;
116 }
117 if line.is_empty() {
118 return LineType::Blank;
119 }
120 if line.starts_with("=>") {
121 return LineType::Link;
122 }
123 if line.starts_with("* ") {
124 return LineType::ListItem;
125 }
126 if line.starts_with(">") {
127 return LineType::Quote;
128 }
129 if line.starts_with("###") {
130 return LineType::Heading3;
131 }
132 if line.starts_with("##") {
133 return LineType::Heading2;
134 }
135 if line.starts_with("#") {
136 return LineType::Heading1;
137 }
138
139 LineType::Text
140 }
141
142 #[derive(PartialEq, Eq)]
143 enum LineType {
144 Text,
145 Blank,
146 Link,
147 PreformattedToggle,
148 PreformattedText,
149 Heading1,
150 Heading2,
151 Heading3,
152 ListItem,
153 Quote
154 }