use super::Span;
use nom::{
character::complete::char, combinator::recognize, multi::many1_count, IResult, Input, Parser,
};
pub fn code_span(input: Span) -> IResult<Span, Span> {
log::debug!("Parsing code span at: {:?}", input.fragment());
let (input, opening) = recognize(many1_count(char('`'))).parse(input)?;
let backtick_count = opening.fragment().len();
log::debug!("Found {} opening backticks", backtick_count);
let content_str = input.fragment();
let mut pos = 0;
while pos < content_str.len() {
if content_str.as_bytes()[pos] == b'`' {
let mut tick_count = 0;
let mut check_pos = pos;
while check_pos < content_str.len() && content_str.as_bytes()[check_pos] == b'`' {
tick_count += 1;
check_pos += 1;
}
if tick_count == backtick_count {
let content = input.take(pos);
let remaining = input.take_from(check_pos);
log::debug!("Code span content: {:?}", content.fragment());
return Ok((remaining, content));
}
pos = check_pos;
} else {
pos += 1;
}
}
Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::TakeUntil,
)))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn smoke_test_code_span_basic() {
let input = Span::new("`code` text");
let result = code_span(input);
assert!(result.is_ok());
let (_rest, content) = result.unwrap();
assert_eq!(*content.fragment(), "code");
assert_eq!(*_rest.fragment(), " text");
}
#[test]
fn smoke_test_code_span_double_backticks() {
let input = Span::new("``code with ` backtick`` text");
let result = code_span(input);
assert!(result.is_ok());
let (_rest, content) = result.unwrap();
assert_eq!(*content.fragment(), "code with ` backtick");
}
#[test]
fn smoke_test_code_span_triple_backticks() {
let input = Span::new("```code```");
let result = code_span(input);
assert!(result.is_ok());
let (_, content) = result.unwrap();
assert_eq!(*content.fragment(), "code");
}
#[test]
fn smoke_test_code_span_no_closing() {
let input = Span::new("`code without closing");
let result = code_span(input);
assert!(result.is_err());
}
#[test]
fn smoke_test_code_span_mismatched_backticks() {
let input = Span::new("`code`` text");
let result = code_span(input);
assert!(result.is_err()); }
#[test]
fn smoke_test_code_span_empty() {
let input = Span::new("` ` text"); let result = code_span(input);
assert!(result.is_ok());
let (_, content) = result.unwrap();
assert_eq!(*content.fragment(), " ");
}
#[test]
fn smoke_test_code_span_with_spaces() {
let input = Span::new("` code ` text");
let result = code_span(input);
assert!(result.is_ok());
let (_, content) = result.unwrap();
assert_eq!(*content.fragment(), " code ");
}
}