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