diff --git a/src/syntax/content/parser.rs b/src/syntax/content/parser.rs index 55fbf68..29e23cd 100644 --- a/src/syntax/content/parser.rs +++ b/src/syntax/content/parser.rs @@ -51,9 +51,7 @@ fn lex(text: &str, map: LexMap, config: &Config) -> Vec { tokens.push(Token::Header(header)); continue; } else if Paragraph::probe(lexeme) { - log!( - "Probed {lexeme:#?} from Block::None -> Block::Paragraph" - ); + log!("Probed block context None -> Paragraph: {lexeme:?}"); state.context.block = Block::Paragraph; tokens.push(Token::Paragraph(Paragraph::new(true))); } @@ -68,12 +66,8 @@ fn lex(text: &str, map: LexMap, config: &Config) -> Vec { continue; }, Block::Paragraph => { - if lexeme.text() == "\n" - && matches!(state.context.inline, Inline::None) - { - log!( - "Probed {lexeme:#?} from Block::Paragraph -> Block::None" - ); + if Paragraph::probe_end(lexeme) { + log!("Probed block context Paragraph -> None: {lexeme:?}"); tokens.push(Token::Paragraph(Paragraph::new(false))); state.context.block = Block::None; } @@ -357,8 +351,7 @@ mod tests { read_noconfig("\n|SomeAnchor|\n"), concat!( "\n", - r#"

SomeAnchor

"#, - "\n" + r#"

SomeAnchor

"# ), ); } @@ -368,10 +361,9 @@ mod tests { assert_eq!( read_noconfig("|SomeAnchor|\n|SomeOtherAnchor|\n"), concat!( - r#"

SomeAnchor

"#, + r#"

SomeAnchor"#, "\n", - r#"

SomeOtherAnchor

"#, - "\n" + r#"SomeOtherAnchor

"# ) ); } @@ -384,18 +376,53 @@ mod tests { r#"

SomeAnchor

"#, "\n", "\n", - r#"

SomeOtherAnchor

"#, - "\n", + r#"

SomeOtherAnchor

"# ), ); } + #[test] + fn homepage_footer() { + assert_eq!( + read_noconfig( + "made by jutty|https://jutty.dev • acknowledgments|Acknowledgments • |source code|https://codeberg.org/jutty/en" + ), + r#"

made by juttyacknowledgmentssource code

"# + ); + } + + #[test] + fn trailing_anchor() { + assert_eq!( + read_noconfig("see acks|acks"), + r#"

see acks

"# + ); + } + + #[test] + fn trailing_anchor_with_newline() { + assert_eq!( + read_noconfig("\nsee acks|acks\n"), + concat!("\n", r#"

see acks

"#) + ); + } + + #[test] + fn trailing_oblique() { + assert_eq!(read_noconfig("see _acks_"), "

see acks

"); + } + + #[test] + fn trailing_oblique_with_newline() { + assert_eq!(read_noconfig("see _acks_\n"), "

see acks

"); + } + #[test] fn pre() { let payload = "D0qdJ184f3q1okbYu3Xm1d93jj6jy615"; assert_eq!( read_noconfig(&format!("`\n{payload}\n`\n")), - format!("
\n{payload}\n
\n"), + format!("
\n{payload}\n
"), ); } diff --git a/src/syntax/content/parser/context.rs b/src/syntax/content/parser/context.rs index 542e51c..a69d66c 100644 --- a/src/syntax/content/parser/context.rs +++ b/src/syntax/content/parser/context.rs @@ -1,6 +1,6 @@ use crate::syntax::content::parser::{ - token::{Token, paragraph::Paragraph, preformat::PreFormat}, State, + token::{Token, paragraph::Paragraph, preformat::PreFormat}, }; pub mod anchor; diff --git a/src/syntax/content/parser/context/anchor.rs b/src/syntax/content/parser/context/anchor.rs index 2fecad3..d35265d 100644 --- a/src/syntax/content/parser/context/anchor.rs +++ b/src/syntax/content/parser/context/anchor.rs @@ -57,6 +57,7 @@ pub fn parse( ); // Conditions in this decision tree should match the destination end + // or some intermediary state necessary to finding it if lexeme.match_as_char('s') && lexeme.is_next_boundary() && !lexeme.match_next_as_char('|') @@ -80,7 +81,7 @@ pub fn parse( state.context.inline = Inline::None; return true; } else if lexeme.match_as_char('|') && !candidate.balanced { - log!("Found a pipe, but no boundary: Destination likely follows"); + log!("State: Found a pipe, but no boundary: destination follows"); candidate.balanced = true; return true; } else if lexeme.match_as_char('|') { @@ -96,12 +97,13 @@ pub fn parse( tokens.push(Token::Anchor(candidate.clone())); state.context.inline = Inline::None; return false; - } else if lexeme.is_whitespace() { - log!("End: Whitespace"); + } else if lexeme.is_next_whitespace() { + log!("End: next is whitespace"); + buffer.destination.push_str(&lexeme.text()); candidate.destination = Some(buffer.destination.clone()); tokens.push(Token::Anchor(candidate.clone())); state.context.inline = Inline::None; - return false; + return true; // This else branch is the 'no end found yet' state and will keep // pushing lexemes into the buffer until an end is found above @@ -137,3 +139,32 @@ pub fn parse( state.context.inline = Inline::None; false } + +#[cfg(test)] +mod tests { + use crate::{syntax::content::parser, types::Graph}; + + fn read_noconfig(input: &str) -> String { + parser::read(input, &Graph::new(None).meta.config) + } + + #[test] + fn indifferent_trailing_pipe() { + assert_eq!(read_noconfig("|a|a|"), read_noconfig("a|a|")); + } + + #[test] + fn indifferent_leading_pipe() { + assert_eq!(read_noconfig("|a|a|"), read_noconfig("|a|a")); + } + + #[test] + fn indifferent_multiline_trailing_pipe() { + assert_eq!(read_noconfig("|a|a|\nn"), read_noconfig("a|a|\nn")); + } + + #[test] + fn indifferent_multiline_leading_pipe() { + assert_eq!(read_noconfig("|a|a|\nn"), read_noconfig("|a|a\nn")); + } +} diff --git a/src/syntax/content/parser/token/linebreak.rs b/src/syntax/content/parser/token/linebreak.rs index 2341384..e9209f8 100644 --- a/src/syntax/content/parser/token/linebreak.rs +++ b/src/syntax/content/parser/token/linebreak.rs @@ -2,12 +2,12 @@ use crate::{ syntax::content::{Parseable, parser::lexeme::Lexeme}, }; -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Default, Debug, Clone, Eq, PartialEq)] pub struct LineBreak {} impl Parseable for LineBreak { fn probe(lexeme: &Lexeme) -> bool { - lexeme.text() == "\n" + lexeme.text() == "\n" && !lexeme.last() } fn lex(_lexeme: &Lexeme) -> LineBreak { diff --git a/src/syntax/content/parser/token/literal.rs b/src/syntax/content/parser/token/literal.rs index d311633..85f12ab 100644 --- a/src/syntax/content/parser/token/literal.rs +++ b/src/syntax/content/parser/token/literal.rs @@ -6,8 +6,8 @@ pub struct Literal { } impl Parseable for Literal { - fn probe(_lexeme: &Lexeme) -> bool { - true + fn probe(lexeme: &Lexeme) -> bool { + !(lexeme.last() && lexeme.is_whitespace()) } fn lex(lexeme: &Lexeme) -> Literal { diff --git a/src/syntax/content/parser/token/paragraph.rs b/src/syntax/content/parser/token/paragraph.rs index b0def3d..bf46b28 100644 --- a/src/syntax/content/parser/token/paragraph.rs +++ b/src/syntax/content/parser/token/paragraph.rs @@ -9,6 +9,10 @@ impl Paragraph { pub fn new(open: bool) -> Paragraph { Paragraph { open: Some(open) } } + + pub fn probe_end(lexeme: &Lexeme) -> bool { + lexeme.match_as_char('\n') && lexeme.match_next_as_char('\n') + } } impl Parseable for Paragraph {