#[derive(Debug, Clone, Default)]
pub struct Fence(Option<(char, usize)>);
impl Fence {
pub fn step(&mut self, line: &str) -> bool {
let t = line.trim_start();
let run = |ch: char| t.chars().take_while(|c| *c == ch).count();
match self.0 {
Some((ch, n)) => {
let m = run(ch);
if m >= n && t[m * ch.len_utf8()..].trim().is_empty() {
self.0 = None;
return true;
}
false
}
None => {
for ch in ['`', '~'] {
let n = run(ch);
if n >= 3 && !(ch == '`' && t[n..].contains('`')) {
self.0 = Some((ch, n));
return true;
}
}
false
}
}
}
pub fn inside(&self) -> bool {
self.0.is_some()
}
}
pub fn atx(line: &str) -> Option<(usize, &str)> {
let indent = line.len() - line.trim_start_matches(' ').len();
if indent > 3 {
return None;
}
let t = &line[indent..];
let n = t.chars().take_while(|c| *c == '#').count();
let rest = &t[n..];
if !(1..=6).contains(&n) || !(rest.is_empty() || rest.starts_with([' ', '\t'])) {
return None;
}
let text = rest.trim();
let open = text.trim_end_matches('#');
let text = if open.is_empty() || open.ends_with([' ', '\t']) { open.trim_end() } else { text };
Some((n, text))
}