| 83 | type Item = (usize, &'a str); |
| 84 | |
| 85 | fn next(&mut self) -> Option<Self::Item> { |
| 86 | let bytes = self.text.as_bytes(); |
| 87 | // Skip non-word characters. |
| 88 | while self.pos < bytes.len() { |
| 89 | let c = self.text[self.pos..].chars().next()?; |
| 90 | if c.is_alphanumeric() || c == '-' || c == '_' { |
| 91 | break; |
| 92 | } |
| 93 | self.pos += c.len_utf8(); |
| 94 | } |
| 95 | if self.pos >= bytes.len() { |
| 96 | return None; |
| 97 | } |
| 98 | |
| 99 | let start = self.pos; |
| 100 | // Consume word characters. |
| 101 | while self.pos < bytes.len() { |
| 102 | let Some(c) = self.text[self.pos..].chars().next() else { |
| 103 | break; |
| 104 | }; |
| 105 | if c.is_alphanumeric() || c == '-' || c == '_' { |
| 106 | self.pos += c.len_utf8(); |
| 107 | } else { |
| 108 | break; |
| 109 | } |
| 110 | } |
| 111 | let word = &self.text[start..self.pos]; |
| 112 | let trimmed_start = start + word.len() - word.trim_start_matches(['-', '_']).len(); |
| 113 | let trimmed_end = trimmed_start + word.trim_matches(['-', '_']).len(); |
| 114 | if trimmed_start >= trimmed_end { |
| 115 | return self.next(); |
| 116 | } |
| 117 | Some((trimmed_start, &self.text[trimmed_start..trimmed_end])) |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | #[cfg(test)] |