use crate::words::{at, before, is_ws};
fn run_length(s: &[char], from: usize) -> usize {
match at(s, from) {
Some(ch @ ('*' | '_')) => {
let mut j = from;
while at(s, j) == Some(ch) {
j += 1;
}
j - from
}
_ => 0,
}
}
pub(crate) fn emphasis_run(s: &[char], from: usize) -> usize {
let n = run_length(s, from);
if n <= 2 {
n
} else {
0
}
}
fn is_outer(ch: Option<char>) -> bool {
ch.map_or(true, |c| is_ws(c) || matches!(c, '[' | ']' | '(' | ')' | '*' | '_'))
}
fn is_inner(ch: Option<char>) -> bool {
ch.is_some_and(|c| !is_ws(c))
}
fn stack_of(ch: Option<char>, len: usize) -> Option<usize> {
match (ch, len) {
(Some('*'), 1) => Some(0),
(Some('*'), 2) => Some(1),
(Some('_'), 1) => Some(2),
(Some('_'), 2) => Some(3),
_ => None,
}
}
fn mark(marked: &mut [bool], from: usize, len: usize) {
for slot in marked.iter_mut().skip(from).take(len) {
*slot = true;
}
}
pub(crate) fn without_markers(raw: &[char], from: usize, open: Option<char>) -> String {
let mut marked = vec![false; raw.len()];
let mut stacks: [Vec<usize>; 4] = [Vec::new(), Vec::new(), Vec::new(), Vec::new()];
let mut i = from;
while i < raw.len() {
let len = run_length(raw, i).max(1);
let own = stack_of(at(raw, i), len);
let prev = before(raw, i);
let next = at(raw, i + len);
let opener = match own {
Some(o) if is_inner(prev) && is_outer(next) => stacks.get_mut(o).and_then(Vec::pop),
_ => None,
};
if let Some(a) = opener {
mark(&mut marked, a, len);
mark(&mut marked, i, len);
for st in stacks.iter_mut() {
while st.last().is_some_and(|&top| top > a) {
st.pop();
}
}
} else if let Some(o) = own {
if is_outer(prev) && is_inner(next) {
if let Some(st) = stacks.get_mut(o) {
st.push(i);
}
}
}
i += len;
}
if let Some(open) = open {
let mut end = raw.len();
while end > from && before(raw, end).is_some_and(is_ws) {
end -= 1;
}
let mut start = end;
while start > from && before(raw, start) == Some(open) {
start -= 1;
}
if end - start <= 2 && start > from && is_inner(before(raw, start)) {
for slot in marked.iter_mut().take(end).skip(start) {
if *slot {
break;
}
*slot = true;
}
}
}
raw.iter().zip(&marked).skip(from).filter(|(_, m)| !**m).map(|(c, _)| *c).collect()
}