harper_core/linting/
initialism_linter.rs1use crate::expr::Expr;
2use itertools::Itertools;
3
4use crate::{Token, patterns::Word};
5
6use super::{ExprLinter, Lint, LintKind, Suggestion};
7use crate::linting::expr_linter::Chunk;
8
9pub struct InitialismLinter {
12 expr: Box<dyn Expr>,
13 expansion_lower: Vec<Vec<char>>,
15}
16
17impl InitialismLinter {
18 pub fn new(initialism: &str, expansion: &str) -> Self {
20 let expansion_lower = expansion
21 .split(' ')
22 .map(|s| s.chars().map(|v| v.to_ascii_lowercase()).collect())
23 .collect();
24
25 Self {
26 expr: Box::new(Word::from_char_string(initialism.chars().collect())),
27 expansion_lower,
28 }
29 }
30}
31
32impl ExprLinter for InitialismLinter {
33 type Unit = Chunk;
34
35 fn expr(&self) -> &dyn Expr {
36 self.expr.as_ref()
37 }
38
39 fn match_to_lint(&self, matched_tokens: &[Token], source: &[char]) -> Option<Lint> {
40 let tok = matched_tokens.first()?;
41 let source = tok.span.get_content(source);
42
43 let mut expansion_lower = self.expansion_lower.to_owned();
44 let first_letter = &mut expansion_lower[0][0];
45
46 *first_letter = if source[0].is_ascii_uppercase() {
47 first_letter.to_ascii_uppercase()
48 } else {
49 first_letter.to_ascii_lowercase()
50 };
51
52 let phrase = Itertools::intersperse_with(expansion_lower.into_iter(), || vec![' '])
53 .reduce(|mut left, mut right| {
54 left.append(&mut right);
55 left
56 })
57 .unwrap();
58
59 Some(Lint {
60 span: tok.span,
61 lint_kind: LintKind::Miscellaneous,
62 suggestions: vec![Suggestion::ReplaceWith(phrase)],
63 message: "Try expanding this initialism.".to_owned(),
64 priority: 127,
65 })
66 }
67
68 fn description(&self) -> &'static str {
69 "Expands an initialism."
70 }
71}
72
73#[cfg(test)]
74mod tests {}