/// Strip inline code (backtick) and fenced code blocks, replacing with spaces. pub fn strip_code_spans(input: &str) -> String { let mut out = String::with_capacity(input.len()); let mut chars = input.chars().peekable(); while let Some(ch) = chars.next() { if ch == '`' { let mut tick_count = 1; while chars.peek() == Some(&'`') { tick_count += 1; chars.next(); } let mut skipped = 0; while let Some(c) = chars.next() { skipped += 1; if c == '`' { let mut close_count = 1; while chars.peek() == Some(&'`') { close_count += 1; chars.next(); } if close_count == tick_count { break; } } } let total = tick_count * 2 + skipped; for _ in 0..total { out.push(' '); } } else { out.push(ch); } } out } /// Return byte ranges of inline code spans and fenced code blocks. pub fn code_span_ranges(input: &str) -> Vec<(usize, usize)> { let mut ranges = Vec::new(); let bytes = input.as_bytes(); let len = bytes.len(); let mut i = 0; while i < len { if bytes[i] == b'`' { let start = i; let mut tick_count = 0; while i < len && bytes[i] == b'`' { tick_count += 1; i += 1; } let mut found = false; while i < len { if bytes[i] == b'`' { let mut close_count = 0; while i < len && bytes[i] == b'`' { close_count += 1; i += 1; } if close_count == tick_count { ranges.push((start, i)); found = true; break; } } else { i += 1; } } if !found { ranges.push((start, len)); } } else { i += 1; } } ranges } #[cfg(test)] mod tests { use super::*; #[test] fn strip_inline_code() { let result = strip_code_spans("hello `code` world"); assert!(!result.contains("code")); assert!(result.contains("hello")); assert!(result.contains("world")); } #[test] fn strip_fenced_code() { let result = strip_code_spans("text\n```\ncode block\n```\nmore"); assert!(!result.contains("code block")); assert!(result.contains("text")); assert!(result.contains("more")); } #[test] fn ranges_inline_code() { let input = "hello `code` world"; let ranges = code_span_ranges(input); assert_eq!(ranges.len(), 1); let (start, end) = ranges[0]; assert_eq!(&input[start..end], "`code`"); } #[test] fn ranges_fenced_code() { let input = "text\n```\ncode\n```\nmore"; let ranges = code_span_ranges(input); assert_eq!(ranges.len(), 1); let (start, end) = ranges[0]; assert!(input[start..end].starts_with("```")); assert!(input[start..end].ends_with("```")); } #[test] fn ranges_unclosed_backtick() { let input = "hello `unclosed"; let ranges = code_span_ranges(input); assert_eq!(ranges.len(), 1); assert_eq!(ranges[0], (6, input.len())); } #[test] fn no_code_spans() { assert!(code_span_ranges("no code here").is_empty()); assert_eq!(strip_code_spans("no code here"), "no code here"); } }