From 878404884c4bcbf60ff1ff6bd1ebbfb41c3f1e92 Mon Sep 17 00:00:00 2001 From: James Devenish Date: Sun, 2 Feb 2025 11:15:12 +1100 Subject: [PATCH] feat(core): matcher_spelling.rs and docs for matcher.rs (fix #558) --- harper-core/src/linting/lint_group.rs | 2 + harper-core/src/linting/matcher.rs | 54 ++++++++++++------- harper-core/src/linting/matcher_spelling.rs | 26 +++++++++ harper-core/src/linting/mod.rs | 2 + .../routes/docs/integrations/neovim/+page.md | 1 + 5 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 harper-core/src/linting/matcher_spelling.rs diff --git a/harper-core/src/linting/lint_group.rs b/harper-core/src/linting/lint_group.rs index 580daf37..87116706 100644 --- a/harper-core/src/linting/lint_group.rs +++ b/harper-core/src/linting/lint_group.rs @@ -13,6 +13,7 @@ use super::lets_confusion::LetsConfusion; use super::linking_verbs::LinkingVerbs; use super::long_sentences::LongSentences; use super::matcher::Matcher; +use super::matcher_spelling::MatcherSpelling; use super::merge_words::MergeWords; use super::multiple_sequential_pronouns::MultipleSequentialPronouns; use super::number_suffix_capitalization::NumberSuffixCapitalization; @@ -167,6 +168,7 @@ create_lint_group_config!( RepeatedWords => true, Spaces => true, Matcher => true, + MatcherSpelling => true, CorrectNumberSuffix => true, NumberSuffixCapitalization => true, MultipleSequentialPronouns => true, diff --git a/harper-core/src/linting/matcher.rs b/harper-core/src/linting/matcher.rs index dc59e4f7..97518b07 100644 --- a/harper-core/src/linting/matcher.rs +++ b/harper-core/src/linting/matcher.rs @@ -94,18 +94,26 @@ struct Rule { /// A linter that uses a variety of curated pattern matches to find and fix /// common grammatical issues. pub struct Matcher { + is_spelling: bool, triggers: Vec, } impl Matcher { - pub fn new() -> Self { + pub fn new(is_spelling: bool) -> Self { // This match list needs to be automatically expanded instead of explicitly // defined like it is now. + let spellings = pt! { + "geiger","counter" => "Geiger counter", + "grammer" => "grammar", + "hashmap" => "hash map", + "hashtable" => "hash table", + "ngram" => "n-gram", + "todo" => "to-do", + "wellbeing" => "well-being", + "wordlist" => "word list" + }; let mut triggers = pt! { "spacial","attention" => "special attention", - "wellbeing" => "well-being", - "hashtable" => "hash table", - "hashmap" => "hash map", "dep" => "dependency", "deps" => "dependencies", "off","the","cuff" => "off-the-cuff", @@ -113,7 +121,6 @@ impl Matcher { "my","self" => "myself", "eight","grade" => "eighth grade", "and","also" => "and", - "todo" => "to-do", "To-Do" => "To-do", "performing","this" => "perform this", "mins" => "minutes", @@ -125,17 +132,13 @@ impl Matcher { "hr" => "hour", "w/o" => "without", "w/" => "with", - "wordlist" => "word list"
, "the","challenged" => "that challenged", "stdin" => "standard input", "stdout" => "standard output", "no","to" => "not to", "No","to" => "not to", - "ngram" => "n-gram", - "grammer" => "grammar", "There","fore" => "Therefore", "fatal","outcome" => "death", - "geiger","counter" => "Geiger counter", "world","war","2" => "World War II", "World","war","ii" => "World War II", "world","War","ii" => "World War II", @@ -203,13 +206,16 @@ impl Matcher { replace_with: vecword!("large language model"), }); - Self { triggers } + Self { + is_spelling, + triggers: if is_spelling { spellings } else { triggers }, + } } } impl Default for Matcher { fn default() -> Self { - Self::new() + Self::new(false) } } @@ -242,15 +248,27 @@ impl Linter for Matcher { match_tokens.first().unwrap().span.start, match_tokens.last().unwrap().span.end, ); + let message = if self.is_spelling { + format!( + "Expected “{}” instead.", + trigger.replace_with.iter().collect::() + ) + } else { + format!( + "Did you mean “{}”?", + trigger.replace_with.iter().collect::() + ) + }; lints.push(Lint { span, - lint_kind: LintKind::Miscellaneous, + lint_kind: if self.is_spelling { + LintKind::Spelling + } else { + LintKind::Miscellaneous + }, suggestions: vec![Suggestion::ReplaceWith(trigger.replace_with.to_owned())], - message: format!( - "Did you mean “{}”?", - trigger.replace_with.iter().collect::() - ), + message, priority: 15, }) } @@ -261,7 +279,7 @@ impl Linter for Matcher { } fn description(&self) -> &'static str { - "A collection of curated rules. A catch-all that will be removed in the future." + "A collection of curated rules: \"Did you mean ...\"? A catch-all that will be removed in the future." } } @@ -273,7 +291,7 @@ mod tests { #[test] fn matches_therefore() { let document = Document::new_plain_english_curated("There fore."); - let mut matcher = Matcher::new(); + let mut matcher = Matcher::default(); let lints = matcher.lint(&document); assert_eq!(lints.len(), 1); } diff --git a/harper-core/src/linting/matcher_spelling.rs b/harper-core/src/linting/matcher_spelling.rs new file mode 100644 index 00000000..e6e11d0b --- /dev/null +++ b/harper-core/src/linting/matcher_spelling.rs @@ -0,0 +1,26 @@ +use crate::linting::{Lint, Linter}; +use crate::Document; + +use super::matcher::Matcher; + +pub struct MatcherSpelling { + matcher: Matcher, +} + +impl Default for MatcherSpelling { + fn default() -> Self { + Self { + matcher: Matcher::new(true), + } + } +} + +impl Linter for MatcherSpelling { + fn lint(&mut self, document: &Document) -> Vec { + self.matcher.lint(document) + } + + fn description(&self) -> &'static str { + "A collection of curated spelling rules: \"Expected ... instead\". A catch-all that will be removed in the future." + } +} diff --git a/harper-core/src/linting/mod.rs b/harper-core/src/linting/mod.rs index 3cf5e763..17ca528f 100644 --- a/harper-core/src/linting/mod.rs +++ b/harper-core/src/linting/mod.rs @@ -19,6 +19,7 @@ mod lint_group; mod lint_kind; mod long_sentences; mod matcher; +mod matcher_spelling; mod merge_linters; mod merge_words; mod multiple_sequential_pronouns; @@ -58,6 +59,7 @@ pub use lint_group::{LintGroup, LintGroupConfig}; pub use lint_kind::LintKind; pub use long_sentences::LongSentences; pub use matcher::Matcher; +pub use matcher_spelling::MatcherSpelling; pub use merge_words::MergeWords; pub use multiple_sequential_pronouns::MultipleSequentialPronouns; pub use number_suffix_capitalization::NumberSuffixCapitalization; diff --git a/packages/web/src/routes/docs/integrations/neovim/+page.md b/packages/web/src/routes/docs/integrations/neovim/+page.md index fc5b9dea..37535fcb 100644 --- a/packages/web/src/routes/docs/integrations/neovim/+page.md +++ b/packages/web/src/routes/docs/integrations/neovim/+page.md @@ -124,6 +124,7 @@ lspconfig.harper_ls.setup { repeated_words = true, spaces = true, matcher = true, + matcher_spelling = true, correct_number_suffix = true, number_suffix_capitalization = true, multiple_sequential_pronouns = true,