harper_core/patterns/
word.rs1use super::Pattern;
2
3use crate::{CharString, Token};
4
5#[derive(Clone)]
9pub struct Word {
10 word: CharString,
11 exact: bool,
12}
13
14impl Word {
15 pub fn new(word: &'static str) -> Self {
17 Self {
18 word: word.chars().collect(),
19 exact: false,
20 }
21 }
22 pub fn from_chars(word: &[char]) -> Self {
24 Self {
25 word: word.iter().copied().collect(),
26 exact: false,
27 }
28 }
29
30 pub fn new_exact(word: &'static str) -> Self {
32 Self {
33 word: word.chars().collect(),
34 exact: true,
35 }
36 }
37}
38
39impl Pattern for Word {
40 fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
41 let tok = tokens.first()?;
42 if !tok.kind.is_word() {
43 return None;
44 }
45 if tok.span.len() != self.word.len() {
46 return None;
47 }
48
49 let chars = tok.span.get_content(source);
50 let eq = if self.exact {
51 chars == self.word.as_slice()
52 } else {
53 chars
54 .iter()
55 .zip(&self.word)
56 .all(|(a, b)| a.eq_ignore_ascii_case(b))
57 };
58
59 if eq { Some(1) } else { None }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::{Document, Span, patterns::DocPattern};
66
67 use super::Word;
68
69 #[test]
70 fn fruit() {
71 let doc = Document::new_markdown_default_curated("I ate a banana and an apple today.");
72
73 assert_eq!(
74 Word::new("banana").find_all_matches_in_doc(&doc),
75 vec![Span::new(6, 7)]
76 );
77 assert_eq!(
78 Word::new_exact("banana").find_all_matches_in_doc(&doc),
79 vec![Span::new(6, 7)]
80 );
81 }
82
83 #[test]
84 fn fruit_whack_capitalization() {
85 let doc = Document::new_markdown_default_curated("I Ate A bAnaNa And aN apPlE today.");
86
87 assert_eq!(
88 Word::new("banana").find_all_matches_in_doc(&doc),
89 vec![Span::new(6, 7)]
90 );
91 assert_eq!(
92 Word::new_exact("banana").find_all_matches_in_doc(&doc),
93 vec![]
94 );
95 }
96}