panache_parser/parser/inlines/
strikeout.rs1use super::core::parse_inline_text;
12use crate::options::ParserOptions;
13use crate::syntax::SyntaxKind;
14use rowan::GreenNodeBuilder;
15
16pub fn try_parse_strikeout(text: &str) -> Option<(usize, &str)> {
19 let bytes = text.as_bytes();
20
21 if bytes.len() < 4 || bytes[0] != b'~' || bytes[1] != b'~' {
23 return None;
24 }
25
26 if bytes.get(2) == Some(&b'~') {
28 return None;
29 }
30
31 let mut pos = 2;
33 let mut found_close = false;
34
35 while pos + 1 < bytes.len() {
36 if bytes[pos] == b'~' && bytes[pos + 1] == b'~' {
37 if pos + 2 < bytes.len() && bytes[pos + 2] == b'~' {
39 pos += 1;
40 continue;
41 }
42
43 found_close = true;
44 break;
45 }
46 pos += 1;
47 }
48
49 if !found_close {
50 return None;
51 }
52
53 let content = &text[2..pos];
55
56 if content.trim().is_empty() {
58 return None;
59 }
60
61 if content.starts_with(char::is_whitespace) || content.ends_with(char::is_whitespace) {
63 return None;
64 }
65
66 let total_len = pos + 2; Some((total_len, content))
68}
69
70pub fn emit_strikeout(
72 builder: &mut GreenNodeBuilder,
73 inner_text: &str,
74 config: &ParserOptions,
75 suppress_footnote_refs: bool,
76) {
77 builder.start_node(SyntaxKind::STRIKEOUT.into());
78
79 builder.start_node(SyntaxKind::STRIKEOUT_MARKER.into());
81 builder.token(SyntaxKind::STRIKEOUT_MARKER.into(), "~~");
82 builder.finish_node();
83
84 parse_inline_text(builder, inner_text, config, false, suppress_footnote_refs);
86
87 builder.start_node(SyntaxKind::STRIKEOUT_MARKER.into());
89 builder.token(SyntaxKind::STRIKEOUT_MARKER.into(), "~~");
90 builder.finish_node();
91
92 builder.finish_node();
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_simple_strikeout() {
101 assert_eq!(try_parse_strikeout("~~hello~~"), Some((9, "hello")));
102 }
103
104 #[test]
105 fn test_strikeout_with_spaces() {
106 assert_eq!(
107 try_parse_strikeout("~~hello world~~"),
108 Some((15, "hello world"))
109 );
110 }
111
112 #[test]
113 fn test_no_whitespace_inside_delimiters() {
114 assert_eq!(try_parse_strikeout("~~ hello~~"), None);
116
117 assert_eq!(try_parse_strikeout("~~hello ~~"), None);
119 }
120
121 #[test]
122 fn test_empty_content() {
123 assert_eq!(try_parse_strikeout("~~~~"), None);
124 assert_eq!(try_parse_strikeout("~~ ~~"), None);
125 }
126
127 #[test]
128 fn test_not_enough_tildes() {
129 assert_eq!(try_parse_strikeout("~hello~"), None);
130 }
131
132 #[test]
133 fn test_too_many_tildes() {
134 assert_eq!(try_parse_strikeout("~~~hello~~~"), None);
136 }
137
138 #[test]
139 fn test_no_closing() {
140 assert_eq!(try_parse_strikeout("~~hello"), None);
141 assert_eq!(try_parse_strikeout("~~hello world"), None);
142 }
143
144 #[test]
145 fn test_strikeout_with_other_content_after() {
146 assert_eq!(try_parse_strikeout("~~hello~~ world"), Some((9, "hello")));
147 }
148
149 #[test]
150 fn test_strikeout_in_middle() {
151 assert_eq!(try_parse_strikeout("~~text~~"), Some((8, "text")));
152 }
153}