From: Ruben Beltran del Rio Date: Thu, 13 Apr 2023 19:56:38 +0000 (+0200) Subject: Add a gemini parser X-Git-Tag: 1.0.0~13 X-Git-Url: https://git.r.bdr.sh/rbdr/page/commitdiff_plain/8d4fac527ea33456de21933b4632a5bf4abbfc8d?ds=sidebyside Add a gemini parser --- 8d4fac527ea33456de21933b4632a5bf4abbfc8d diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..40f6366 --- /dev/null +++ b/Cargo.lock @@ -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 index 0000000..33b0c29 --- /dev/null +++ b/Cargo.toml @@ -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 index 0000000..36abb16 --- /dev/null +++ b/src/gemini_parser.rs @@ -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 = 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) = ¤t_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) = ¤t_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) = ¤t_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!("
  • {}
  • ", 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!("

    {}

    \n", line.trim()), + LineType::Blank => "
    \n".to_string(), + LineType::Link => format!("
    {}
    \n", get_link_address(line), get_link_content(line)), + LineType::Heading1 => format!("

    {}

    \n", line[1..].trim()), + LineType::Heading2 => format!("

    {}

    \n", line[2..].trim()), + LineType::Heading3 => format!("

    {}

    \n", line[3..].trim()), + _ => "".to_string(), + } +} + +fn get_line_opener(line_type: &LineType) -> &'static str { + match line_type { + LineType::ListItem => "\n", + LineType::Quote => "\n", + LineType::PreformattedText => "\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 index 0000000..aa3fb93 --- /dev/null +++ b/src/main.rs @@ -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) +}