]> git.r.bdr.sh - rbdr/page/commitdiff
Wrap headings, fix empty lines 1.2.0
authorRuben Beltran del Rio <redacted>
Fri, 6 Oct 2023 21:55:04 +0000 (23:55 +0200)
committerRuben Beltran del Rio <redacted>
Fri, 6 Oct 2023 21:55:04 +0000 (23:55 +0200)
Cargo.lock
Cargo.toml
src/gemini_parser.rs

index e75fffbe49d602ddabd0c6c94b2a64ed7ac65242..2a9b116404e78e904bea127f5aaddc73e028a636 100644 (file)
@@ -4,4 +4,4 @@ version = 3
 
 [[package]]
 name = "page"
-version = "1.1.0"
+version = "1.2.0"
index ca22de13efc46a2d5bfa1adf5e9b84fb1ecac953..7ddba562adb74e2e0496c18dbbf7dbe35a9c5669 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "page"
-version = "1.1.0"
+version = "1.2.0"
 edition = "2021"
 
 [dependencies]
index d0715f102246aef12dbeade159c285b9d856ccd8..e63ebd30344dccdfe22e06eaeba3f0cb4fefd2de 100644 (file)
@@ -6,8 +6,9 @@ pub fn parse(source: &str) -> String {
     let mut html:String = "".to_owned();
     let mut current_line_type: Option<LineType> = None;
 
+    let mut heading_stack: Vec<u8> = Vec::new();
     for line in lines {
-        let mut line_type = LineType::Text;
+        let mut line_type = LineType::Blank;
         if line.char_indices().count() > 2 {
             let mut end = line.len();
             if line.char_indices().count() > 3 {
@@ -38,8 +39,8 @@ pub fn parse(source: &str) -> String {
                     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);
+                    html.push_str(&get_heading_wrapper(&mut heading_stack, &line_type));
+                    html.push_str(&get_full_line_content(&line_type, line));
                 }
                 current_line_type = Some(line_type);
             },
@@ -50,30 +51,31 @@ pub fn parse(source: &str) -> String {
             html.push_str(get_line_closer(line));
         }
     }
+    html.push_str(&close_heading_wrapper(&mut heading_stack));
     html
 }
 
 fn is_block(line_type: &LineType) -> bool {
     return match line_type {
-        LineType::PreformattedText => true,
-        LineType::ListItem => true,
-        LineType::Quote => true,
+        LineType::PreformattedText | LineType::ListItem | LineType::Quote => true,
         _ => false,
     }
 }
 
 fn get_partial_line_content(line_type: &LineType, line: &str) -> String {
+    let encoded_line = line.replace("<", "&lt;").replace(">", "&gt;");
     return match line_type {
-        LineType::ListItem => format!("<li>{}</li>", line[2..].trim()),
-        LineType::Quote => line[1..].trim().to_string(),
-        LineType::PreformattedText => format!("{}\n", line),
+        LineType::ListItem => format!("<li>{}</li>", encoded_line[2..].trim()),
+        LineType::Quote => encoded_line[1..].trim().to_string(),
+        LineType::PreformattedText => format!("{}\n", encoded_line),
         _ => "".to_string(),
     }
 }
 
 fn get_full_line_content(line_type: &LineType, line: &str) -> String {
+    let encoded_line = line.replace("<", "&lt;").replace(">", "&gt;");
      match line_type {
-        LineType::Text => format!("<p>{}</p>\n", line.trim()),
+        LineType::Text => format!("<p>{}</p>\n", encoded_line.trim()),
         LineType::Blank => "<br/>\n".to_string(),
         LineType::Link => {
             let url = get_link_address(line);
@@ -83,13 +85,52 @@ fn get_full_line_content(line_type: &LineType, line: &str) -> String {
                 format!("<div><a href=\"{}\">{}</a></div>\n", url.replace(".gmi", ".html"), 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()),
+        LineType::Heading1 => format!("<h1>{}</h1>\n", encoded_line[1..].trim()),
+        LineType::Heading2 => format!("<h2>{}</h2>\n", encoded_line[2..].trim()),
+        LineType::Heading3 => format!("<h3>{}</h3>\n", encoded_line[3..].trim()),
         _ => "".to_string(),
     }
 }
 
+fn get_heading_wrapper(heading_stack: &mut Vec<u8>, line_type: &LineType) -> String {
+    let mut string = String::new();
+    let current_heading: u8 = match line_type {
+        LineType::Heading1 => 1,
+        LineType::Heading2 => 2,
+        LineType::Heading3 => 3,
+        _ => 255
+    };
+
+    if current_heading < 255 {
+        while let Some(open_heading) = heading_stack.pop() {
+            // You just encountered a more important heading.
+            // Put it back. Desist.
+            if open_heading < current_heading {
+                heading_stack.push(open_heading);
+                break;
+            }
+
+            string.push_str("</div>");
+
+            if open_heading == current_heading {
+                break;
+            }
+        }
+        heading_stack.push(current_heading);
+        string.push_str(&format!("<div class=\"h{}\">", current_heading));
+    }
+
+    return string;
+}
+
+fn close_heading_wrapper(heading_stack: &mut Vec<u8>) -> String {
+    let mut string = String::new();
+    while let Some(_open_heading) = heading_stack.pop() {
+        string.push_str("</div>");
+    }
+    return string;
+}
+
 fn get_line_opener(line_type: &LineType) -> &'static str {
     match line_type {
         LineType::ListItem => "<ul>",