From 6b34bb453149325fb652915224de2c454cb480f5 Mon Sep 17 00:00:00 2001 From: jutty Date: Sun, 21 Dec 2025 14:51:49 -0300 Subject: [PATCH] Fix an anchor clustering corner case --- src/syntax/content/parser/cluster.rs | 75 ++++++++++++++++++---------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/src/syntax/content/parser/cluster.rs b/src/syntax/content/parser/cluster.rs index 24462eb..8cb6f47 100644 --- a/src/syntax/content/parser/cluster.rs +++ b/src/syntax/content/parser/cluster.rs @@ -24,11 +24,34 @@ pub fn cluster(text: &str) -> Vec { } let Some(delimiter) = delimiter::match_delimiter(&word) else { - log!("Skip: {word:?} does not start with a delimiter"); + log!("Skip: {word:?} does not have a delimiter"); clusters.push(word); continue; }; + if !delimiter.leading && !word.starts_with(delimiter.char) { + clusters.push(word); + continue; + } + + if (!delimiter.greedy + && !delimiter.triple + && word.matches(delimiter.char).count() == 2) + || (delimiter.triple + && (2..=3).contains(&word.matches(delimiter.char).count())) + { + log!("Skip: {word:?} is almost atomic, but must be split"); + match word.rsplit_once(delimiter.char) { + Some((head, tail)) => { + log!("Pushing head {head:?}, tail {tail:?} into clusters"); + clusters.push(format!("{head}{}", delimiter.char)); + clusters.push(tail.to_string()); + continue; + }, + None => unreachable!(), + } + } + if let Some(next) = iterator.peek() && next == "\n" && delimiter.greedy @@ -46,23 +69,6 @@ pub fn cluster(text: &str) -> Vec { continue; } - if (!delimiter.greedy - && !delimiter.triple - && word.matches(delimiter.char).count() == 2) - || (delimiter.triple && word.matches(delimiter.char).count() == 3) - { - log!("Skip: {word:?} is almost atomic, but must be split"); - match word.rsplit_once(delimiter.char) { - Some((head, tail)) => { - log!("Pushing head {head:?}, tail {tail:?} into clusters"); - clusters.push(format!("{head}{}", delimiter.char)); - clusters.push(tail.to_string()); - continue; - }, - None => unreachable!(), - } - } - log!("Found cluster from {delimiter:?} in {word:?}"); let mut parts: Vec = vec![word.clone()]; log!("Seeking from a base of {parts:?}"); @@ -138,30 +144,49 @@ mod delimiter { pub string: String, pub greedy: bool, pub triple: bool, + pub leading: bool, } - fn make_delimiters() -> Vec { - vec![ + fn make_delimiters() -> (Vec, Vec) { + let delimiters = [ Delimiter { char: '|', string: "|".to_string(), greedy: true, triple: true, + leading: false, }, Delimiter { char: '`', string: "`".to_string(), greedy: false, triple: false, + leading: true, }, - ] + ]; + + ( + delimiters.iter().filter(|d| d.leading).cloned().collect(), + delimiters.iter().filter(|d| !d.leading).cloned().collect(), + ) } pub fn match_delimiter(word: &str) -> Option { + let (leading, nonleading) = make_delimiters(); + let first_char = word.chars().next()?; - make_delimiters() - .iter() - .find(|d| d.char == first_char) - .cloned() + + if let Some(leading_match) = + leading.iter().find(|d| d.char == first_char).cloned() + { + Some(leading_match) + } else { + for delimiter in nonleading { + if word.contains(delimiter.char) { + return Some(delimiter); + } + } + None + } } }