]> git.r.bdr.sh - rbdr/page/commitdiff
Add a gemini parser
authorRuben Beltran del Rio <redacted>
Thu, 13 Apr 2023 19:56:38 +0000 (21:56 +0200)
committerRuben Beltran del Rio <redacted>
Thu, 13 Apr 2023 19:56:38 +0000 (21:56 +0200)
.gitignore [new file with mode: 0644]
Cargo.lock [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
src/gemini_parser.rs [new file with mode: 0644]
src/main.rs [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..ea8c4bf
--- /dev/null
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644 (file)
index 0000000..40f6366
--- /dev/null
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "page"
+version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..33b0c29
--- /dev/null
@@ -0,0 +1,6 @@
+[package]
+name = "page"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/gemini_parser.rs b/src/gemini_parser.rs
new file mode 100644 (file)
index 0000000..36abb16
--- /dev/null
@@ -0,0 +1,154 @@
+pub fn parse(source: &str) -> String {
+
+    let lines = source.split("\n");
+    let mut is_preformatted = false;
+
+    let mut html:String = "".to_owned();
+    let mut current_line_type: Option<LineType> = None;
+
+    for line in lines {
+        let line_type = identify_line(&(line[..3]), is_preformatted);
+        match line_type {
+            LineType::PreformattedToggle => is_preformatted = !is_preformatted,
+            _ => {
+                // Close previous block if needed
+                if let Some(line) = &current_line_type {
+                    if line != &line_type && is_block(line) {
+                        html.push_str(get_line_closer(line));
+                    }
+                }
+
+                // Blocks
+                if is_block(&line_type) {
+                    if let Some(line) = &current_line_type {
+                        if line != &line_type  {
+                            html.push_str(get_line_opener(&line_type));
+                        }
+                    } else {
+                        html.push_str(get_line_opener(&line_type));
+                    }
+
+                    let line_content = get_partial_line_content(&line_type, line);
+                    html.push_str(&line_content);
+                } else {
+                    let line_content = get_full_line_content(&line_type, line);
+                    html.push_str(&line_content);
+                }
+                current_line_type = Some(line_type);
+            },
+        }
+    }
+    if let Some(line) = &current_line_type {
+        if is_block(line) {
+            html.push_str(get_line_closer(line));
+        }
+    }
+    html
+}
+
+fn is_block(line_type: &LineType) -> bool {
+    return match line_type {
+        LineType::PreformattedText => true,
+        LineType::ListItem => true,
+        LineType::Quote => true,
+        _ => false,
+    }
+}
+
+fn get_partial_line_content(line_type: &LineType, line: &str) -> String {
+    return match line_type {
+        LineType::ListItem => format!("<li>{}</li>", line[2..].trim()),
+        LineType::Quote => line[1..].trim().to_string(),
+        LineType::PreformattedText => format!("{}\n", line),
+        _ => "".to_string(),
+    }
+}
+
+fn get_full_line_content(line_type: &LineType, line: &str) -> String {
+     match line_type {
+        LineType::Text => format!("<p>{}</p>\n", line.trim()),
+        LineType::Blank => "<br/>\n".to_string(),
+        LineType::Link => format!("<div><a href=\"{}\">{}</a></div>\n", get_link_address(line), get_link_content(line)),
+        LineType::Heading1 => format!("<h1>{}</h1>\n", line[1..].trim()),
+        LineType::Heading2 => format!("<h2>{}</h2>\n", line[2..].trim()),
+        LineType::Heading3 => format!("<h3>{}</h3>\n", line[3..].trim()),
+        _ => "".to_string(),
+    }
+}
+
+fn get_line_opener(line_type: &LineType) -> &'static str {
+    match line_type {
+        LineType::ListItem => "<ul>",
+        LineType::Quote => "<blockquote>",
+        LineType::PreformattedText => "<pre>",
+        _ => "",
+    }
+}
+
+fn get_line_closer(line_type: &LineType) -> &'static str {
+    match line_type {
+        LineType::ListItem => "</ul>\n",
+        LineType::Quote => "</blockquote>\n",
+        LineType::PreformattedText => "</pre>\n",
+        _ => "",
+    }
+}
+
+fn get_link_content(line: &str) -> &str {
+    let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect();
+    if components.len() > 1 {
+        return components[1].trim()
+    }
+    components[0].trim()
+}
+
+fn get_link_address(line: &str) -> &str {
+    let components: Vec<&str> = line[2..].trim().splitn(2, " ").collect();
+    components[0].trim()
+}
+
+fn identify_line(line: &str, is_preformatted: bool) -> LineType {
+    if line.starts_with("```") {
+        return LineType::PreformattedToggle;
+    }
+    if is_preformatted {
+        return LineType::PreformattedText;
+    }
+    if line.is_empty() {
+        return LineType::Blank;
+    }
+    if line.starts_with("=>") {
+        return LineType::Link;
+    }
+    if line.starts_with("* ") {
+        return LineType::ListItem;
+    }
+    if line.starts_with(">") {
+        return LineType::Quote;
+    }
+    if line.starts_with("###") {
+        return LineType::Heading3;
+    }
+    if line.starts_with("##") {
+        return LineType::Heading2;
+    }
+    if line.starts_with("#") {
+        return LineType::Heading1;
+    }
+
+    LineType::Text
+}
+
+#[derive(PartialEq, Eq)]
+enum LineType {
+    Text,
+    Blank,
+    Link,
+    PreformattedToggle,
+    PreformattedText,
+    Heading1,
+    Heading2,
+    Heading3,
+    ListItem,
+    Quote
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644 (file)
index 0000000..aa3fb93
--- /dev/null
@@ -0,0 +1,9 @@
+mod gemini_parser;
+
+use crate::gemini_parser::parse;
+
+fn main() {
+    let gemini_source = "# Test\n## 2nd H\na line\n another line\n```\npreformat\n=> preformat\n```\n=> http://lol.com\n=> http://lol.com lol\n* lol\nbla\n* lol\n* lmao\n> blabla\n> blabla";
+    let html = parse(gemini_source);
+    println!("{}", html)
+}