From: Ruben Beltran del Rio Date: Fri, 6 Oct 2023 21:55:04 +0000 (+0200) Subject: Wrap headings, fix empty lines X-Git-Tag: 1.2.0 X-Git-Url: https://git.r.bdr.sh/rbdr/page/commitdiff_plain/6a8515fe6ed81369badb51496699a2ff25dbfa9f?ds=inline Wrap headings, fix empty lines --- diff --git a/Cargo.lock b/Cargo.lock index e75fffb..2a9b116 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 3 [[package]] name = "page" -version = "1.1.0" +version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index ca22de1..7ddba56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "page" -version = "1.1.0" +version = "1.2.0" edition = "2021" [dependencies] diff --git a/src/gemini_parser.rs b/src/gemini_parser.rs index d0715f1..e63ebd3 100644 --- a/src/gemini_parser.rs +++ b/src/gemini_parser.rs @@ -6,8 +6,9 @@ pub fn parse(source: &str) -> String { let mut html:String = "".to_owned(); let mut current_line_type: Option = None; + let mut heading_stack: Vec = 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("<", "<").replace(">", ">"); return match line_type { - LineType::ListItem => format!("
  • {}
  • ", line[2..].trim()), - LineType::Quote => line[1..].trim().to_string(), - LineType::PreformattedText => format!("{}\n", line), + LineType::ListItem => format!("
  • {}
  • ", 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("<", "<").replace(">", ">"); match line_type { - LineType::Text => format!("

    {}

    \n", line.trim()), + LineType::Text => format!("

    {}

    \n", encoded_line.trim()), LineType::Blank => "
    \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!("
    {}
    \n", url.replace(".gmi", ".html"), 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()), + LineType::Heading1 => format!("

    {}

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

    {}

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

    {}

    \n", encoded_line[3..].trim()), _ => "".to_string(), } } +fn get_heading_wrapper(heading_stack: &mut Vec, 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(""); + + if open_heading == current_heading { + break; + } + } + heading_stack.push(current_heading); + string.push_str(&format!("
    ", current_heading)); + } + + return string; +} + +fn close_heading_wrapper(heading_stack: &mut Vec) -> String { + let mut string = String::new(); + while let Some(_open_heading) = heading_stack.pop() { + string.push_str("
    "); + } + return string; +} + fn get_line_opener(line_type: &LineType) -> &'static str { match line_type { LineType::ListItem => "
      ",