use harper_brill::UPOS;
use crate::CharStringExt;
use crate::expr::Expr;
use crate::expr::SequenceExpr;
use crate::linting::expr_linter::Chunk;
use crate::{
Token,
dict_word_metadata::Person,
linting::{ExprLinter, Lint, LintKind, Suggestion},
patterns::WordSet,
};
pub struct NominalWants {
expr: SequenceExpr,
}
impl Default for NominalWants {
fn default() -> Self {
fn is_applicable_pronoun(tok: &Token, src: &[char]) -> bool {
if tok.kind.is_pronoun() && tok.kind.is_upos(UPOS::PRON) {
let pron = tok.get_ch(src);
!pron.eq_any_ignore_ascii_case_chars(&[
&['t', 'h', 'a', 't'],
&['m', 'e'],
&['u', 's'],
&['h', 'i', 'm'],
&['h', 'e', 'r'],
&['i', 't'],
&['t', 'h', 'e', 'm'],
&['w', 'h', 'o'],
])
} else {
false
}
}
let miss = WordSet::new(&["wont", "wonts", "want", "wants"]);
let pattern = SequenceExpr::with(is_applicable_pronoun)
.then_whitespace()
.then(miss);
Self { expr: pattern }
}
}
impl ExprLinter for NominalWants {
type Unit = Chunk;
fn expr(&self) -> &dyn Expr {
&self.expr
}
fn match_to_lint(&self, toks: &[Token], source: &[char]) -> Option<Lint> {
let subject = toks.first()?;
let offender = &toks.last()?;
let plural = subject.kind.is_plural_nominal();
let person = subject
.kind
.as_word()
.unwrap()
.clone()
.unwrap()
.pronoun
.and_then(|p| p.person)
.unwrap_or(Person::Third);
let replacement = if person == Person::Third {
if plural { "want" } else { "wants" }
} else {
"want"
};
let replacement_chars: Vec<char> = replacement.chars().collect();
let offender_span = offender.span;
let offender_chars = offender_span.get_content(source);
if offender_chars.eq_ch(&replacement_chars) {
return None;
}
Some(Lint {
span: offender_span,
lint_kind: LintKind::Miscellaneous,
suggestions: vec![Suggestion::replace_with_match_case(
replacement_chars,
offender_chars,
)],
message: format!("Did you mean `{replacement}`?"),
priority: 55,
})
}
fn description(&self) -> &str {
"Ensures you use the correct `want` / `wants` after a nominal."
}
}
#[cfg(test)]
mod tests {
use super::NominalWants;
use crate::linting::tests::{assert_lint_count, assert_no_lints, assert_suggestion_result};
#[test]
fn fixes_he_wonts() {
assert_suggestion_result(
"He wonts to join us.",
NominalWants::default(),
"He wants to join us.",
);
}
#[test]
#[ignore = "This is not a grammar error if the previous word is `help`, `let`, or `make`."]
fn fixes_it_wont() {
assert_suggestion_result(
"It wont to move forward.",
NominalWants::default(),
"It wants to move forward.",
);
}
#[test]
fn fixes_she_wont() {
assert_suggestion_result(
"She wont to leave early.",
NominalWants::default(),
"She wants to leave early.",
);
}
#[test]
fn fixes_i_wont() {
assert_suggestion_result(
"I wonts to leave early.",
NominalWants::default(),
"I want to leave early.",
);
}
#[test]
fn allows_you_want() {
assert_lint_count("What size do you want to be?", NominalWants::default(), 0);
}
#[test]
fn fixes_you_wants() {
assert_suggestion_result(
"What do you wants?",
NominalWants::default(),
"What do you want?",
);
}
#[test]
fn ignores_correct_usage_they() {
assert_lint_count("They want to help.", NominalWants::default(), 0);
}
#[test]
fn ignores_correct_usage_he() {
assert_lint_count("He wants to help.", NominalWants::default(), 0);
}
#[test]
fn ignores_correct_usage_that_1298() {
assert_lint_count(
"The projects that want to take it seriously are the best.",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_make_me() {
assert_lint_count(
"Take another person code make me want to die.",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_makes_me() {
assert_lint_count(
"It makes me want to not use GitHub at all.",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_make_us() {
assert_lint_count(
"... try harder to make us want to implement it.",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_made_us() {
assert_lint_count(
"This change made us want to adopt luxon's strict mode",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_help_us() {
assert_lint_count("... help us want to help you.", NominalWants::default(), 0);
}
#[test]
fn ignores_correct_usage_make_you() {
assert_lint_count(
"I can certainly see why that would make you want to ditch Linux packaging.",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_makes_you() {
assert_lint_count(
"If something happens that makes you want to scream from the top of your lungs",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_made_you() {
assert_lint_count(
"What made you want to leave the LibFuzzer ...",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_make_him() {
assert_lint_count(
"make him want to help with your issue",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_make_her() {
assert_lint_count(
"... and make her want to get into coding.",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_make_it() {
assert_lint_count(
"you just make it want to appear as a drama",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_makes_it() {
assert_lint_count(
"using UHD makes it want to put labels in the corner saying UHD",
NominalWants::default(),
0,
);
}
#[test]
fn ignores_correct_usage_make_them() {
assert_lint_count(
"And make them want to believe in it.",
NominalWants::default(),
0,
)
}
#[test]
fn ignores_correct_usage_making_them() {
assert_lint_count(
"you're annoying ALMOST ALL of the users and making them want to switch to another ...",
NominalWants::default(),
0,
)
}
#[test]
fn ignores_correct_usage_help_them() {
assert_lint_count("And help them want to do it.", NominalWants::default(), 0)
}
#[test]
fn allows_want_to() {
assert_no_lints(
"Harper is a grammar checker for people who want to write fast.",
NominalWants::default(),
);
}
#[test]
fn test_2007() {
assert_no_lints(
"### 🙌 **We Want to Hear From You!**",
NominalWants::default(),
)
}
}