harper_core/linting/
initialism_linter.rs1use crate::expr::Expr;
2
3use crate::{Token, patterns::Word};
4
5use super::{ExprLinter, Lint, LintKind, Suggestion};
6use crate::linting::expr_linter::Chunk;
7
8type InitialismWord = Vec<char>;
10type InitialismPhrase = Vec<InitialismWord>;
12
13pub struct InitialismLinter {
16 expr: Word,
17 expansions_lower: Vec<InitialismPhrase>,
19}
20
21impl InitialismLinter {
22 pub fn new(initialism: &str, expansions: &[&str]) -> Self {
24 let expansions_lower = expansions
25 .iter()
26 .map(|expansion| {
27 expansion
28 .split(' ')
29 .map(|s| s.chars().map(|v| v.to_ascii_lowercase()).collect())
30 .collect()
31 })
32 .collect();
33
34 Self {
35 expr: Word::from_char_string(initialism.chars().collect()),
36 expansions_lower,
37 }
38 }
39}
40
41impl ExprLinter for InitialismLinter {
42 type Unit = Chunk;
43
44 fn expr(&self) -> &dyn Expr {
45 &self.expr
46 }
47
48 fn match_to_lint(&self, matched_tokens: &[Token], source: &[char]) -> Option<Lint> {
49 let tok = matched_tokens.first()?;
50 let source = tok.get_ch(source);
51
52 let suggestions = self
53 .expansions_lower
54 .iter()
55 .map(|expansion_lower| {
56 let mut expansion = expansion_lower.clone();
57 let first_letter = &mut expansion[0][0];
58 *first_letter = if source[0].is_ascii_uppercase() {
59 first_letter.to_ascii_uppercase()
60 } else {
61 first_letter.to_ascii_lowercase()
62 };
63 Suggestion::ReplaceWith(
64 expansion
65 .iter()
66 .flat_map(|word| std::iter::once(' ').chain(word.iter().copied()))
67 .skip(1)
68 .collect::<Vec<_>>(),
69 )
70 })
71 .collect::<Vec<_>>();
72
73 Some(Lint {
74 span: tok.span,
75 lint_kind: LintKind::Miscellaneous,
76 suggestions,
77 message: "Try expanding this initialism.".to_owned(),
78 priority: 127,
79 })
80 }
81
82 fn description(&self) -> &'static str {
83 "Expands an initialism."
84 }
85}
86
87#[cfg(test)]
88mod tests {}