diff --git a/harper-cli/src/main.rs b/harper-cli/src/main.rs index c7706c04f6..48d8108d41 100644 --- a/harper-cli/src/main.rs +++ b/harper-cli/src/main.rs @@ -38,6 +38,9 @@ enum Args { /// If omitted, `harper-cli` will run every rule. #[arg(short, long)] only_lint_with: Option>, + /// Specify the language. + #[arg(short, long, default_value = "en")] + langiso639: String, /// Specify the dialect. #[arg(short, long, default_value = Dialect::American.to_string())] dialect: Dialect, @@ -50,11 +53,17 @@ enum Args { }, /// Parse a provided document and print the detected symbols. Parse { + /// Specify the language. + #[arg(short, long, default_value = "en")] + langiso639: String, /// The file you wish to parse. file: PathBuf, }, /// Parse a provided document and show the spans of the detected tokens. Spans { + /// Specify the language. + #[arg(short, long, default_value = "en")] + langiso639: String, /// The file you wish to display the spans. file: PathBuf, /// Include newlines in the output @@ -62,17 +71,32 @@ enum Args { include_newlines: bool, }, /// Get the metadata associated with a particular word. - Metadata { word: String }, + Metadata { + /// Specify the language. + #[arg(short, long, default_value = "en")] + langiso639: String, + /// The word you wish to get metadata for. + word: String, + }, /// Get all the forms of a word using the affixes. - Forms { line: String }, + Forms { + /// Specify the language. + #[arg(short, long, default_value = "en")] + langiso639: String, + /// The word you wish to get forms for. + line: String, + }, /// Emit a decompressed, line-separated list of the words in Harper's dictionary. - Words, + Words { langiso639: String }, /// Summarize a lint record SummarizeLintRecord { file: PathBuf }, /// Print the default config with descriptions. - Config, + Config { langiso639: String }, /// Print a list of all the words in a document, sorted by frequency. MineWords { + /// Specify the language. + #[arg(short, long, default_value = "en")] + langiso639: String, /// The document to mine words from. file: PathBuf, }, @@ -81,27 +105,28 @@ enum Args { fn main() -> anyhow::Result<()> { let args = Args::parse(); let markdown_options = MarkdownOptions::default(); - let dictionary = FstDictionary::curated(); match args { Args::Lint { file, count, only_lint_with, + langiso639, dialect, user_dict_path, file_dict_path, } => { - let mut merged_dict = MergedDictionary::new(); + let dictionary = FstDictionary::curated(&langiso639); + let mut merged_dict = MergedDictionary::new(&langiso639); merged_dict.add_dictionary(dictionary); - match load_dict(&user_dict_path) { + match load_dict(&user_dict_path, &langiso639) { Ok(user_dict) => merged_dict.add_dictionary(Arc::new(user_dict)), Err(err) => println!("{}: {}", user_dict_path.display(), err), } let file_dict_path = file_dict_path.join(file_dict_name(&file)); - match load_dict(&file_dict_path) { + match load_dict(&file_dict_path, &langiso639) { Ok(file_dict) => merged_dict.add_dictionary(Arc::new(file_dict)), Err(err) => println!("{}: {}", file_dict_path.display(), err), } @@ -154,7 +179,8 @@ fn main() -> anyhow::Result<()> { process::exit(1) } - Args::Parse { file } => { + Args::Parse { langiso639, file } => { + let dictionary = FstDictionary::curated(&langiso639); let (doc, _) = load_file(&file, markdown_options, &dictionary)?; for token in doc.tokens() { @@ -165,9 +191,11 @@ fn main() -> anyhow::Result<()> { Ok(()) } Args::Spans { + langiso639, file, include_newlines, } => { + let dictionary = FstDictionary::curated(&langiso639); let (doc, source) = load_file(&file, markdown_options, &dictionary)?; let primary_color = Color::Blue; @@ -209,7 +237,8 @@ fn main() -> anyhow::Result<()> { Ok(()) } - Args::Words => { + Args::Words { langiso639 } => { + let dictionary = FstDictionary::curated(&langiso639); let mut word_str = String::new(); for word in dictionary.words_iter() { @@ -221,7 +250,8 @@ fn main() -> anyhow::Result<()> { Ok(()) } - Args::Metadata { word } => { + Args::Metadata { langiso639, word } => { + let dictionary = FstDictionary::curated(&langiso639); let metadata = dictionary.get_word_metadata_str(&word); let json = serde_json::to_string_pretty(&metadata).unwrap(); @@ -239,7 +269,7 @@ fn main() -> anyhow::Result<()> { Ok(()) } - Args::Forms { line } => { + Args::Forms { langiso639, line } => { let (word, annot) = line_to_parts(&line); let curated_word_list = include_str!("../../harper-core/dictionary.dict"); @@ -290,12 +320,13 @@ fn main() -> anyhow::Result<()> { if let Some((dict_word, dict_annot)) = &entry_in_dict { println!("Old, from the dictionary:"); - print_word_derivations(dict_word, dict_annot, &FstDictionary::curated()); + print_word_derivations(dict_word, dict_annot, &FstDictionary::curated(&langiso639)); }; if !annot.is_empty() { let rune_words = format!("1\n{line}"); let dict = MutableDictionary::from_rune_files( + &langiso639, &rune_words, include_str!("../../harper-core/affixes.json"), )?; @@ -306,13 +337,16 @@ fn main() -> anyhow::Result<()> { Ok(()) } - Args::Config => { + Args::Config { + langiso639: language, + } => { #[derive(Serialize)] struct Config { default_value: bool, description: String, } + let dictionary = FstDictionary::curated(&language); let linter = LintGroup::new_curated(dictionary, Dialect::American); let default_config: HashMap = @@ -334,7 +368,8 @@ fn main() -> anyhow::Result<()> { Ok(()) } - Args::MineWords { file } => { + Args::MineWords { langiso639, file } => { + let dictionary = FstDictionary::curated(&langiso639); let (doc, _source) = load_file(&file, MarkdownOptions::default(), &dictionary)?; let mut words = HashMap::new(); @@ -415,10 +450,10 @@ fn print_word_derivations(word: &str, annot: &str, dictionary: &impl Dictionary) } /// Sync version of harper-ls/src/dictionary_io@load_dict -fn load_dict(path: &Path) -> anyhow::Result { +fn load_dict(path: &Path, langiso639: &str) -> anyhow::Result { let str = fs::read_to_string(path)?; - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new(langiso639); dict.extend_words( str.lines() .map(|l| (l.chars().collect::>(), WordMetadata::default())), diff --git a/harper-comments/src/comment_parsers/jsdoc.rs b/harper-comments/src/comment_parsers/jsdoc.rs index 2aefb12864..d3e469c3eb 100644 --- a/harper-comments/src/comment_parsers/jsdoc.rs +++ b/harper-comments/src/comment_parsers/jsdoc.rs @@ -171,7 +171,7 @@ mod tests { let source = "/** This should _not_cause an infinite loop: {@ */"; let parser = CommentParser::new_from_language_id("javascript", MarkdownOptions::default()).unwrap(); - Document::new_curated(source, &parser); + Document::new_curated(source, &parser, "en"); } #[test] @@ -179,7 +179,7 @@ mod tests { let source = "/** See {@link MyClass} and [MyClass's foo property]{@link MyClass#foo}. */"; let parser = CommentParser::new_from_language_id("javascript", MarkdownOptions::default()).unwrap(); - let document = Document::new_curated(source, &parser); + let document = Document::new_curated(source, &parser, "en"); assert!(matches!( document @@ -224,7 +224,7 @@ mod tests { let source = "/** @class Circle representing a circle. */"; let parser = CommentParser::new_from_language_id("javascript", MarkdownOptions::default()).unwrap(); - let document = Document::new_curated(source, &parser); + let document = Document::new_curated(source, &parser, "en"); assert!( document.tokens().all(|t| t.kind.is_unlintable() diff --git a/harper-comments/src/masker.rs b/harper-comments/src/masker.rs index e058c7c155..c13226f461 100644 --- a/harper-comments/src/masker.rs +++ b/harper-comments/src/masker.rs @@ -8,7 +8,10 @@ pub struct CommentMasker { impl CommentMasker { pub fn create_ident_dict(&self, source: &[char]) -> Option { - self.inner.create_ident_dict(source) + // self.inner.create_ident_dict("fake_language_cid", source) + eprintln!("##🚜## CommentMasker/create_ident_dict"); + // self.inner.create_ident_dict("es", source) + self.inner.create_ident_dict("en", source) } pub fn new( diff --git a/harper-comments/tests/language_support.rs b/harper-comments/tests/language_support.rs index 6cdfccbf1c..3487ad6ce8 100644 --- a/harper-comments/tests/language_support.rs +++ b/harper-comments/tests/language_support.rs @@ -22,7 +22,7 @@ macro_rules! create_test { ); let parser = CommentParser::new_from_filename(Path::new(filename), MarkdownOptions::default()).unwrap(); - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let document = Document::new(&source, &parser, &dict); let mut linter = LintGroup::new_curated(dict, Dialect::American); diff --git a/harper-core/affixes-es.json b/harper-core/affixes-es.json new file mode 100644 index 0000000000..c7abd0761b --- /dev/null +++ b/harper-core/affixes-es.json @@ -0,0 +1,60 @@ +{ + "affixes": { + "a": { + "#": "adjective property", + "kind": "property", + "cross_product": true, + "replacements": [], + "target_metadata": {}, + "base_metadata": { + "adjective": {} + } + }, + "f": { + "#": "feminine property", + "kind": "property", + "cross_product": true, + "replacements": [], + "target_metadata": {}, + "base_metadata": { + "noun": { + "//": "should be an enum rather than a boolean", + "is_feminine": true + } + } + }, + "m": { + "#": "masculine property", + "kind": "property", + "cross_product": true, + "replacements": [], + "target_metadata": {}, + "base_metadata": { + "noun": { + "//": "should be an enum rather than a boolean", + "is_masculine": true + } + } + }, + "n": { + "#": "noun property", + "kind": "property", + "cross_product": true, + "replacements": [], + "target_metadata": {}, + "base_metadata": { + "noun": {} + } + }, + "v": { + "#": "verb property", + "kind": "property", + "cross_product": true, + "replacements": [], + "target_metadata": {}, + "base_metadata": { + "verb": {} + } + } + } +} diff --git a/harper-core/benches/parse_demo.rs b/harper-core/benches/parse_demo.rs index 6339cc5293..f62b45e096 100644 --- a/harper-core/benches/parse_demo.rs +++ b/harper-core/benches/parse_demo.rs @@ -6,14 +6,14 @@ static ESSAY: &str = include_str!("./essay.md"); fn parse_essay(c: &mut Criterion) { c.bench_function("parse_essay", |b| { - b.iter(|| Document::new_markdown_default_curated(black_box(ESSAY))); + b.iter(|| Document::new_markdown_default_curated(black_box(ESSAY), "en")); }); } fn lint_essay(c: &mut Criterion) { - let dictionary = FstDictionary::curated(); + let dictionary = FstDictionary::curated("en"); let mut lint_set = LintGroup::new_curated(dictionary, Dialect::American); - let document = Document::new_markdown_default_curated(black_box(ESSAY)); + let document = Document::new_markdown_default_curated(black_box(ESSAY), "en"); c.bench_function("lint_essay", |b| { b.iter(|| lint_set.lint(&document)); @@ -23,7 +23,7 @@ fn lint_essay(c: &mut Criterion) { fn lint_essay_uncached(c: &mut Criterion) { c.bench_function("lint_essay_uncached", |b| { b.iter(|| { - let dictionary = FstDictionary::curated(); + let dictionary = FstDictionary::curated("en"); let mut lint_set = LintGroup::new_curated(dictionary.clone(), Dialect::American); let document = Document::new_markdown_default(black_box(ESSAY), &dictionary); lint_set.lint(&document) diff --git a/harper-core/dictionary-es.dict b/harper-core/dictionary-es.dict new file mode 100644 index 0000000000..24839e630c --- /dev/null +++ b/harper-core/dictionary-es.dict @@ -0,0 +1,67 @@ +66 + +aire/nm +árbol/nm +asiento/nm +caja/nm +cama/nf +cara/nf +casa/nf +caso/nm +cielo/nf +ciudad/nf +coche/nm +código/nm +comer/v +comida/nf +computador/nm +computadora/nf +dar/vn +dedo/nm +desarrollar/v +día/nm +dificil/a +el/m +este +flojo/a +gato/nm +grande/a +gustar/v +haber/v +ir/v +juego/nm +jugar/v +la/f +luna/nf +luz/nf +maquina/nf +mesa/nf +noche/f +nombre/nm +nosotros +oscuro/a +palabra/nf +pantalla/nf +pared/nf +pequeño/a +playa/nf +poder/vnm +programar/v +próximo/a +rana/nf +rápido/a +regla/nf +ropa/nf +secar/v +sol/nm +sombrero/nm +tarde/a +tecla/nm +teclado/nm +temprano/a +tener/v +tierra/nf +tormenta/nf +venir/v +ventana/nf +vivir/v \ No newline at end of file diff --git a/harper-core/src/document.rs b/harper-core/src/document.rs index 9c0d310064..ec398b6b67 100644 --- a/harper-core/src/document.rs +++ b/harper-core/src/document.rs @@ -23,8 +23,9 @@ pub struct Document { } impl Default for Document { + // TODO since it says PlainEnglish, should we just use "en"? fn default() -> Self { - Self::new("", &PlainEnglish, &FstDictionary::curated()) + Self::new("", &PlainEnglish, &FstDictionary::curated("en")) } } @@ -61,10 +62,14 @@ impl Document { /// Lexes and parses text to produce a document using a provided language /// parser and the included curated dictionary. - pub fn new_curated(text: &str, parser: &impl Parser) -> Self { + pub fn new_curated(text: &str, parser: &impl Parser, langiso639: &str) -> Self { let source: Vec<_> = text.chars().collect(); - Self::new_from_vec(Lrc::new(source), parser, &FstDictionary::curated()) + Self::new_from_vec( + Lrc::new(source), + parser, + &FstDictionary::curated(langiso639), + ) } /// Lexes and parses text to produce a document using a provided language @@ -85,7 +90,7 @@ impl Document { /// Parse text to produce a document using the built-in [`PlainEnglish`] /// parser and curated dictionary. pub fn new_plain_english_curated(text: &str) -> Self { - Self::new(text, &PlainEnglish, &FstDictionary::curated()) + Self::new(text, &PlainEnglish, &FstDictionary::curated("en")) } /// Parse text to produce a document using the built-in [`PlainEnglish`] @@ -96,18 +101,22 @@ impl Document { /// Parse text to produce a document using the built-in [`Markdown`] parser /// and curated dictionary. - pub fn new_markdown_curated(text: &str, markdown_options: MarkdownOptions) -> Self { + pub fn new_markdown_curated( + langiso639: &str, + text: &str, + markdown_options: MarkdownOptions, + ) -> Self { Self::new( text, &Markdown::new(markdown_options), - &FstDictionary::curated(), + &FstDictionary::curated(langiso639), ) } /// Parse text to produce a document using the built-in [`Markdown`] parser /// and curated dictionary with the default Markdown configuration. - pub fn new_markdown_default_curated(text: &str) -> Self { - Self::new_markdown_curated(text, MarkdownOptions::default()) + pub fn new_markdown_default_curated(text: &str, langiso639: &str) -> Self { + Self::new_markdown_curated(langiso639, text, MarkdownOptions::default()) } /// Parse text to produce a document using the built-in [`PlainEnglish`] @@ -658,7 +667,7 @@ mod tests { assert_eq!(document.tokens.len(), final_tok_count); - let document = Document::new_markdown_curated(text, MarkdownOptions::default()); + let document = Document::new_markdown_curated("en", text, MarkdownOptions::default()); assert_eq!(document.tokens.len(), final_tok_count); } diff --git a/harper-core/src/ignored_lints/mod.rs b/harper-core/src/ignored_lints/mod.rs index ab6f335bc8..6dc9132d37 100644 --- a/harper-core/src/ignored_lints/mod.rs +++ b/harper-core/src/ignored_lints/mod.rs @@ -72,10 +72,10 @@ mod tests { #[quickcheck] fn can_ignore_all(text: String) -> bool { - let document = Document::new_markdown_default_curated(&text); + let document = Document::new_markdown_default_curated(&text, "en"); let mut lints = - LintGroup::new_curated(FstDictionary::curated(), Dialect::American).lint(&document); + LintGroup::new_curated(FstDictionary::curated("en"), Dialect::American).lint(&document); let mut ignored = IgnoredLints::new(); @@ -89,10 +89,10 @@ mod tests { #[quickcheck] fn can_ignore_first(text: String) -> TestResult { - let document = Document::new_markdown_default_curated(&text); + let document = Document::new_markdown_default_curated(&text, "en"); let mut lints = - LintGroup::new_curated(FstDictionary::curated(), Dialect::American).lint(&document); + LintGroup::new_curated(FstDictionary::curated("en"), Dialect::American).lint(&document); let Some(first) = lints.first().cloned() else { return TestResult::discard(); @@ -108,10 +108,10 @@ mod tests { // Check that ignoring the nth lint found in source text actually removes it (and no others). fn assert_ignore_lint_reduction(source: &str, nth_lint: usize) { - let document = Document::new_markdown_default_curated(source); + let document = Document::new_markdown_default_curated(source, "en"); let mut lints = - LintGroup::new_curated(FstDictionary::curated(), Dialect::American).lint(&document); + LintGroup::new_curated(FstDictionary::curated("en"), Dialect::American).lint(&document); let nth = lints.get(nth_lint).cloned().unwrap_or_else(|| { panic!("If ignoring the lint at {nth_lint}, make sure there are enough problems.") diff --git a/harper-core/src/language_detection.rs b/harper-core/src/language_detection.rs index fff6604542..1dca222b57 100644 --- a/harper-core/src/language_detection.rs +++ b/harper-core/src/language_detection.rs @@ -54,7 +54,7 @@ mod tests { use crate::{Document, FstDictionary}; fn assert_not_english(source: &'static str) { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let doc = Document::new_plain_english(source, &dict); let is_likely_english = is_doc_likely_english(&doc, &dict); dbg!(source); @@ -62,7 +62,7 @@ mod tests { } fn assert_english(source: &'static str) { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let doc = Document::new_plain_english(source, &dict); let is_likely_english = is_doc_likely_english(&doc, &dict); dbg!(source); diff --git a/harper-core/src/lib.rs b/harper-core/src/lib.rs index 739dc82960..4c6faafa35 100644 --- a/harper-core/src/lib.rs +++ b/harper-core/src/lib.rs @@ -86,7 +86,7 @@ mod tests { fn keeps_space_lint() { let doc = Document::new_plain_english_curated("Ths tet"); - let mut linter = LintGroup::new_curated(FstDictionary::curated(), Dialect::American); + let mut linter = LintGroup::new_curated(FstDictionary::curated("en"), Dialect::American); let mut lints = linter.lint(&doc); diff --git a/harper-core/src/linting/adjective_of_a.rs b/harper-core/src/linting/adjective_of_a.rs index 3dbe521ccb..c2265710d3 100644 --- a/harper-core/src/linting/adjective_of_a.rs +++ b/harper-core/src/linting/adjective_of_a.rs @@ -172,6 +172,7 @@ mod tests { fn correct_large_of_a() { assert_suggestion_result( "Yeah I'm using as large of a batch size as I can on this machine", + "en", AdjectiveOfA, "Yeah I'm using as large a batch size as I can on this machine", ) @@ -181,6 +182,7 @@ mod tests { fn correct_bad_of_an() { assert_suggestion_result( "- If forking is really that bad of an option, let's first decide where to put this.", + "en", AdjectiveOfA, "- If forking is really that bad an option, let's first decide where to put this.", ); @@ -190,6 +192,7 @@ mod tests { fn dont_flag_comparative() { assert_lint_count( "I only worked with custom composer installers for the better of a day, so please excuse me if I missed a thing.", + "en", AdjectiveOfA, 0, ); @@ -199,6 +202,7 @@ mod tests { fn dont_flag_superlative() { assert_lint_count( "I am trying to use composites to visualize the worst of a set of metrics.", + "en", AdjectiveOfA, 0, ); @@ -209,6 +213,7 @@ mod tests { // Adjective as in "a kind person" vs noun as in "A kind of person" assert_lint_count( "Log.txt file automatic creation in PWD is kind of an anti-feature", + "en", AdjectiveOfA, 0, ); @@ -219,6 +224,7 @@ mod tests { // Can be an adjective in e.g. "He is just part owner" assert_lint_count( "cannot delete a food that is no longer part of a recipe", + "en", AdjectiveOfA, 0, ); @@ -229,6 +235,7 @@ mod tests { // "much of" is correct idiomatic usage assert_lint_count( "How much of a performance impact when switching from rails to rails-api ?", + "en", AdjectiveOfA, 0, ); @@ -239,6 +246,7 @@ mod tests { // Can be an adjective in e.g. "Part man, part machine" assert_lint_count( "Quarkus Extension as Part of a Project inside a Monorepo?", + "en", AdjectiveOfA, 0, ); @@ -249,6 +257,7 @@ mod tests { // "all of" is correct idiomatic usage assert_lint_count( "This repository is deprecated. All of its content and history has been moved.", + "en", AdjectiveOfA, 0, ); @@ -259,6 +268,7 @@ mod tests { // "inside of" is idiomatic usage assert_lint_count( "Michael and Brock sat inside of a diner in Brandon", + "en", AdjectiveOfA, 0, ); @@ -269,6 +279,7 @@ mod tests { // "out of" is correct idiomatic usage assert_lint_count( "not only would he potentially be out of a job and back to sort of poverty", + "en", AdjectiveOfA, 0, ); @@ -279,6 +290,7 @@ mod tests { // "full of" is correct idiomatic usage assert_lint_count( "fortunately I happen to have this Tupperware full of an unceremoniously disassembled LED Mac Mini", + "en", AdjectiveOfA, 0, ); @@ -289,6 +301,7 @@ mod tests { // Can be a noun in e.g. "a certain something" assert_lint_count( "Well its popularity seems to be taking something of a dip right now.", + "en", AdjectiveOfA, 0, ); @@ -299,6 +312,7 @@ mod tests { // Can be a noun in e.g. "use a multimeter to find the short" assert_lint_count( "I found one Youtube short of an indonesian girl.", + "en", AdjectiveOfA, 0, ) @@ -309,6 +323,7 @@ mod tests { // Can be an adjective in e.g. "bottom bunk" assert_lint_count( "When leaves are just like coming out individually from the bottom of a fruit.", + "en", AdjectiveOfA, 0, ) @@ -317,12 +332,17 @@ mod tests { #[test] fn dont_flag_left() { // Can be an adjective in e.g. "left hand" - assert_lint_count("and what is left of a 12vt coil", AdjectiveOfA, 0) + assert_lint_count("and what is left of a 12vt coil", "en", AdjectiveOfA, 0) } #[test] fn dont_flag_full_uppercase() { - assert_lint_count("Full of a bunch varnish like we get.", AdjectiveOfA, 0); + assert_lint_count( + "Full of a bunch varnish like we get.", + "en", + AdjectiveOfA, + 0, + ); } #[test] @@ -330,6 +350,7 @@ mod tests { // Can be an adjective in e.g. "the head cook" assert_lint_count( "You need to get out if you're the head of an education department and you're not using AI", + "en", AdjectiveOfA, 0, ); @@ -340,6 +361,7 @@ mod tests { // Can be an adjective in e.g. "middle child" assert_lint_count( "just to get to that part in the middle of a blizzard", + "en", AdjectiveOfA, 0, ); @@ -350,6 +372,7 @@ mod tests { // Can be an adjective in e.g. "a chance encounter" assert_lint_count( "products that you overpay for because there are subtle details in the terms and conditions that reduce the size or chance of a payout.", + "en", AdjectiveOfA, 0, ); @@ -360,6 +383,7 @@ mod tests { // Can be an adjective in e.g. "a potential candidate" assert_lint_count( "People that are happy to accept it for the potential of a reward.", + "en", AdjectiveOfA, 0, ); @@ -368,14 +392,14 @@ mod tests { #[test] fn dont_flag_sound() { // Can be an adjective in e.g. "sound advice" - assert_lint_count("the sound of an approaching Krampus", AdjectiveOfA, 0); + assert_lint_count("the sound of an approaching Krampus", "en", AdjectiveOfA, 0); } #[test] fn dont_flag_rid() { // I removed the `5` flag from `rid` in `dictionary.dict` // because dictionaries say the sense is archaic. - assert_lint_count("I need to get rid of a problem", AdjectiveOfA, 0); + assert_lint_count("I need to get rid of a problem", "en", AdjectiveOfA, 0); } #[test] @@ -383,6 +407,7 @@ mod tests { // Can be an adjective in e.g. "a precision instrument" assert_lint_count( "a man whose crew cut has the precision of a targeted drone strike", + "en", AdjectiveOfA, 0, ); @@ -393,6 +418,7 @@ mod tests { // Can be an adjective in e.g. "back door" assert_lint_count( "a man whose crew cut has the back of a targeted drone strike", + "en", AdjectiveOfA, 0, ); @@ -403,6 +429,7 @@ mod tests { // "emblematic of" is correct idiomatic usage assert_lint_count( "... situation was emblematic of a publication that ...", + "en", AdjectiveOfA, 0, ); @@ -411,25 +438,40 @@ mod tests { #[test] fn dont_flag_half() { // Can be an adjective in e.g. "half man, half machine" - assert_lint_count("And now I only have half of a CyberTruck", AdjectiveOfA, 0); + assert_lint_count( + "And now I only have half of a CyberTruck", + "en", + AdjectiveOfA, + 0, + ); } #[test] fn dont_flag_bit() { // Technically also an adj as in "that guy's bit - he'll turn into a zombie" - assert_lint_count("we ran into a bit of an issue", AdjectiveOfA, 0); + assert_lint_count("we ran into a bit of an issue", "en", AdjectiveOfA, 0); } #[test] fn dont_flag_dream() { // Can be an adjective in e.g. "we built our dream house" - assert_lint_count("When the dream of a united Europe began", AdjectiveOfA, 0); + assert_lint_count( + "When the dream of a united Europe began", + "en", + AdjectiveOfA, + 0, + ); } #[test] fn dont_flag_beginning() { // Present participles have properties of adjectives, nouns, and verbs - assert_lint_count("That's the beginning of a conversation.", AdjectiveOfA, 0); + assert_lint_count( + "That's the beginning of a conversation.", + "en", + AdjectiveOfA, + 0, + ); } #[test] @@ -437,6 +479,7 @@ mod tests { // Can be an adjective in e.g. "via a side door" assert_lint_count( "it hit the barrier on the side of a highway", + "en", AdjectiveOfA, 0, ); @@ -447,6 +490,7 @@ mod tests { // Adj: "a derivative story", Noun: "stocks and derivatives" assert_lint_count( "Techniques for evaluating the *partial derivative of a function", + "en", AdjectiveOfA, 0, ) @@ -456,6 +500,7 @@ mod tests { fn dont_flag_equivalent() { assert_lint_count( "Rust's equivalent of a switch statement is a match expression", + "en", AdjectiveOfA, 0, ); @@ -465,6 +510,7 @@ mod tests { fn dont_flag_clockwork() { assert_lint_count( "so something's wrong in this clockwork of a thing and I'm not going to bother taking this apart", + "en", AdjectiveOfA, 0, ); @@ -474,6 +520,7 @@ mod tests { fn dont_flag_up() { assert_lint_count( "Yeah gas is made up of a bunch of teenytiny particles all moving around.", + "en", AdjectiveOfA, 0, ); @@ -483,6 +530,7 @@ mod tests { fn dont_flag_eighth() { assert_lint_count( "It's about an eighth of an inch or whatever", + "en", AdjectiveOfA, 0, ); @@ -492,6 +540,7 @@ mod tests { fn dont_flag_shy() { assert_lint_count( "... or just shy of a third of the country's total trade deficit.", + "en", AdjectiveOfA, 0, ); @@ -501,6 +550,7 @@ mod tests { fn dont_flag_fun() { assert_lint_count( "Remember that $4,000 Hermes horse bag I was making fun of a little while ago.", + "en", AdjectiveOfA, 0, ); @@ -512,6 +562,7 @@ mod tests { // This should be in a different lint that handles based on/off/off of. assert_lint_count( "can't identify a person based off of an IP from 10 years ago", + "en", AdjectiveOfA, 0, ); @@ -521,6 +572,7 @@ mod tests { fn dont_flag_borderline_of() { assert_lint_count( "it's very very on the borderline of a rock pop ballad", + "en", AdjectiveOfA, 0, ); @@ -528,13 +580,14 @@ mod tests { #[test] fn dont_flag_light() { - assert_lint_count("The light of a star.", AdjectiveOfA, 0); + assert_lint_count("The light of a star.", "en", AdjectiveOfA, 0); } #[test] fn dont_flag_multiple() { assert_lint_count( "The image needs to be a multiple of a certain size.", + "en", AdjectiveOfA, 0, ); @@ -542,18 +595,19 @@ mod tests { #[test] fn dont_flag_red() { - assert_lint_count("The red of a drop of blood.", AdjectiveOfA, 0); + assert_lint_count("The red of a drop of blood.", "en", AdjectiveOfA, 0); } #[test] fn dont_flag_top() { - assert_lint_count("The top of a hill.", AdjectiveOfA, 0); + assert_lint_count("The top of a hill.", "en", AdjectiveOfA, 0); } #[test] fn dont_flag_slack() { assert_lint_count( "They've been picking up the slack of a federal government mostly dominated by whatever this is.", + "en", AdjectiveOfA, 0, ); @@ -563,6 +617,7 @@ mod tests { fn dont_flag_illustrative() { assert_lint_count( "Yet, the fact that they clearly give a one-sided account of most of their case studies is illustrative of a bias.", + "en", AdjectiveOfA, 0, ); diff --git a/harper-core/src/linting/an_a.rs b/harper-core/src/linting/an_a.rs index 5c0d83c498..8822e139a1 100644 --- a/harper-core/src/linting/an_a.rs +++ b/harper-core/src/linting/an_a.rs @@ -194,78 +194,79 @@ mod tests { #[test] fn detects_html_as_vowel() { - assert_lint_count("Here is a HTML document.", AnA, 1); + assert_lint_count("Here is a HTML document.", "en", AnA, 1); } #[test] fn detects_llm_as_vowel() { - assert_lint_count("Here is a LLM document.", AnA, 1); + assert_lint_count("Here is a LLM document.", "en", AnA, 1); } #[test] fn detects_llm_hyphen_as_vowel() { - assert_lint_count("Here is a LLM-based system.", AnA, 1); + assert_lint_count("Here is a LLM-based system.", "en", AnA, 1); } #[test] fn capitalized_fourier() { - assert_lint_count("Then, perform a Fourier transform.", AnA, 0); + assert_lint_count("Then, perform a Fourier transform.", "en", AnA, 0); } #[test] fn once_over() { - assert_lint_count("give this a once-over.", AnA, 0); + assert_lint_count("give this a once-over.", "en", AnA, 0); } #[test] fn issue_196() { - assert_lint_count("This is formatted as an `ext4` file system.", AnA, 0); + assert_lint_count("This is formatted as an `ext4` file system.", "en", AnA, 0); } #[test] fn allows_lowercase_vowels() { - assert_lint_count("not an error", AnA, 0); + assert_lint_count("not an error", "en", AnA, 0); } #[test] fn allows_lowercase_consonants() { - assert_lint_count("not a crash", AnA, 0); + assert_lint_count("not a crash", "en", AnA, 0); } #[test] fn disallows_lowercase_vowels() { - assert_lint_count("not a error", AnA, 1); + assert_lint_count("not a error", "en", AnA, 1); } #[test] fn disallows_lowercase_consonants() { - assert_lint_count("not an crash", AnA, 1); + assert_lint_count("not an crash", "en", AnA, 1); } #[test] fn allows_uppercase_vowels() { - assert_lint_count("not an Error", AnA, 0); + assert_lint_count("not an Error", "en", AnA, 0); } #[test] fn allows_uppercase_consonants() { - assert_lint_count("not a Crash", AnA, 0); + assert_lint_count("not a Crash", "en", AnA, 0); } #[test] fn disallows_uppercase_vowels() { - assert_lint_count("not a Error", AnA, 1); + assert_lint_count("not a Error", "en", AnA, 1); } #[test] fn disallows_uppercase_consonants() { - assert_lint_count("not an Crash", AnA, 1); + assert_lint_count("not an Crash", "en", AnA, 1); } #[test] fn disallows_a_interface() { assert_lint_count( "A interface for an object that can perform linting actions.", + "en", AnA, 1, ); @@ -273,6 +274,6 @@ mod tests { #[test] fn allow_issue_751() { - assert_lint_count("He got a 52% approval rating.", AnA, 0); + assert_lint_count("He got a 52% approval rating.", "en", AnA, 0); } } diff --git a/harper-core/src/linting/avoid_curses.rs b/harper-core/src/linting/avoid_curses.rs index 717327c8cc..8b1bab49cb 100644 --- a/harper-core/src/linting/avoid_curses.rs +++ b/harper-core/src/linting/avoid_curses.rs @@ -31,6 +31,11 @@ mod tests { #[test] fn detects_shit() { - assert_lint_count("He ate shit when he fell off the bike.", AvoidCurses, 1); + assert_lint_count( + "He ate shit when he fell off the bike.", + "en", + AvoidCurses, + 1, + ); } } diff --git a/harper-core/src/linting/back_in_the_day.rs b/harper-core/src/linting/back_in_the_day.rs index 814a5d3358..a1efdbfc6a 100644 --- a/harper-core/src/linting/back_in_the_day.rs +++ b/harper-core/src/linting/back_in_the_day.rs @@ -14,7 +14,7 @@ pub struct BackInTheDay { impl Default for BackInTheDay { fn default() -> Self { let exceptions = Lrc::new(WordSet::new(&["before", "of", "when"])); - let phrase = Lrc::new(ExactPhrase::from_phrase("back in the days")); + let phrase = Lrc::new(ExactPhrase::from_phrase("back in the days", "en")); let pattern = SequencePattern::default() .then(phrase.clone()) @@ -70,6 +70,7 @@ mod tests { fn detects_gem_update_case() { assert_suggestion_result( "... has been resolved through a gem update back in the days", + "en", BackInTheDay::default(), "... has been resolved through a gem update back in the day", ); @@ -79,6 +80,7 @@ mod tests { fn detects_install_case() { assert_suggestion_result( "Back in the days we're used to install it directly from ...", + "en", BackInTheDay::default(), "Back in the day we're used to install it directly from ...", ); @@ -88,6 +90,7 @@ mod tests { fn detects_composer_json_case() { assert_suggestion_result( "Back in the days there was only composer.json and ...", + "en", BackInTheDay::default(), "Back in the day there was only composer.json and ...", ); @@ -97,6 +100,7 @@ mod tests { fn detects_version_release_case() { assert_suggestion_result( "... should have been released back in the days in a version 11", + "en", BackInTheDay::default(), "... should have been released back in the day in a version 11", ); @@ -106,6 +110,7 @@ mod tests { fn avoids_false_positive_springfox() { assert_lint_count( "Back in the days of SpringFox, there were several requests to ...", + "en", BackInTheDay::default(), 0, ); @@ -115,6 +120,7 @@ mod tests { fn avoids_false_positive_ie() { assert_lint_count( "Back in the days of IE, Powershell used to ...", + "en", BackInTheDay::default(), 0, ); @@ -124,6 +130,7 @@ mod tests { fn avoids_false_positive_code_usage() { assert_lint_count( "Back in the days when I had 100% of my code in ...", + "en", BackInTheDay::default(), 0, ); @@ -132,6 +139,7 @@ mod tests { fn catches_uppercase() { assert_lint_count( "Back in the days, we went for a walk.", + "en", BackInTheDay::default(), 1, ); @@ -141,6 +149,7 @@ mod tests { fn catches_lowercase() { assert_lint_count( "We used to go for walks back in the days.", + "en", BackInTheDay::default(), 1, ); @@ -150,6 +159,7 @@ mod tests { fn doesnt_catch_false_positive_of() { assert_lint_count( "Back in the days of CRTs, computers were expensive.", + "en", BackInTheDay::default(), 0, ); @@ -159,6 +169,7 @@ mod tests { fn doesnt_catch_false_positive_when() { assert_lint_count( "Back in the days when videogame arcades were popular.", + "en", BackInTheDay::default(), 0, ); @@ -168,6 +179,7 @@ mod tests { fn catches_comma_when() { assert_lint_count( "Back in the days, when we were children, we played outside.", + "en", BackInTheDay::default(), 1, ); @@ -177,6 +189,7 @@ mod tests { fn doesnt_catch_false_positive_before() { assert_lint_count( "Back in the days before laptops we had \"luggables\".", + "en", BackInTheDay::default(), 0, ); @@ -186,6 +199,7 @@ mod tests { fn catches_comma_before() { assert_lint_count( "Back in the days, before laptops.", + "en", BackInTheDay::default(), 1, ); @@ -195,6 +209,7 @@ mod tests { fn doesnt_catch_qualified_days() { assert_lint_count( "Back in the old days we did this by hand.", + "en", BackInTheDay::default(), 0, ); diff --git a/harper-core/src/linting/capitalize_personal_pronouns.rs b/harper-core/src/linting/capitalize_personal_pronouns.rs index 82a722eb16..deb019bddd 100644 --- a/harper-core/src/linting/capitalize_personal_pronouns.rs +++ b/harper-core/src/linting/capitalize_personal_pronouns.rs @@ -52,13 +52,19 @@ mod tests { #[test] fn start() { - assert_suggestion_result("i am hungry", CapitalizePersonalPronouns, "I am hungry"); + assert_suggestion_result( + "i am hungry", + "en", + CapitalizePersonalPronouns, + "I am hungry", + ); } #[test] fn end() { assert_suggestion_result( "There is no one stronger than i", + "en", CapitalizePersonalPronouns, "There is no one stronger than I", ); @@ -68,6 +74,7 @@ mod tests { fn middle() { assert_suggestion_result( "First of all, i am not happy with this.", + "en", CapitalizePersonalPronouns, "First of all, I am not happy with this.", ); @@ -77,6 +84,7 @@ mod tests { fn issue_365() { assert_lint_count( "access will succeed, unlike with UDEREF/i386.", + "en", CapitalizePersonalPronouns, 0, ); @@ -84,13 +92,14 @@ mod tests { #[test] fn corrects_id() { - assert_suggestion_result("i'd", CapitalizePersonalPronouns, "I'd"); + assert_suggestion_result("i'd", "en", CapitalizePersonalPronouns, "I'd"); } #[test] fn correct_real_world_id() { assert_suggestion_result( "Personal Homebrew tap with tools i'd like to use", + "en", CapitalizePersonalPronouns, "Personal Homebrew tap with tools I'd like to use", ) @@ -98,13 +107,14 @@ mod tests { #[test] fn corrects_idve() { - assert_suggestion_result("i'd've", CapitalizePersonalPronouns, "I'd've"); + assert_suggestion_result("i'd've", "en", CapitalizePersonalPronouns, "I'd've"); } #[test] fn correct_real_world_idve() { assert_suggestion_result( "... i'd've loved this even more twice length , but let not get greedy", + "en", CapitalizePersonalPronouns, "... I'd've loved this even more twice length , but let not get greedy", ) @@ -112,13 +122,14 @@ mod tests { #[test] fn corrects_ill() { - assert_suggestion_result("i'll", CapitalizePersonalPronouns, "I'll"); + assert_suggestion_result("i'll", "en", CapitalizePersonalPronouns, "I'll"); } #[test] fn correct_real_world_ill() { assert_suggestion_result( "Hey i deploy my contract it give me error and i'll match with the script file both are same if someone have idea how i slove this please ...", + "en", CapitalizePersonalPronouns, "Hey I deploy my contract it give me error and I'll match with the script file both are same if someone have idea how I slove this please ...", ) @@ -126,13 +137,14 @@ mod tests { #[test] fn corrects_im() { - assert_suggestion_result("i'm", CapitalizePersonalPronouns, "I'm"); + assert_suggestion_result("i'm", "en", CapitalizePersonalPronouns, "I'm"); } #[test] fn correct_real_world_im() { assert_suggestion_result( "Grid view not working, i'm not using any template", + "en", CapitalizePersonalPronouns, "Grid view not working, I'm not using any template", ) @@ -140,13 +152,14 @@ mod tests { #[test] fn corrects_ive() { - assert_suggestion_result("i've", CapitalizePersonalPronouns, "I've"); + assert_suggestion_result("i've", "en", CapitalizePersonalPronouns, "I've"); } #[test] fn correct_real_world_ive() { assert_suggestion_result( "Can't use Github Pro although i've verified for student pack", + "en", CapitalizePersonalPronouns, "Can't use Github Pro although I've verified for student pack", ) diff --git a/harper-core/src/linting/chock_full.rs b/harper-core/src/linting/chock_full.rs index 950b651c9d..6e49d383c8 100644 --- a/harper-core/src/linting/chock_full.rs +++ b/harper-core/src/linting/chock_full.rs @@ -66,6 +66,7 @@ mod tests { fn allows_correct_form() { assert_lint_count( "'Chalk full', 'chalk-full', 'choke full', and 'choke-full' are nonstandard forms of 'chock-full'.", + "en", ChockFull::default(), 4, ); @@ -75,6 +76,7 @@ mod tests { fn lower_space_chalk() { assert_suggestion_result( "The codebase is chalk full of errors that we need to address.", + "en", ChockFull::default(), "The codebase is chock-full of errors that we need to address.", ); @@ -84,6 +86,7 @@ mod tests { fn lower_space_choke() { assert_suggestion_result( "The project is choke full of questionable decisions that we need to revisit.", + "en", ChockFull::default(), "The project is chock-full of questionable decisions that we need to revisit.", ); @@ -93,6 +96,7 @@ mod tests { fn upper_space_chalk() { assert_suggestion_result( "Chalk full of deprecated methods; we should refactor.", + "en", ChockFull::default(), "Chock-full of deprecated methods; we should refactor.", ); @@ -102,6 +106,7 @@ mod tests { fn upper_space_choke() { assert_suggestion_result( "Choke full of unnecessary complexity; simplify it.", + "en", ChockFull::default(), "Chock-full of unnecessary complexity; simplify it.", ); @@ -111,6 +116,7 @@ mod tests { fn lower_hyphen_chalk() { assert_suggestion_result( "The code is chalk-full of bugs; we need to debug before release.", + "en", ChockFull::default(), "The code is chock-full of bugs; we need to debug before release.", ); @@ -120,6 +126,7 @@ mod tests { fn lower_hyphen_choke() { assert_suggestion_result( "The project is choke-full of warnings; we should address them.", + "en", ChockFull::default(), "The project is chock-full of warnings; we should address them.", ); @@ -129,6 +136,7 @@ mod tests { fn upper_hyphen_chalk() { assert_suggestion_result( "Chalk-full of features, but we only need a few.", + "en", ChockFull::default(), "Chock-full of features, but we only need a few.", ); @@ -138,6 +146,7 @@ mod tests { fn upper_hyphen_choke() { assert_suggestion_result( "Choke-full of pitfalls; let's consider alternatives.", + "en", ChockFull::default(), "Chock-full of pitfalls; let's consider alternatives.", ); diff --git a/harper-core/src/linting/closed_compounds.rs b/harper-core/src/linting/closed_compounds.rs index 25c25e64a1..5ee5403074 100644 --- a/harper-core/src/linting/closed_compounds.rs +++ b/harper-core/src/linting/closed_compounds.rs @@ -1,6 +1,6 @@ use crate::linting::LintGroup; -use super::MapPhraseLinter; +use super::MapPhraseLinterEn; pub fn lint_group() -> LintGroup { let mut group = LintGroup::empty(); @@ -10,7 +10,7 @@ pub fn lint_group() -> LintGroup { $( $group.add( $name, - Box::new(MapPhraseLinter::new_closed_compound($bad, $good)), + Box::new(MapPhraseLinterEn::new_closed_compound($bad, $good)), ); )+ }; @@ -84,139 +84,139 @@ mod tests { fn it_self() { let test_sentence = "The project, it self, was quite challenging."; let expected = "The project, itself, was quite challenging."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn my_self() { let test_sentence = "He treated my self with respect."; let expected = "He treated myself with respect."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn there_fore() { let test_sentence = "This is the reason; there fore, this is true."; let expected = "This is the reason; therefore, this is true."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn mis_understood() { let test_sentence = "She miss understood the instructions."; let expected = "She misunderstood the instructions."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn mis_use() { let test_sentence = "He tends to miss use the tool."; let expected = "He tends to misuse the tool."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn mis_used() { let test_sentence = "The software was miss used."; let expected = "The software was misused."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn world_wide() { let test_sentence = "The world wide impact was significant."; let expected = "The worldwide impact was significant."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn over_all() { let test_sentence = "The over all performance was good."; let expected = "The overall performance was good."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn how_ever() { let test_sentence = "This is true, how ever, details matter."; let expected = "This is true, however, details matter."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn wide_spread() { let test_sentence = "The news was wide spread throughout the region."; let expected = "The news was widespread throughout the region."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn not_with_standing() { let test_sentence = "They decided to proceed not with standing any further delay."; let expected = "They decided to proceed notwithstanding any further delay."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn any_how() { let test_sentence = "She solved the problem any how, even under pressure."; let expected = "She solved the problem anyhow, even under pressure."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn none_the_less() { let test_sentence = "The results were disappointing, none the less, they continued."; let expected = "The results were disappointing, nonetheless, they continued."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn there_upon() { let test_sentence = "A decision was made there upon reviewing the data."; let expected = "A decision was made thereupon reviewing the data."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn in_so_far() { let test_sentence = "This rule applies in so far as it covers all cases."; let expected = "This rule applies insofar as it covers all cases."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn where_upon() { let test_sentence = "They acted where upon the circumstances allowed."; let expected = "They acted whereupon the circumstances allowed."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn up_ward() { let test_sentence = "The temperature moved up ward during the afternoon."; let expected = "The temperature moved upward during the afternoon."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn hence_forth() { let test_sentence = "All new policies apply hence forth immediately."; let expected = "All new policies apply henceforth immediately."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn regard_less() { let test_sentence = "The decision was made, regard less of the opposition."; let expected = "The decision was made, regardless of the opposition."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } #[test] fn over_night() { let test_sentence = "They set off on their journey over night."; let expected = "They set off on their journey overnight."; - assert_suggestion_result(test_sentence, lint_group(), expected); + assert_suggestion_result(test_sentence, "en", lint_group(), expected); } } diff --git a/harper-core/src/linting/comma_fixes.rs b/harper-core/src/linting/comma_fixes.rs index 2f102b4648..8780241c36 100644 --- a/harper-core/src/linting/comma_fixes.rs +++ b/harper-core/src/linting/comma_fixes.rs @@ -122,23 +122,24 @@ mod tests { #[test] fn allows_english_comma_atomic() { - assert_lint_count(",", CommaFixes, 0); + assert_lint_count(",", "en", CommaFixes, 0); } #[test] fn flags_fullwidth_comma_atomic() { - assert_lint_count(",", CommaFixes, 1); + assert_lint_count(",", "en", CommaFixes, 1); } #[test] fn flags_ideographic_comma_atomic() { - assert_lint_count("、", CommaFixes, 1); + assert_lint_count("、", "en", CommaFixes, 1); } #[test] fn corrects_fullwidth_comma_real_world() { assert_suggestion_result( "higher 2 bits of the number of nodes, whether abandoned or not decided by .index section", + "en", CommaFixes, "higher 2 bits of the number of nodes, whether abandoned or not decided by .index section", ); @@ -146,61 +147,61 @@ mod tests { #[test] fn corrects_ideographic_comma_real_world() { - assert_suggestion_result("cout、endl、string", CommaFixes, "cout, endl, string") + assert_suggestion_result("cout、endl、string", "en", CommaFixes, "cout, endl, string") } #[test] fn doesnt_flag_comma_space_between_words() { - assert_lint_count("foo, bar", CommaFixes, 0); + assert_lint_count("foo, bar", "en", CommaFixes, 0); } #[test] fn flags_fullwidth_comma_space_between_words() { - assert_lint_count("foo, bar", CommaFixes, 1); + assert_lint_count("foo, bar", "en", CommaFixes, 1); } #[test] fn flags_ideographic_comma_space_between_words() { - assert_lint_count("foo、 bar", CommaFixes, 1); + assert_lint_count("foo、 bar", "en", CommaFixes, 1); } #[test] fn doesnt_flag_semicolon_space_between_words() { - assert_lint_count("foo; bar", CommaFixes, 0); + assert_lint_count("foo; bar", "en", CommaFixes, 0); } #[test] fn corrects_comma_between_words_with_no_space() { - assert_suggestion_result("foo,bar", CommaFixes, "foo, bar") + assert_suggestion_result("foo,bar", "en", CommaFixes, "foo, bar") } #[test] fn corrects_asian_comma_between_words_with_no_space() { - assert_suggestion_result("foo,bar", CommaFixes, "foo, bar") + assert_suggestion_result("foo,bar", "en", CommaFixes, "foo, bar") } #[test] fn corrects_space_on_wrong_side_of_comma_between_words() { - assert_suggestion_result("foo ,bar", CommaFixes, "foo, bar") + assert_suggestion_result("foo ,bar", "en", CommaFixes, "foo, bar") } #[test] fn corrects_comma_on_wrong_side_of_asian_comma_between_words() { - assert_suggestion_result("foo ,bar", CommaFixes, "foo, bar") + assert_suggestion_result("foo ,bar", "en", CommaFixes, "foo, bar") } #[test] fn corrects_comma_between_words_with_space_on_both_sides() { - assert_suggestion_result("foo , bar", CommaFixes, "foo, bar") + assert_suggestion_result("foo , bar", "en", CommaFixes, "foo, bar") } #[test] fn corrects_asian_comma_between_words_with_space_on_both_sides() { - assert_suggestion_result("foo 、 bar", CommaFixes, "foo, bar") + assert_suggestion_result("foo 、 bar", "en", CommaFixes, "foo, bar") } #[test] fn doesnt_correct_comma_between_non_english_tokens() { - assert_lint_count("严禁采摘花、 果、叶,挖掘树根、草药!", CommaFixes, 0); + assert_lint_count("严禁采摘花、 果、叶,挖掘树根、草药!", "en", CommaFixes, 0); } } diff --git a/harper-core/src/linting/compound_nouns/general_compound_nouns.rs b/harper-core/src/linting/compound_nouns/general_compound_nouns.rs index d05bcaa854..8c8bdf8bc5 100644 --- a/harper-core/src/linting/compound_nouns/general_compound_nouns.rs +++ b/harper-core/src/linting/compound_nouns/general_compound_nouns.rs @@ -49,7 +49,7 @@ impl Default for GeneralCompoundNouns { tok.span.len() > 1 && !meta.determiner && !meta.is_adverb() && !meta.preposition }); - let compound_pattern = Lrc::new(SplitCompoundWord::new(|meta| { + let compound_pattern = Lrc::new(SplitCompoundWord::new("en", |meta| { meta.is_noun() && !meta.is_adjective() })); diff --git a/harper-core/src/linting/compound_nouns/implied_instantiated_compound_nouns.rs b/harper-core/src/linting/compound_nouns/implied_instantiated_compound_nouns.rs index af6cb4acc1..3ec41a9926 100644 --- a/harper-core/src/linting/compound_nouns/implied_instantiated_compound_nouns.rs +++ b/harper-core/src/linting/compound_nouns/implied_instantiated_compound_nouns.rs @@ -16,7 +16,7 @@ pub struct ImpliedInstantiatedCompoundNouns { impl Default for ImpliedInstantiatedCompoundNouns { fn default() -> Self { - let split_pattern = Lrc::new(SplitCompoundWord::new(|meta| { + let split_pattern = Lrc::new(SplitCompoundWord::new("en", |meta| { meta.is_noun() && !meta.is_proper_noun() })); let pattern = SequencePattern::default() diff --git a/harper-core/src/linting/compound_nouns/implied_ownership_compound_nouns.rs b/harper-core/src/linting/compound_nouns/implied_ownership_compound_nouns.rs index 707de606eb..5d1362b00f 100644 --- a/harper-core/src/linting/compound_nouns/implied_ownership_compound_nouns.rs +++ b/harper-core/src/linting/compound_nouns/implied_ownership_compound_nouns.rs @@ -23,7 +23,7 @@ pub struct ImpliedOwnershipCompoundNouns { impl Default for ImpliedOwnershipCompoundNouns { fn default() -> Self { - let split_pattern = Lrc::new(SplitCompoundWord::new(|meta| meta.is_noun())); + let split_pattern = Lrc::new(SplitCompoundWord::new("en", |meta| meta.is_noun())); let pattern = SequencePattern::default() .then_possessive_nominal() .then_whitespace() @@ -85,6 +85,7 @@ mod tests { fn does_not_flag_lets() { assert_lint_count( "Let's check out this article.", + "en", ImpliedOwnershipCompoundNouns::default(), 0, ); diff --git a/harper-core/src/linting/compound_nouns/mod.rs b/harper-core/src/linting/compound_nouns/mod.rs index 466cb608c2..102047dca8 100644 --- a/harper-core/src/linting/compound_nouns/mod.rs +++ b/harper-core/src/linting/compound_nouns/mod.rs @@ -19,235 +19,236 @@ mod tests { fn web_cam() { let test_sentence = "The web cam captured a stunning image."; let expected = "The webcam captured a stunning image."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn note_book() { let test_sentence = "She always carries a note book to jot down ideas."; let expected = "She always carries a notebook to jot down ideas."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn mother_board() { let test_sentence = "After the upgrade, the mother board was replaced."; let expected = "After the upgrade, the motherboard was replaced."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn smart_phone() { let test_sentence = "He bought a new smart phone last week."; let expected = "He bought a new smartphone last week."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn firm_ware() { let test_sentence = "The device's firm ware was updated overnight."; let expected = "The device's firmware was updated overnight."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn back_plane() { let test_sentence = "A reliable back plane is essential for high-speed data transfer."; let expected = "A reliable backplane is essential for high-speed data transfer."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn spread_sheet() { let test_sentence = "The accountant reviewed the spread sheet carefully."; let expected = "The accountant reviewed the spreadsheet carefully."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn side_bar() { let test_sentence = "The website's side bar offers quick navigation links."; let expected = "The website's sidebar offers quick navigation links."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn back_pack() { let test_sentence = "I packed my books in my back pack before leaving."; let expected = "I packed my books in my backpack before leaving."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn cup_board() { let test_sentence = "She stored the dishes in the old cup board."; let expected = "She stored the dishes in the old cupboard."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn key_board() { let test_sentence = "My key board stopped working during the meeting."; let expected = "My keyboard stopped working during the meeting."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn touch_screen() { let test_sentence = "The device features a responsive touch screen."; let expected = "The device features a responsive touchscreen."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn head_set() { let test_sentence = "He bought a new head set for his workouts."; let expected = "He bought a new headset for his workouts."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn frame_work() { let test_sentence = "The frame work of the app was built with care."; let expected = "The framework of the app was built with care."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn touch_pad() { let test_sentence = "The touch pad on my laptop is very sensitive."; let expected = "The touchpad on my laptop is very sensitive."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn micro_processor() { let test_sentence = "This micro processor is among the fastest available."; let expected = "This microprocessor is among the fastest available."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn head_phone() { let test_sentence = "I lost my head phone at the gym."; let expected = "I lost my headphone at the gym."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn micro_services() { let test_sentence = "Our architecture now relies on micro services."; let expected = "Our architecture now relies on microservices."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn dash_board() { let test_sentence = "The dash board shows real-time analytics."; let expected = "The dashboard shows real-time analytics."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn site_map() { let test_sentence = "A site map is provided at the footer of the website."; let expected = "A sitemap is provided at the footer of the website."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn fire_wall() { let test_sentence = "A robust fire wall is essential for network security."; let expected = "A robust firewall is essential for network security."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn bit_stream() { let test_sentence = "The bit stream was interrupted during transmission."; let expected = "The bitstream was interrupted during transmission."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn block_chain() { let test_sentence = "The block chain is revolutionizing the financial sector."; let expected = "The blockchain is revolutionizing the financial sector."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn thumb_nail() { let test_sentence = "I saved the image as a thumb nail."; let expected = "I saved the image as a thumbnail."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn bath_room() { let test_sentence = "They remodeled the bath room entirely."; let expected = "They remodeled the bathroom entirely."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn every_one() { let test_sentence = "Every one should have access to quality education."; let expected = "Everyone should have access to quality education."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn play_ground() { let test_sentence = "The kids spent the afternoon at the play ground."; let expected = "The kids spent the afternoon at the playground."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn run_way() { let test_sentence = "The airplane taxied along the run way."; let expected = "The airplane taxied along the runway."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn cyber_space() { let test_sentence = "Hackers roam the cyber space freely."; let expected = "Hackers roam the cyberspace freely."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn cyber_attack() { let test_sentence = "The network was hit by a cyber attack."; let expected = "The network was hit by a cyberattack."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn web_socket() { let test_sentence = "Real-time updates are sent via a web socket."; let expected = "Real-time updates are sent via a websocket."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn finger_print() { let test_sentence = "The detective collected a finger print as evidence."; let expected = "The detective collected a fingerprint as evidence."; - assert_suggestion_result(test_sentence, CompoundNouns::default(), expected); + assert_suggestion_result(test_sentence, "en", CompoundNouns::default(), expected); } #[test] fn got_is_not_possessive() { - assert_lint_count("I got here by car...", CompoundNouns::default(), 0); + assert_lint_count("I got here by car...", "en", CompoundNouns::default(), 0); } #[test] fn allow_issue_662() { assert_lint_count( "They are as old as *modern* computers ", + "en", CompoundNouns::default(), 0, ); @@ -255,13 +256,14 @@ mod tests { #[test] fn allow_issue_661() { - assert_lint_count("I may be wrong.", CompoundNouns::default(), 0); + assert_lint_count("I may be wrong.", "en", CompoundNouns::default(), 0); } #[test] fn allow_issue_704() { assert_lint_count( "Here are some ways to do that:", + "en", CompoundNouns::default(), 0, ); @@ -271,6 +273,7 @@ mod tests { fn allows_issue_721() { assert_lint_count( "So if you adjust any one of these adjusters that can have a negative or a positive effect.", + "en", CompoundNouns::default(), 0, ); @@ -280,6 +283,7 @@ mod tests { fn allows_678() { assert_lint_count( "they can't catch all the bugs.", + "en", CompoundNouns::default(), 0, ); @@ -289,6 +293,7 @@ mod tests { fn ina_not_suggested() { assert_lint_count( "past mistakes or a character in a looping reality facing personal challenges.", + "en", CompoundNouns::default(), 0, ); @@ -298,6 +303,7 @@ mod tests { fn allow_suppress_or() { assert_lint_count( "He must decide whether to suppress or coexist with his doppelgänger.", + "en", CompoundNouns::default(), 0, ); diff --git a/harper-core/src/linting/confident.rs b/harper-core/src/linting/confident.rs index c4cb8aff2c..1f309df389 100644 --- a/harper-core/src/linting/confident.rs +++ b/harper-core/src/linting/confident.rs @@ -57,6 +57,7 @@ mod tests { fn describing_person_incorrect() { assert_suggestion_result( "She felt confidant about her presentation.", + "en", Confident::default(), "She felt confident about her presentation.", ); @@ -66,6 +67,7 @@ mod tests { fn describing_person_correct() { assert_lint_count( "She felt confident about her presentation.", + "en", Confident::default(), 0, ); @@ -75,6 +77,7 @@ mod tests { fn certainty_incorrect() { assert_suggestion_result( "I am confidant the test results are accurate.", + "en", Confident::default(), "I am confident the test results are accurate.", ); @@ -84,6 +87,7 @@ mod tests { fn certainty_correct() { assert_lint_count( "I am confident the test results are accurate.", + "en", Confident::default(), 0, ); @@ -93,6 +97,7 @@ mod tests { fn demeanor_incorrect() { assert_suggestion_result( "He walked to the stage with a confidant stride.", + "en", Confident::default(), "He walked to the stage with a confident stride.", ); @@ -102,6 +107,7 @@ mod tests { fn demeanor_correct() { assert_lint_count( "He walked to the stage with a confident stride.", + "en", Confident::default(), 0, ); @@ -111,6 +117,7 @@ mod tests { fn professional_incorrect() { assert_suggestion_result( "You should sound confidant during job interviews.", + "en", Confident::default(), "You should sound confident during job interviews.", ); @@ -120,6 +127,7 @@ mod tests { fn professional_correct() { assert_lint_count( "You should sound confident during job interviews.", + "en", Confident::default(), 0, ); @@ -129,6 +137,7 @@ mod tests { fn assured_tone_incorrect() { assert_suggestion_result( "Present your argument in a confidant, persuasive manner.", + "en", Confident::default(), "Present your argument in a confident, persuasive manner.", ); @@ -138,6 +147,7 @@ mod tests { fn assured_tone_correct() { assert_lint_count( "Present your argument in a confident, persuasive manner.", + "en", Confident::default(), 0, ); @@ -147,6 +157,7 @@ mod tests { fn extra_text_between() { assert_suggestion_result( "She felt very confidant about her presentation.", + "en", Confident::default(), "She felt very confident about her presentation.", ); @@ -156,6 +167,7 @@ mod tests { fn linking_verb_was_confidant() { assert_suggestion_result( "She was confidant about her presentation.", + "en", Confident::default(), "She was confident about her presentation.", ); diff --git a/harper-core/src/linting/correct_number_suffix.rs b/harper-core/src/linting/correct_number_suffix.rs index 38e38d871a..c7eec0c5d6 100644 --- a/harper-core/src/linting/correct_number_suffix.rs +++ b/harper-core/src/linting/correct_number_suffix.rs @@ -51,15 +51,15 @@ mod tests { #[test] fn passes_correct_cases() { - assert_lint_count("2nd", CorrectNumberSuffix, 0); - assert_lint_count("101st", CorrectNumberSuffix, 0); - assert_lint_count("1012th", CorrectNumberSuffix, 0); + assert_lint_count("2nd", "en", CorrectNumberSuffix, 0); + assert_lint_count("101st", "en", CorrectNumberSuffix, 0); + assert_lint_count("1012th", "en", CorrectNumberSuffix, 0); } #[test] fn detects_incorrect_cases() { - assert_lint_count("2st", CorrectNumberSuffix, 1); - assert_lint_count("101nd", CorrectNumberSuffix, 1); - assert_lint_count("1012rd", CorrectNumberSuffix, 1); + assert_lint_count("2st", "en", CorrectNumberSuffix, 1); + assert_lint_count("101nd", "en", CorrectNumberSuffix, 1); + assert_lint_count("1012rd", "en", CorrectNumberSuffix, 1); } } diff --git a/harper-core/src/linting/currency_placement.rs b/harper-core/src/linting/currency_placement.rs index 2e1826bc88..2669f97461 100644 --- a/harper-core/src/linting/currency_placement.rs +++ b/harper-core/src/linting/currency_placement.rs @@ -70,6 +70,7 @@ mod tests { fn eof() { assert_suggestion_result( "It was my last bill worth more than 4$.", + "en", CurrencyPlacement::default(), "It was my last bill worth more than $4.", ); @@ -77,13 +78,19 @@ mod tests { #[test] fn blog_title_allows_correct() { - assert_lint_count("The Best $25 I Ever Spent", CurrencyPlacement::default(), 0); + assert_lint_count( + "The Best $25 I Ever Spent", + "en", + CurrencyPlacement::default(), + 0, + ); } #[test] fn blog_title() { assert_suggestion_result( "The Best 25$ I Ever Spent", + "en", CurrencyPlacement::default(), "The Best $25 I Ever Spent", ); @@ -93,6 +100,7 @@ mod tests { fn blog_title_cents() { assert_suggestion_result( "The Best ¢25 I Ever Spent", + "en", CurrencyPlacement::default(), "The Best 25¢ I Ever Spent", ); @@ -102,6 +110,7 @@ mod tests { fn blog_title_with_space() { assert_suggestion_result( "The Best 25 $ I Ever Spent", + "en", CurrencyPlacement::default(), "The Best $25 I Ever Spent", ); @@ -111,6 +120,7 @@ mod tests { fn multiple_dollar() { assert_suggestion_result( "They were either 25$ 24$ or 23$.", + "en", CurrencyPlacement::default(), "They were either $25 $24 or $23.", ); @@ -120,6 +130,7 @@ mod tests { fn multiple_pound() { assert_suggestion_result( "They were either 25£ 24£ or 23£.", + "en", CurrencyPlacement::default(), "They were either £25 £24 or £23.", ); @@ -129,6 +140,7 @@ mod tests { fn suffix() { assert_suggestion_result( "It was my 20th$.", + "en", CurrencyPlacement::default(), "It was my $20th.", ); @@ -136,6 +148,6 @@ mod tests { #[test] fn seven_even_two_decimal_clean() { - assert_lint_count("$7.00", CurrencyPlacement::default(), 0); + assert_lint_count("$7.00", "en", CurrencyPlacement::default(), 0); } } diff --git a/harper-core/src/linting/dashes.rs b/harper-core/src/linting/dashes.rs index 6dbbc6a07b..2f4db0fa33 100644 --- a/harper-core/src/linting/dashes.rs +++ b/harper-core/src/linting/dashes.rs @@ -68,6 +68,7 @@ mod tests { fn catches_en_dash() { assert_suggestion_result( "pre--Industrial Revolution", + "en", Dashes::default(), "pre–Industrial Revolution", ); @@ -77,6 +78,7 @@ mod tests { fn catches_em_dash() { assert_suggestion_result( "'There is no box' --- Scott", + "en", Dashes::default(), "'There is no box' — Scott", ); @@ -84,6 +86,6 @@ mod tests { #[test] fn no_overlaps() { - assert_suggestion_count("'There is no box' --- Scott", Dashes::default(), 1); + assert_suggestion_count("'There is no box' --- Scott", "en", Dashes::default(), 1); } } diff --git a/harper-core/src/linting/despite_of.rs b/harper-core/src/linting/despite_of.rs index 90ed3d9f86..3607c0e193 100644 --- a/harper-core/src/linting/despite_of.rs +++ b/harper-core/src/linting/despite_of.rs @@ -56,6 +56,7 @@ mod tests { fn catches_lowercase() { assert_suggestion_result( "The team performed well, despite of the difficulties they faced.", + "en", DespiteOf::default(), "The team performed well, despite the difficulties they faced.", ); @@ -65,6 +66,7 @@ mod tests { fn catches_different_cases() { assert_lint_count( "Despite of the rain, we went for a walk.", + "en", DespiteOf::default(), 1, ); @@ -74,6 +76,7 @@ mod tests { fn likes_correction() { assert_lint_count( "The team performed well, despite the difficulties they faced. In spite of the rain, we went for a walk.", + "en", DespiteOf::default(), 0, ); diff --git a/harper-core/src/linting/dot_initialisms.rs b/harper-core/src/linting/dot_initialisms.rs index 4d46a4b405..8c1efd6244 100644 --- a/harper-core/src/linting/dot_initialisms.rs +++ b/harper-core/src/linting/dot_initialisms.rs @@ -66,6 +66,7 @@ mod tests { fn matches_eg() { assert_suggestion_result( "Some text here (eg. more text).", + "en", DotInitialisms::default(), "Some text here (e.g. more text).", ) diff --git a/harper-core/src/linting/ellipsis_length.rs b/harper-core/src/linting/ellipsis_length.rs index adee684472..18a7afb729 100644 --- a/harper-core/src/linting/ellipsis_length.rs +++ b/harper-core/src/linting/ellipsis_length.rs @@ -48,18 +48,18 @@ mod tests { #[test] fn allows_correct_ellipsis() { - assert_lint_count("...", EllipsisLength, 0); + assert_lint_count("...", "en", EllipsisLength, 0); } #[test] fn corrects_long_ellipsis() { - assert_lint_count(".....", EllipsisLength, 1); - assert_suggestion_result(".....", EllipsisLength, "..."); + assert_lint_count(".....", "en", EllipsisLength, 1); + assert_suggestion_result(".....", "en", EllipsisLength, "..."); } #[test] fn corrects_short_ellipsis() { - assert_lint_count("..", EllipsisLength, 1); - assert_suggestion_result("..", EllipsisLength, "..."); + assert_lint_count("..", "en", EllipsisLength, 1); + assert_suggestion_result("..", "en", EllipsisLength, "..."); } } diff --git a/harper-core/src/linting/expand_time_shorthands.rs b/harper-core/src/linting/expand_time_shorthands.rs index 32976303ba..cd3b33e235 100644 --- a/harper-core/src/linting/expand_time_shorthands.rs +++ b/harper-core/src/linting/expand_time_shorthands.rs @@ -105,71 +105,76 @@ mod tests { #[test] fn detects_singular_hour() { - assert_suggestion_result("5 hr", ExpandTimeShorthands::new(), "5 hours"); + assert_suggestion_result("5 hr", "en", ExpandTimeShorthands::new(), "5 hours"); } #[test] fn detects_singular_minute() { - assert_suggestion_result("10 min", ExpandTimeShorthands::new(), "10 minutes"); + assert_suggestion_result("10 min", "en", ExpandTimeShorthands::new(), "10 minutes"); } #[test] fn detects_singular_second() { - assert_suggestion_result("30 sec", ExpandTimeShorthands::new(), "30 seconds"); + assert_suggestion_result("30 sec", "en", ExpandTimeShorthands::new(), "30 seconds"); } #[test] fn detects_plural_hours() { - assert_suggestion_result("5 hrs", ExpandTimeShorthands::new(), "5 hours"); + assert_suggestion_result("5 hrs", "en", ExpandTimeShorthands::new(), "5 hours"); } #[test] fn detects_plural_minutes() { - assert_suggestion_result("10 mins", ExpandTimeShorthands::new(), "10 minutes"); + assert_suggestion_result("10 mins", "en", ExpandTimeShorthands::new(), "10 minutes"); } #[test] fn detects_plural_seconds() { - assert_suggestion_result("30 secs", ExpandTimeShorthands::new(), "30 seconds"); + assert_suggestion_result("30 secs", "en", ExpandTimeShorthands::new(), "30 seconds"); } #[test] fn detects_millisecond() { - assert_suggestion_result("5 ms", ExpandTimeShorthands::new(), "5 milliseconds"); + assert_suggestion_result("5 ms", "en", ExpandTimeShorthands::new(), "5 milliseconds"); } #[test] fn detects_milliseconds() { - assert_suggestion_result("10 msecs", ExpandTimeShorthands::new(), "10 milliseconds"); + assert_suggestion_result( + "10 msecs", + "en", + ExpandTimeShorthands::new(), + "10 milliseconds", + ); } #[test] fn handles_punctuation_hour() { - assert_suggestion_result("5 hr.", ExpandTimeShorthands::new(), "5 hours."); + assert_suggestion_result("5 hr.", "en", ExpandTimeShorthands::new(), "5 hours."); } #[test] fn handles_punctuation_minute() { - assert_suggestion_result("10 min,", ExpandTimeShorthands::new(), "10 minutes,"); + assert_suggestion_result("10 min,", "en", ExpandTimeShorthands::new(), "10 minutes,"); } #[test] fn handles_punctuation_second() { - assert_suggestion_result("30 sec!", ExpandTimeShorthands::new(), "30 seconds!"); + assert_suggestion_result("30 sec!", "en", ExpandTimeShorthands::new(), "30 seconds!"); } #[test] fn handles_adjacent_number_hour() { - assert_suggestion_result("5hr", ExpandTimeShorthands::new(), "5 hours"); + assert_suggestion_result("5hr", "en", ExpandTimeShorthands::new(), "5 hours"); } #[test] fn handles_adjacent_number_minute() { - assert_suggestion_result("10-min", ExpandTimeShorthands::new(), "10-minutes"); + assert_suggestion_result("10-min", "en", ExpandTimeShorthands::new(), "10-minutes"); } #[test] fn handles_adjacent_number_second() { - assert_suggestion_result("30sec", ExpandTimeShorthands::new(), "30 seconds"); + assert_suggestion_result("30sec", "en", ExpandTimeShorthands::new(), "30 seconds"); } } diff --git a/harper-core/src/linting/first_aid_kit.rs b/harper-core/src/linting/first_aid_kit.rs index cf81bd7971..e3b94cb389 100644 --- a/harper-core/src/linting/first_aid_kit.rs +++ b/harper-core/src/linting/first_aid_kit.rs @@ -56,6 +56,7 @@ mod tests { fn corrects_first_aid_kid() { assert_suggestion_result( "A first aid kid is a collection of medical supplies.", + "en", FirstAidKit::default(), "A first aid kit is a collection of medical supplies.", ); @@ -65,6 +66,7 @@ mod tests { fn corrects_starter_kid() { assert_suggestion_result( "Check the starter kid before proceeding.", + "en", FirstAidKit::default(), "Check the starter kit before proceeding.", ); @@ -74,6 +76,7 @@ mod tests { fn corrects_travel_kid() { assert_suggestion_result( "Pack your travel kid for the trip.", + "en", FirstAidKit::default(), "Pack your travel kit for the trip.", ); @@ -83,6 +86,7 @@ mod tests { fn corrects_tool_kid() { assert_suggestion_result( "Don't forget the tool kid for assembly.", + "en", FirstAidKit::default(), "Don't forget the tool kit for assembly.", ); @@ -92,6 +96,7 @@ mod tests { fn does_not_flag_kid_in_other_contexts() { assert_lint_count( "The kid ran through the aid station.", + "en", FirstAidKit::default(), 0, ); diff --git a/harper-core/src/linting/for_noun.rs b/harper-core/src/linting/for_noun.rs index dbfb4eb12c..54d29f3104 100644 --- a/harper-core/src/linting/for_noun.rs +++ b/harper-core/src/linting/for_noun.rs @@ -56,6 +56,7 @@ mod tests { fn corrects_fro_basic_correction() { assert_suggestion_result( "I got a text fro Sarah.", + "en", ForNoun::default(), "I got a text for Sarah.", ); @@ -63,13 +64,14 @@ mod tests { #[test] fn allows_for_clean() { - assert_lint_count("I got a text for Sarah.", ForNoun::default(), 0); + assert_lint_count("I got a text for Sarah.", "en", ForNoun::default(), 0); } #[test] fn corrects_fro_sure() { assert_suggestion_result( "He was away fro sure!", + "en", ForNoun::default(), "He was away for sure!", ); diff --git a/harper-core/src/linting/hedging.rs b/harper-core/src/linting/hedging.rs index 74faee6286..b84f1bfc54 100644 --- a/harper-core/src/linting/hedging.rs +++ b/harper-core/src/linting/hedging.rs @@ -13,7 +13,7 @@ impl Default for Hedging { let patterns: Vec> = phrases .into_iter() - .map(|s| Box::new(ExactPhrase::from_phrase(s)) as Box) + .map(|s| Box::new(ExactPhrase::from_phrase(s, "en")) as Box) .collect(); let pattern = Box::new(EitherPattern::new(patterns)); @@ -49,18 +49,24 @@ mod tests { #[test] fn detects_hedging_phrase() { - assert_lint_count("I would argue that this is correct.", Hedging::default(), 1); + assert_lint_count( + "I would argue that this is correct.", + "en", + Hedging::default(), + 1, + ); } #[test] fn does_not_flag_clean_text() { - assert_lint_count("This is clear and direct.", Hedging::default(), 0); + assert_lint_count("This is clear and direct.", "en", Hedging::default(), 0); } #[test] fn lowercase_hedging() { assert_lint_count( "i would argue that the outcome is uncertain.", + "en", Hedging::default(), 1, ); @@ -68,19 +74,25 @@ mod tests { #[test] fn incomplete_phrase_not_flagged() { - assert_lint_count("I would argue the data is clear.", Hedging::default(), 0); + assert_lint_count( + "I would argue the data is clear.", + "en", + Hedging::default(), + 0, + ); } #[test] fn phrase_with_trailing_comma() { let text = "I would argue that, this method works."; - assert_lint_count(text, Hedging::default(), 1); + assert_lint_count(text, "en", Hedging::default(), 1); } #[test] fn phrase_with_extra_whitespace() { assert_lint_count( "to a certain degree the results are ambiguous.", + "en", Hedging::default(), 1, ); @@ -90,6 +102,7 @@ mod tests { fn does_not_flag_similar_but_incorrect_phrase() { assert_lint_count( "He spoke so to speakingly about the event.", + "en", Hedging::default(), 0, ); @@ -99,6 +112,7 @@ mod tests { fn phrase_split_by_line_break() { assert_lint_count( "I would argue\nthat this approach fails.", + "en", Hedging::default(), 1, ); diff --git a/harper-core/src/linting/hereby.rs b/harper-core/src/linting/hereby.rs index 9d486d6588..5744bbc44d 100644 --- a/harper-core/src/linting/hereby.rs +++ b/harper-core/src/linting/hereby.rs @@ -58,6 +58,7 @@ mod tests { fn declare() { assert_suggestion_result( "I here by declare this state to be free.", + "en", Hereby::default(), "I hereby declare this state to be free.", ); diff --git a/harper-core/src/linting/hop_hope/mod.rs b/harper-core/src/linting/hop_hope/mod.rs index eb63d18e6d..6d6eb51324 100644 --- a/harper-core/src/linting/hop_hope/mod.rs +++ b/harper-core/src/linting/hop_hope/mod.rs @@ -16,6 +16,7 @@ mod tests { fn corrects_hop_to_hope() { assert_suggestion_result( "I hop we can clarify this soon.", + "en", HopHope::default(), "I hope we can clarify this soon.", ); @@ -25,6 +26,7 @@ mod tests { fn does_not_correct_unrelated_use() { assert_suggestion_result( "I hop on one foot for fun.", + "en", HopHope::default(), "I hop on one foot for fun.", ); @@ -34,6 +36,7 @@ mod tests { fn corrects_mixed_case_hop() { assert_suggestion_result( "I HoP we can find a solution.", + "en", HopHope::default(), "I HoPe we can find a solution.", ); @@ -43,6 +46,7 @@ mod tests { fn corrects_hoping_on_call() { assert_suggestion_result( "I was hoping on a call to discuss this.", + "en", HopHope::default(), "I was hopping on a call to discuss this.", ); @@ -52,6 +56,7 @@ mod tests { fn corrects_hoped_on_plane() { assert_suggestion_result( "She hoped on an airplane to visit family.", + "en", HopHope::default(), "She hopped on an airplane to visit family.", ); @@ -61,6 +66,7 @@ mod tests { fn corrects_hope_on_bus() { assert_suggestion_result( "They hope on a bus every morning.", + "en", HopHope::default(), "They hop on a bus every morning.", ); @@ -70,6 +76,7 @@ mod tests { fn does_not_correct_unrelated_context() { assert_suggestion_result( "I hope everything goes well with your project.", + "en", HopHope::default(), "I hope everything goes well with your project.", ); @@ -79,6 +86,7 @@ mod tests { fn corrects_mixed_case() { assert_suggestion_result( "She HoPeD on a train to get home.", + "en", HopHope::default(), "She HoPpEd on a train to get home.", ); diff --git a/harper-core/src/linting/hyphenate_number_day.rs b/harper-core/src/linting/hyphenate_number_day.rs index 7a17331df5..f4a84c4a18 100644 --- a/harper-core/src/linting/hyphenate_number_day.rs +++ b/harper-core/src/linting/hyphenate_number_day.rs @@ -71,6 +71,7 @@ mod tests { fn corrects_three_day_training() { assert_suggestion_result( "The company offers a 3 day training program.", + "en", HyphenateNumberDay::default(), "The company offers a 3-day training program.", ); @@ -80,6 +81,7 @@ mod tests { fn corrects_five_day_challenge() { assert_suggestion_result( "Join the 5 day challenge to improve your skills.", + "en", HyphenateNumberDay::default(), "Join the 5-day challenge to improve your skills.", ); @@ -89,6 +91,7 @@ mod tests { fn corrects_seven_day_plan() { assert_suggestion_result( "She followed a strict 7 day meal plan.", + "en", HyphenateNumberDay::default(), "She followed a strict 7-day meal plan.", ); @@ -98,6 +101,7 @@ mod tests { fn does_not_correct_when_not_adjective() { assert_suggestion_result( "The seminar lasts for 2 days.", + "en", HyphenateNumberDay::default(), "The seminar lasts for 2 days.", ); @@ -107,12 +111,14 @@ mod tests { fn corrects_varied_phrases() { assert_suggestion_result( "They implemented a new 6 day work schedule.", + "en", HyphenateNumberDay::default(), "They implemented a new 6-day work schedule.", ); assert_suggestion_result( "Enroll in our 10 day fitness bootcamp!", + "en", HyphenateNumberDay::default(), "Enroll in our 10-day fitness bootcamp!", ); @@ -122,6 +128,7 @@ mod tests { fn edge_case_day_long() { assert_suggestion_result( "The 4 day-long seminar was insightful.", + "en", HyphenateNumberDay::default(), "The 4-day-long seminar was insightful.", ); @@ -131,6 +138,7 @@ mod tests { fn edge_case_plural_days() { assert_suggestion_result( "The trip was a fun 5 day experience.", + "en", HyphenateNumberDay::default(), "The trip was a fun 5-day experience.", ); @@ -140,6 +148,7 @@ mod tests { fn ignores_spelled_out_numbers() { assert_suggestion_result( "We had a three day holiday.", + "en", HyphenateNumberDay::default(), "We had a three day holiday.", ); diff --git a/harper-core/src/linting/inflected_verb_after_to.rs b/harper-core/src/linting/inflected_verb_after_to.rs index 35131dfbb2..0619b80a83 100644 --- a/harper-core/src/linting/inflected_verb_after_to.rs +++ b/harper-core/src/linting/inflected_verb_after_to.rs @@ -96,7 +96,8 @@ mod tests { fn dont_flag_to_check_both_verb_and_noun() { assert_lint_count( "to check", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -105,7 +106,8 @@ mod tests { fn dont_flag_to_checks_both_verb_and_noun() { assert_lint_count( "to checks", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -114,7 +116,8 @@ mod tests { fn dont_flag_to_cheques_not_a_verb() { assert_lint_count( "to cheques", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -122,14 +125,15 @@ mod tests { // -ing forms can act as nouns, current heuristics cannot distinguish // #[test] // fn flag_to_checking() { - // assert_lint_count("to checking", InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), 1); + // assert_lint_count("to checking", InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 1); // } #[test] fn dont_flag_check_ed() { assert_lint_count( "to checked", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -138,7 +142,8 @@ mod tests { fn dont_flag_noun_belief_s() { assert_lint_count( "to beliefs", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -147,7 +152,8 @@ mod tests { fn dont_flag_noun_meat_s() { assert_lint_count( "to meats", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -157,7 +163,7 @@ mod tests { // fn check_993_suggestions() { // assert_suggestion_result( // "A location-agnostic structure that attempts to captures the context and content that a Lint occurred.", - // InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + // InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), // "A location-agnostic structure that attempts to capture the context and content that a Lint occurred.", // ); // } @@ -166,7 +172,8 @@ mod tests { fn dont_flag_embarrass_not_in_dictionary() { assert_lint_count( "Second I'm going to embarrass you for a.", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -175,7 +182,8 @@ mod tests { fn corrects_exist_s() { assert_suggestion_result( "A valid solution is expected to exists.", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), "A valid solution is expected to exist.", ); } @@ -185,7 +193,7 @@ mod tests { // fn corrects_es_ending() { // assert_suggestion_result( // "I need it to catches every exception.", - // InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + // InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), // "I need it to catch every exception.", // ); // } @@ -194,7 +202,8 @@ mod tests { fn corrects_ed_ending() { assert_suggestion_result( "I had to expanded my horizon.", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), "I had to expand my horizon.", ); } @@ -203,7 +212,8 @@ mod tests { fn flags_expire_d() { assert_lint_count( "I didn't know it was going to expired.", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 1, ); } @@ -212,7 +222,8 @@ mod tests { fn corrects_explain_ed() { assert_suggestion_result( "To explained the rules to the team.", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), "To explain the rules to the team.", ); } @@ -222,7 +233,7 @@ mod tests { // fn corrects_explor_ed() { // assert_suggestion_result( // "I went to explored distant galaxies.", - // InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + // InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), // "I went to explore distant galaxies.", // ); // } @@ -231,7 +242,8 @@ mod tests { fn cant_flag_express_ed_also_noun() { assert_lint_count( "I failed to clearly expressed my point.", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -240,7 +252,8 @@ mod tests { fn correct_feign_ed() { assert_suggestion_result( "I was able to feigned ignorance.", - InflectedVerbAfterTo::new(FstDictionary::curated(), Dialect::American), + "en", + InflectedVerbAfterTo::new(FstDictionary::curated("en"), Dialect::American), "I was able to feign ignorance.", ); } diff --git a/harper-core/src/linting/it_is.rs b/harper-core/src/linting/it_is.rs index 9c29cf56c7..059386be71 100644 --- a/harper-core/src/linting/it_is.rs +++ b/harper-core/src/linting/it_is.rs @@ -96,6 +96,7 @@ mod tests { fn flags_simple_case() { assert_suggestion_result( "Its amazing to see this.", + "en", ItIs::default(), "It's amazing to see this.", ); @@ -105,6 +106,7 @@ mod tests { fn flags_with_preposition() { assert_suggestion_result( "Its critical for the project.", + "en", ItIs::default(), "It's critical for the project.", ); @@ -112,12 +114,12 @@ mod tests { #[test] fn does_not_flag_exception_own() { - assert_lint_count("Its own design is unique.", ItIs::default(), 0); + assert_lint_count("Its own design is unique.", "en", ItIs::default(), 0); } #[test] fn does_not_flag_exception_team() { - assert_lint_count("Its team lead is excellent.", ItIs::default(), 0); + assert_lint_count("Its team lead is excellent.", "en", ItIs::default(), 0); } // This case fails, but I think that's acceptable. @@ -132,13 +134,14 @@ mod tests { #[test] fn does_not_flag_already_correct() { - assert_lint_count("It's important to note.", ItIs::default(), 0); + assert_lint_count("It's important to note.", "en", ItIs::default(), 0); } #[test] fn flags_search_filter_context() { assert_suggestion_result( "Its important to note that the search filter will currently only search the current page.", + "en", ItIs::default(), "It's important to note that the search filter will currently only search the current page.", ); @@ -148,6 +151,7 @@ mod tests { fn flags_ens_restart_context() { assert_suggestion_result( "Today is the third day and I am still stuck on Register. Its important to note that after hours of waiting, I tried to restart the process and clicked on register again but it gets stuck at TX pending.", + "en", ItIs::default(), "Today is the third day and I am still stuck on Register. It's important to note that after hours of waiting, I tried to restart the process and clicked on register again but it gets stuck at TX pending.", ); @@ -157,6 +161,7 @@ mod tests { fn flags_academics_support_context() { assert_suggestion_result( "To assist learners, because its critical for academics to support their ideas and arguments with sources of published research.", + "en", ItIs::default(), "To assist learners, because it's critical for academics to support their ideas and arguments with sources of published research.", ); @@ -166,6 +171,7 @@ mod tests { fn flags_parents_explain_context() { assert_suggestion_result( "I also think its critical for parents to explain their reason for saying no though I would advise against attempting to use logic in the face of either toddler or teenage rage.", + "en", ItIs::default(), "I also think it's critical for parents to explain their reason for saying no though I would advise against attempting to use logic in the face of either toddler or teenage rage.", ); @@ -175,6 +181,7 @@ mod tests { fn flags_chapter_context() { assert_suggestion_result( "I think it's okay since its critical for the rest of the chapter in terms of tone and approach.", + "en", ItIs::default(), "I think it's okay since it's critical for the rest of the chapter in terms of tone and approach.", ); @@ -184,6 +191,7 @@ mod tests { fn flags_microsoft_work_context() { assert_suggestion_result( "... Need help, its critical for my work, as i am a technical blog writer ...", + "en", ItIs::default(), "... Need help, it's critical for my work, as i am a technical blog writer ...", ); @@ -193,6 +201,7 @@ mod tests { fn flags_feminists_context() { assert_suggestion_result( "when it comes to the teaching of grammar and diverse linguistics practices. Its critical for feminists to think about the ways in which they frame language.", + "en", ItIs::default(), "when it comes to the teaching of grammar and diverse linguistics practices. It's critical for feminists to think about the ways in which they frame language.", ); @@ -202,6 +211,7 @@ mod tests { fn flags_students_proofreading_context() { assert_suggestion_result( "its critical for students to develop a similarly sharp eye for misspellings and grammatical errors.", + "en", ItIs::default(), "it's critical for students to develop a similarly sharp eye for misspellings and grammatical errors.", ); @@ -211,6 +221,7 @@ mod tests { fn flags_americans_context() { assert_suggestion_result( "Its critical for Americans to realize that Fox has nothing to do with news.", + "en", ItIs::default(), "It's critical for Americans to realize that Fox has nothing to do with news.", ); @@ -219,7 +230,7 @@ mod tests { // Negative guard: correct possessive use #[test] fn does_not_flag_its_team_lead() { - assert_lint_count("Its team lead is excellent.", ItIs::default(), 0); + assert_lint_count("Its team lead is excellent.", "en", ItIs::default(), 0); } // Imagined edge cases based on real usage: @@ -227,6 +238,7 @@ mod tests { fn flags_crucial_api_context() { assert_suggestion_result( "Its crucial to understand the API before using it.", + "en", ItIs::default(), "It's crucial to understand the API before using it.", ); @@ -236,6 +248,7 @@ mod tests { fn flags_essential_standards_context() { assert_suggestion_result( "Its essential to follow the coding standards in this project.", + "en", ItIs::default(), "It's essential to follow the coding standards in this project.", ); @@ -245,6 +258,7 @@ mod tests { fn flags_vital_dependencies_context() { assert_suggestion_result( "Its vital to keep dependencies up to date.", + "en", ItIs::default(), "It's vital to keep dependencies up to date.", ); diff --git a/harper-core/src/linting/it_would_be.rs b/harper-core/src/linting/it_would_be.rs index 098f83ae58..9ba583d766 100644 --- a/harper-core/src/linting/it_would_be.rs +++ b/harper-core/src/linting/it_would_be.rs @@ -95,6 +95,7 @@ mod tests { fn flags_simple_shame() { assert_suggestion_result( "I think I would be a shame if this happened.", + "en", ItWouldBe::default(), "I think it would be a shame if this happened.", ); @@ -104,6 +105,7 @@ mod tests { fn flags_believe_bummer() { assert_suggestion_result( "We believe I might not be a bummer after all.", + "en", ItWouldBe::default(), "We believe it might not be a bummer after all.", ); @@ -113,6 +115,7 @@ mod tests { fn flags_doubt_good_idea() { assert_suggestion_result( "They doubt I will be a good idea for the team.", + "en", ItWouldBe::default(), "They doubt it will be a good idea for the team.", ); @@ -122,6 +125,7 @@ mod tests { fn ignores_correct_it() { assert_lint_count( "I think it would be a shame if this happened.", + "en", ItWouldBe::default(), 0, ); @@ -131,6 +135,7 @@ mod tests { fn ignores_first_person_statement() { assert_lint_count( "I would be a good fit for the role.", + "en", ItWouldBe::default(), 0, ); diff --git a/harper-core/src/linting/left_right_hand.rs b/harper-core/src/linting/left_right_hand.rs index d4aaddde86..222229a2a6 100644 --- a/harper-core/src/linting/left_right_hand.rs +++ b/harper-core/src/linting/left_right_hand.rs @@ -56,6 +56,7 @@ mod tests { fn corrects_left_hand_side() { assert_suggestion_result( "You'll see it on the left hand side.", + "en", LeftRightHand::default(), "You'll see it on the left-hand side.", ); @@ -65,6 +66,7 @@ mod tests { fn corrects_right_hand_corner() { assert_suggestion_result( "It's in the right hand corner.", + "en", LeftRightHand::default(), "It's in the right-hand corner.", ); @@ -74,6 +76,7 @@ mod tests { fn does_not_correct_noun_usage() { assert_suggestion_result( "She raised her right hand.", + "en", LeftRightHand::default(), "She raised her right hand.", ); diff --git a/harper-core/src/linting/lets_confusion/mod.rs b/harper-core/src/linting/lets_confusion/mod.rs index ca6e31ae47..ae1d41dd67 100644 --- a/harper-core/src/linting/lets_confusion/mod.rs +++ b/harper-core/src/linting/lets_confusion/mod.rs @@ -22,6 +22,7 @@ mod tests { fn walking() { assert_suggestion_result( "The crutch let's him walk.", + "en", LetsConfusion::default(), "The crutch lets him walk.", ); @@ -29,18 +30,19 @@ mod tests { #[test] fn issue_426_us() { - assert_suggestion_result("let's us do", LetsConfusion::default(), "lets us do"); + assert_suggestion_result("let's us do", "en", LetsConfusion::default(), "lets us do"); } #[test] fn issue_426_me() { - assert_suggestion_result("let's me do", LetsConfusion::default(), "lets me do"); + assert_suggestion_result("let's me do", "en", LetsConfusion::default(), "lets me do"); } #[test] fn from_harper_docs() { assert_suggestion_result( "Often the longest and the shortest words are the most helpful, so lets push them first.", + "en", LetsConfusion::default(), "Often the longest and the shortest words are the most helpful, so let's push them first.", ); @@ -49,28 +51,39 @@ mod tests { // "play" is also a noun so in a context like "Sometimes the umpire lets play continue" // #[test] // fn issue_470_missing_apostrophe() { - // assert_suggestion_result("lets play", LetsConfusion::default(), "let's play"); + // assert_suggestion_result("lets play", "en", LetsConfusion::default(), "let's play"); // } // #[test] // fn issue_470_missing_subject() { - // assert_suggestion_result("let play", LetsConfusion::default(), "let's play"); + // assert_suggestion_result("let play", "en", LetsConfusion::default(), "let's play"); // } #[test] fn issue_470_missing_apostrophe() { - assert_suggestion_result("lets proceed", LetsConfusion::default(), "let's proceed"); + assert_suggestion_result( + "lets proceed", + "en", + LetsConfusion::default(), + "let's proceed", + ); } #[test] fn issue_470_missing_subject() { - assert_suggestion_result("let proceed", LetsConfusion::default(), "let's proceed"); + assert_suggestion_result( + "let proceed", + "en", + LetsConfusion::default(), + "let's proceed", + ); } #[test] fn issue_548() { assert_lint_count( "A simple web app that lets you fetch random issues.", + "en", LetsConfusion::default(), 0, ); diff --git a/harper-core/src/linting/lets_confusion/no_contraction_with_verb.rs b/harper-core/src/linting/lets_confusion/no_contraction_with_verb.rs index 276faa6bdb..847edd4111 100644 --- a/harper-core/src/linting/lets_confusion/no_contraction_with_verb.rs +++ b/harper-core/src/linting/lets_confusion/no_contraction_with_verb.rs @@ -105,6 +105,7 @@ mod tests { fn fix_lets_inspect() { assert_suggestion_result( "In the end lets inspect with git-blame the results.", + "en", NoContractionWithVerb::default(), "In the end let's inspect with git-blame the results.", ); @@ -114,13 +115,19 @@ mod tests { #[test] fn dont_flag_let_chance() { - assert_lint_count("Let chance decide", NoContractionWithVerb::default(), 0); + assert_lint_count( + "Let chance decide", + "en", + NoContractionWithVerb::default(), + 0, + ); } #[test] fn dont_flag_let_time() { assert_lint_count( "Let time granularity be parametrized", + "en", NoContractionWithVerb::default(), 0, ); @@ -130,6 +137,7 @@ mod tests { fn dont_flag_lets_staff() { assert_lint_count( "A plugin that backs up player's inventories and lets staff restore them or export it as a shulker.", + "en", NoContractionWithVerb::default(), 0, ); @@ -139,6 +147,7 @@ mod tests { fn dont_flag_lets_time() { assert_lint_count( "This is very different than demo recording, which just simulates a network level connection and lets time move at its own rate.", + "en", NoContractionWithVerb::default(), 0, ); @@ -148,6 +157,7 @@ mod tests { fn dont_flag_lets_play() { assert_lint_count( "Sometimes the umpire lets play continue", + "en", NoContractionWithVerb::default(), 0, ); @@ -159,6 +169,7 @@ mod tests { fn dont_flag_let_sleeping() { assert_lint_count( "Let sleeping logs lie.", + "en", NoContractionWithVerb::default(), 0, ); @@ -170,6 +181,7 @@ mod tests { fn dont_flag_let_processed() { assert_lint_count( "Let processed response be a new structure analogous to server auction response.", + "en", NoContractionWithVerb::default(), 0, ); @@ -181,6 +193,7 @@ mod tests { fn corrects_lets_make_this() { assert_suggestion_result( "Lets make this joke repo into one of the best.", + "en", NoContractionWithVerb::default(), "Let's make this joke repo into one of the best.", ); @@ -192,6 +205,7 @@ mod tests { fn corrects_lets_mock_them() { assert_suggestion_result( "Then lets mock them using Module._load based mocker.", + "en", NoContractionWithVerb::default(), "Then let's mock them using Module._load based mocker.", ); diff --git a/harper-core/src/linting/likewise.rs b/harper-core/src/linting/likewise.rs index 0592e813a0..ef03b244bb 100644 --- a/harper-core/src/linting/likewise.rs +++ b/harper-core/src/linting/likewise.rs @@ -63,6 +63,7 @@ mod tests { fn wise_men() { assert_suggestion_result( "Like wise men, we waited.", + "en", Likewise::default(), "Like wise men, we waited.", ); @@ -72,6 +73,7 @@ mod tests { fn like_wise() { assert_suggestion_result( "He acted, like wise, without hesitation.", + "en", Likewise::default(), "He acted, likewise, without hesitation.", ); diff --git a/harper-core/src/linting/linking_verbs.rs b/harper-core/src/linting/linking_verbs.rs index cc71dabf74..03aec3d679 100644 --- a/harper-core/src/linting/linking_verbs.rs +++ b/harper-core/src/linting/linking_verbs.rs @@ -50,16 +50,16 @@ mod tests { #[test] fn dora() { - assert_lint_count("Dora is a noun.", LinkingVerbs, 0); + assert_lint_count("Dora is a noun.", "en", LinkingVerbs, 0); } #[test] fn working_wrong() { - assert_lint_count("working is not a noun.", LinkingVerbs, 1); + assert_lint_count("working is not a noun.", "en", LinkingVerbs, 1); } #[test] fn working_right() { - assert_lint_count("\"working\" is a noun.", LinkingVerbs, 0); + assert_lint_count("\"working\" is a noun.", "en", LinkingVerbs, 0); } } diff --git a/harper-core/src/linting/lint_group.rs b/harper-core/src/linting/lint_group.rs index 309c9f372a..8315373377 100644 --- a/harper-core/src/linting/lint_group.rs +++ b/harper-core/src/linting/lint_group.rs @@ -85,7 +85,8 @@ pub struct LintGroupConfig { #[cached] fn curated_config() -> LintGroupConfig { // The Dictionary and Dialect do not matter, we're just after the config. - let group = LintGroup::new_curated(MutableDictionary::new().into(), Dialect::American); + // So the language also does not matter right? + let group = LintGroup::new_curated(MutableDictionary::new("en").into(), Dialect::American); group.config } @@ -463,13 +464,13 @@ mod tests { #[test] fn can_get_all_descriptions() { let group = - LintGroup::new_curated(Arc::new(MutableDictionary::default()), Dialect::American); + LintGroup::new_curated(Arc::new(MutableDictionary::new("en")), Dialect::American); group.all_descriptions(); } #[test] fn lint_descriptions_are_clean() { - let mut group = LintGroup::new_curated(FstDictionary::curated(), Dialect::American); + let mut group = LintGroup::new_curated(FstDictionary::curated("en"), Dialect::American); let pairs: Vec<_> = group .all_descriptions() .into_iter() @@ -477,7 +478,7 @@ mod tests { .collect(); for (key, value) in pairs { - let doc = Document::new_markdown_default_curated(&value); + let doc = Document::new_markdown_default_curated(&value, "en"); eprintln!("{key}: {value}"); if !group.lint(&doc).is_empty() { diff --git a/harper-core/src/linting/map_phrase_linter.rs b/harper-core/src/linting/map_phrase_linter.rs index 4bb541513a..181b9bddb1 100644 --- a/harper-core/src/linting/map_phrase_linter.rs +++ b/harper-core/src/linting/map_phrase_linter.rs @@ -3,14 +3,14 @@ use crate::linting::Suggestion; use crate::patterns::{EitherPattern, ExactPhrase, Pattern, SimilarToPhrase}; use crate::{Token, TokenStringExt}; -pub struct MapPhraseLinter { +pub struct MapPhraseLinterEn { description: String, pattern: Box, correct_forms: Vec, message: String, } -impl MapPhraseLinter { +impl MapPhraseLinterEn { pub fn new( pattern: Box, correct_forms: impl IntoIterator, @@ -35,6 +35,7 @@ impl MapPhraseLinter { } pub fn new_exact_phrases( + langiso639: &str, phrase: impl IntoIterator>, correct_forms: impl IntoIterator, message: impl ToString, @@ -44,7 +45,8 @@ impl MapPhraseLinter { phrase .into_iter() .map(|p| { - let pattern: Box = Box::new(ExactPhrase::from_phrase(p.as_ref())); + let pattern: Box = + Box::new(ExactPhrase::from_phrase(p.as_ref(), langiso639)); pattern }) .collect(), @@ -54,13 +56,14 @@ impl MapPhraseLinter { } pub fn new_exact_phrase( + langiso639: &str, phrase: impl AsRef, correct_forms: impl IntoIterator, message: impl ToString, description: impl ToString, ) -> Self { Self::new( - Box::new(ExactPhrase::from_phrase(phrase.as_ref())), + Box::new(ExactPhrase::from_phrase(phrase.as_ref(), langiso639)), correct_forms, message, description, @@ -78,11 +81,11 @@ impl MapPhraseLinter { correct_form.to_string() ); - Self::new_exact_phrase(phrase, [correct_form], message, description) + Self::new_exact_phrase("en", phrase, [correct_form], message, description) } } -impl PatternLinter for MapPhraseLinter { +impl PatternLinter for MapPhraseLinterEn { fn pattern(&self) -> &dyn Pattern { self.pattern.as_ref() } diff --git a/harper-core/src/linting/merge_words.rs b/harper-core/src/linting/merge_words.rs index 108ff2106b..dcda1318c1 100644 --- a/harper-core/src/linting/merge_words.rs +++ b/harper-core/src/linting/merge_words.rs @@ -11,16 +11,16 @@ pub struct MergeWords { } impl MergeWords { - pub fn new() -> Self { + pub fn new(langiso639: &str) -> Self { Self { - dict: FstDictionary::curated(), + dict: FstDictionary::curated(langiso639), } } } impl Default for MergeWords { fn default() -> Self { - Self::new() + Self::new("en") } } @@ -101,6 +101,7 @@ mod tests { fn clean() { assert_lint_count( "When referring to the political party, make sure to treat them as a proper noun.", + "en", MergeWords::default(), 0, ); @@ -110,6 +111,7 @@ mod tests { fn heretofore() { assert_lint_count( "This is a her etofore unseen problem.", + "en", MergeWords::default(), 1, ); @@ -117,17 +119,22 @@ mod tests { #[test] fn therefore() { - assert_lint_count("The refore", MergeWords::default(), 1); + assert_lint_count("The refore", "en", MergeWords::default(), 1); } #[test] fn that_is_contraction() { - assert_suggestion_result("That s", MergeWords::default(), "That's"); + assert_suggestion_result("That s", "en", MergeWords::default(), "That's"); } #[test] fn allows_issue_722() { - assert_lint_count("Leaving S and K alone.", MergeWords::default(), 0); - assert_lint_count("Similarly an S with a line.", MergeWords::default(), 0); + assert_lint_count("Leaving S and K alone.", "en", MergeWords::default(), 0); + assert_lint_count( + "Similarly an S with a line.", + "en", + MergeWords::default(), + 0, + ); } } diff --git a/harper-core/src/linting/mod.rs b/harper-core/src/linting/mod.rs index 104a78299b..79e8b98e62 100644 --- a/harper-core/src/linting/mod.rs +++ b/harper-core/src/linting/mod.rs @@ -105,7 +105,7 @@ pub use lint::Lint; pub use lint_group::{LintGroup, LintGroupConfig}; pub use lint_kind::LintKind; pub use long_sentences::LongSentences; -pub use map_phrase_linter::MapPhraseLinter; +pub use map_phrase_linter::MapPhraseLinterEn; pub use merge_words::MergeWords; pub use modal_of::ModalOf; pub use multiple_sequential_pronouns::MultipleSequentialPronouns; @@ -160,8 +160,8 @@ mod tests { use crate::{Document, FstDictionary, parsers::PlainEnglish}; #[track_caller] - pub fn assert_lint_count(text: &str, mut linter: impl Linter, count: usize) { - let test = Document::new_markdown_default_curated(text); + pub fn assert_lint_count(text: &str, langiso639: &str, mut linter: impl Linter, count: usize) { + let test = Document::new_markdown_default_curated(text, langiso639); let lints = linter.lint(&test); dbg!(&lints); if lints.len() != count { @@ -175,8 +175,13 @@ mod tests { /// Assert the total number of suggestions produced by a [`Linter`], spread across all produced /// [`Lint`]s. #[track_caller] - pub fn assert_suggestion_count(text: &str, mut linter: impl Linter, count: usize) { - let test = Document::new_markdown_default_curated(text); + pub fn assert_suggestion_count( + text: &str, + langiso639: &str, + mut linter: impl Linter, + count: usize, + ) { + let test = Document::new_markdown_default_curated(text, langiso639); let lints = linter.lint(&test); assert_eq!( lints.iter().map(|l| l.suggestions.len()).sum::(), @@ -191,6 +196,7 @@ mod tests { #[track_caller] pub fn assert_nth_suggestion_result( text: &str, + langiso639: &str, mut linter: impl Linter, expected_result: &str, n: usize, @@ -205,7 +211,7 @@ mod tests { let test = Document::new_from_vec( text_chars.clone().into(), &PlainEnglish, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); let lints = linter.lint(&test); @@ -238,13 +244,18 @@ mod tests { } // Applying the suggestions should fix all the lints. - assert_lint_count(&transformed_str, linter, 0); + assert_lint_count(&transformed_str, langiso639, linter, 0); } /// Runs a provided linter on text, applies the first suggestion from each lint /// and asserts whether the result is equal to a given value. #[track_caller] - pub fn assert_suggestion_result(text: &str, linter: impl Linter, expected_result: &str) { - assert_nth_suggestion_result(text, linter, expected_result, 0); + pub fn assert_suggestion_result( + text: &str, + langiso639: &str, + linter: impl Linter, + expected_result: &str, + ) { + assert_nth_suggestion_result(text, langiso639, linter, expected_result, 0); } } diff --git a/harper-core/src/linting/modal_of.rs b/harper-core/src/linting/modal_of.rs index e5b1291e6f..8fe6f10c63 100644 --- a/harper-core/src/linting/modal_of.rs +++ b/harper-core/src/linting/modal_of.rs @@ -133,37 +133,37 @@ mod tests { #[test] fn test_lowercase() { - assert_suggestion_result("could of", ModalOf::default(), "could have"); + assert_suggestion_result("could of", "en", ModalOf::default(), "could have"); } #[test] fn test_negative() { - assert_suggestion_result("mightn't of", ModalOf::default(), "mightn't have"); + assert_suggestion_result("mightn't of", "en", ModalOf::default(), "mightn't have"); } #[test] fn test_uppercase_negative() { - assert_suggestion_result("Mustn't of", ModalOf::default(), "Mustn't have"); + assert_suggestion_result("Mustn't of", "en", ModalOf::default(), "Mustn't have"); } #[test] fn test_false_positive_of_course() { - assert_lint_count("should of course", ModalOf::default(), 0); + assert_lint_count("should of course", "en", ModalOf::default(), 0); } #[test] fn test_false_positive_the_might_of() { - assert_lint_count("the might of", ModalOf::default(), 0); + assert_lint_count("the might of", "en", ModalOf::default(), 0); } #[test] fn test_false_positive_great_might_of() { - assert_lint_count("great might of", ModalOf::default(), 0); + assert_lint_count("great might of", "en", ModalOf::default(), 0); } #[test] fn test_false_positive_capital_negative() { - assert_lint_count("Wouldn't of course", ModalOf::default(), 0); + assert_lint_count("Wouldn't of course", "en", ModalOf::default(), 0); } // real-world tests @@ -172,6 +172,7 @@ mod tests { fn test_buggy_implementation() { assert_lint_count( "... could of just been a buggy implementation", + "en", ModalOf::default(), 1, ); @@ -181,6 +182,7 @@ mod tests { fn test_missed_one() { assert_lint_count( "We already have a function ... that nedb can understand so we might of missed one.", + "en", ModalOf::default(), 1, ); @@ -190,6 +192,7 @@ mod tests { fn test_user_option() { assert_lint_count( "im more likely to believe you might of left in the 'user' option", + "en", ModalOf::default(), 1, ); @@ -199,6 +202,7 @@ mod tests { fn catches_must_of() { assert_suggestion_result( "Ah I must of missed that part.", + "en", ModalOf::default(), "Ah I must have missed that part.", ); @@ -208,6 +212,7 @@ mod tests { fn catches_should_of() { assert_lint_count( "Yeah I should of just mentioned it should of been a for of.", + "en", ModalOf::default(), 2, ); @@ -217,6 +222,7 @@ mod tests { fn catches_would_of() { assert_suggestion_result( "now this issue would of caused hundreds of thousands of extra lines", + "en", ModalOf::default(), "now this issue would have caused hundreds of thousands of extra lines", ); @@ -226,6 +232,7 @@ mod tests { fn doesnt_catch_you_could_of_course() { assert_lint_count( "You could of course explicit the else with each possibility", + "en", ModalOf::default(), 0, ); @@ -235,6 +242,7 @@ mod tests { fn doesnt_catch_compiler_could_of_course() { assert_lint_count( "The compiler could of course detect this too", + "en", ModalOf::default(), 0, ); @@ -244,6 +252,7 @@ mod tests { fn doesnt_catch_might_of_course_be() { assert_lint_count( "There might of course be other places where not implementing the IMemberSource might break ...", + "en", ModalOf::default(), 0, ); @@ -253,6 +262,7 @@ mod tests { fn doesnt_catch_not_a_must_of_course() { assert_lint_count( "Not a must of course if the convention should be .ts", + "en", ModalOf::default(), 0, ); @@ -262,6 +272,7 @@ mod tests { fn doesnt_catch_must_of_course_also() { assert_lint_count( "the schedular must of course also have run through", + "en", ModalOf::default(), 0, ); @@ -271,6 +282,7 @@ mod tests { fn doesnt_catch_should_of_course_not() { assert_lint_count( "not being local should of course not be supported", + "en", ModalOf::default(), 0, ); @@ -280,6 +292,7 @@ mod tests { fn doesnt_catch_would_of_course_just() { assert_lint_count( "I would of course just test this by compiling with MATX_MULTI_GPU=ON", + "en", ModalOf::default(), 0, ); @@ -287,13 +300,19 @@ mod tests { #[test] fn doesnt_catch_to_take_on_the_full_might_of_nato() { - assert_lint_count("To take on the full might of NATO.", ModalOf::default(), 0); + assert_lint_count( + "To take on the full might of NATO.", + "en", + ModalOf::default(), + 0, + ); } #[test] fn doesnt_catch_mixed_case_of_course() { assert_lint_count( "... for now you could of Course put ...", + "en", ModalOf::default(), 0, ); @@ -301,6 +320,11 @@ mod tests { #[test] fn catches_mixed_case_could_of_put() { - assert_lint_count("... for now you could of Put ...", ModalOf::default(), 1); + assert_lint_count( + "... for now you could of Put ...", + "en", + ModalOf::default(), + 1, + ); } } diff --git a/harper-core/src/linting/multiple_sequential_pronouns.rs b/harper-core/src/linting/multiple_sequential_pronouns.rs index 2fd77d9c7d..fbc83f6db2 100644 --- a/harper-core/src/linting/multiple_sequential_pronouns.rs +++ b/harper-core/src/linting/multiple_sequential_pronouns.rs @@ -141,6 +141,7 @@ mod tests { fn can_detect_two_pronouns() { assert_lint_count( "...little bit about my I want to do.", + "en", MultipleSequentialPronouns::new(), 1, ) @@ -150,6 +151,7 @@ mod tests { fn can_detect_three_pronouns() { assert_lint_count( "...little bit about my I you want to do.", + "en", MultipleSequentialPronouns::new(), 1, ) @@ -159,6 +161,7 @@ mod tests { fn allows_single_pronouns() { assert_lint_count( "...little bit about I want to do.", + "en", MultipleSequentialPronouns::new(), 0, ) @@ -168,6 +171,7 @@ mod tests { fn detects_multiple_pronouns_at_end() { assert_lint_count( "...I need to explain this to you them.", + "en", MultipleSequentialPronouns::new(), 1, ) @@ -175,13 +179,19 @@ mod tests { #[test] fn comma_separated() { - assert_lint_count("To prove it, we...", MultipleSequentialPronouns::new(), 0) + assert_lint_count( + "To prove it, we...", + "en", + MultipleSequentialPronouns::new(), + 0, + ) } #[test] fn dont_flag_578() { assert_lint_count( "I can lend you my car.", + "en", MultipleSequentialPronouns::new(), 0, ) @@ -191,6 +201,7 @@ mod tests { fn dont_flag_724() { assert_lint_count( "One told me they were able to begin reading.", + "en", MultipleSequentialPronouns::new(), 0, ) @@ -200,6 +211,7 @@ mod tests { fn dont_flag_us() { assert_lint_count( "Take the plunge and pull plug from their US tech.", + "en", MultipleSequentialPronouns::new(), 0, ) @@ -209,6 +221,7 @@ mod tests { fn dont_flag_my_us_your_us() { assert_lint_count( "My US passport looks different from your US passport.", + "en", MultipleSequentialPronouns::new(), 0, ) @@ -218,6 +231,7 @@ mod tests { fn dont_flag_subject_after_usa() { assert_lint_count( "And if it’s manufactured in the US it may have more automation.", + "en", MultipleSequentialPronouns::new(), 0, ) @@ -227,6 +241,7 @@ mod tests { fn dont_flag_case_insensitive_cost_him_his_life() { assert_lint_count( "to the point where it very well likely cost Him his life", + "en", MultipleSequentialPronouns::new(), 0, ) diff --git a/harper-core/src/linting/no_oxford_comma.rs b/harper-core/src/linting/no_oxford_comma.rs index 143ef96bb4..8db7a76e76 100644 --- a/harper-core/src/linting/no_oxford_comma.rs +++ b/harper-core/src/linting/no_oxford_comma.rs @@ -95,6 +95,7 @@ mod tests { fn fruits() { assert_lint_count( "An apple, a banana, and a pear", + "en", NoOxfordComma::default(), 1, ); @@ -104,6 +105,7 @@ mod tests { fn people() { assert_suggestion_result( "Nancy, Steve, and Carl are going to the coffee shop.", + "en", NoOxfordComma::default(), "Nancy, Steve and Carl are going to the coffee shop.", ); @@ -113,6 +115,7 @@ mod tests { fn places() { assert_suggestion_result( "I've always wanted to visit Paris, Tokyo, and Rome.", + "en", NoOxfordComma::default(), "I've always wanted to visit Paris, Tokyo and Rome.", ); @@ -122,6 +125,7 @@ mod tests { fn foods() { assert_suggestion_result( "My favorite foods are pizza, sushi, tacos, and burgers.", + "en", NoOxfordComma::default(), "My favorite foods are pizza, sushi, tacos and burgers.", ); @@ -131,6 +135,7 @@ mod tests { fn allows_clean_music() { assert_lint_count( "I enjoy listening to pop music, rock, hip-hop, electronic dance and classical music.", + "en", NoOxfordComma::default(), 0, ); @@ -140,6 +145,7 @@ mod tests { fn allows_clean_nations() { assert_lint_count( "The team consists of players from different countries: France, Germany, Italy and Spain.", + "en", NoOxfordComma::default(), 0, ); @@ -149,6 +155,7 @@ mod tests { fn or_writing() { assert_suggestion_result( "Harper can be a lifesaver when writing technical documents, emails, or other formal forms of communication.", + "en", NoOxfordComma::default(), "Harper can be a lifesaver when writing technical documents, emails or other formal forms of communication.", ); @@ -158,6 +165,7 @@ mod tests { fn sports() { assert_suggestion_result( "They enjoy playing soccer, basketball, or tennis.", + "en", NoOxfordComma::default(), "They enjoy playing soccer, basketball or tennis.", ); @@ -167,6 +175,7 @@ mod tests { fn nor_vegetables() { assert_suggestion_result( "I like carrots, kale, nor broccoli.", + "en", NoOxfordComma::default(), "I like carrots, kale nor broccoli.", ); diff --git a/harper-core/src/linting/nobody.rs b/harper-core/src/linting/nobody.rs index 68b6d74033..7ee9f63b93 100644 --- a/harper-core/src/linting/nobody.rs +++ b/harper-core/src/linting/nobody.rs @@ -57,6 +57,7 @@ mod tests { fn both_valid_and_invalid() { assert_suggestion_result( "No body told me. I have a head but no body.", + "en", Nobody::default(), "Nobody told me. I have a head but no body.", ); diff --git a/harper-core/src/linting/number_suffix_capitalization.rs b/harper-core/src/linting/number_suffix_capitalization.rs index d4d4205e5a..640975753e 100644 --- a/harper-core/src/linting/number_suffix_capitalization.rs +++ b/harper-core/src/linting/number_suffix_capitalization.rs @@ -48,16 +48,16 @@ mod tests { #[test] fn detects_uppercase_suffix() { - assert_lint_count("2ND", NumberSuffixCapitalization, 1); + assert_lint_count("2ND", "en", NumberSuffixCapitalization, 1); } #[test] fn detects_inconsistent_suffix() { - assert_lint_count("2nD", NumberSuffixCapitalization, 1); + assert_lint_count("2nD", "en", NumberSuffixCapitalization, 1); } #[test] fn passes_correct_case() { - assert_lint_count("2nd", NumberSuffixCapitalization, 0); + assert_lint_count("2nd", "en", NumberSuffixCapitalization, 0); } } diff --git a/harper-core/src/linting/of_course.rs b/harper-core/src/linting/of_course.rs index 9f69b07e4b..468c268f25 100644 --- a/harper-core/src/linting/of_course.rs +++ b/harper-core/src/linting/of_course.rs @@ -82,13 +82,19 @@ mod tests { #[test] fn flags_of_curse() { - assert_suggestion_result("Yes, of curse!", OfCourse::default(), "Yes, of course!"); + assert_suggestion_result( + "Yes, of curse!", + "en", + OfCourse::default(), + "Yes, of course!", + ); } #[test] fn flags_of_corse() { assert_suggestion_result( "Well, of corse we can.", + "en", OfCourse::default(), "Well, of course we can.", ); @@ -96,18 +102,29 @@ mod tests { #[test] fn ignores_kind_of_curse() { - assert_lint_count("This kind of curse is dangerous.", OfCourse::default(), 0); + assert_lint_count( + "This kind of curse is dangerous.", + "en", + OfCourse::default(), + 0, + ); } #[test] fn ignores_sort_of_curse() { - assert_lint_count("It's a sort of curse that lingers.", OfCourse::default(), 0); + assert_lint_count( + "It's a sort of curse that lingers.", + "en", + OfCourse::default(), + 0, + ); } #[test] fn ignores_curse_of_title() { assert_lint_count( "The Curse of Strahd is a famous module.", + "en", OfCourse::default(), 0, ); diff --git a/harper-core/src/linting/out_of_date.rs b/harper-core/src/linting/out_of_date.rs index 00c31fd9ce..be658e4e17 100644 --- a/harper-core/src/linting/out_of_date.rs +++ b/harper-core/src/linting/out_of_date.rs @@ -12,9 +12,9 @@ pub struct OutOfDate { impl Default for OutOfDate { fn default() -> Self { let pattern = EitherPattern::new(vec![ - Box::new(ExactPhrase::from_phrase("out of date")), - Box::new(ExactPhrase::from_phrase("out-of date")), - Box::new(ExactPhrase::from_phrase("out of-date")), + Box::new(ExactPhrase::from_phrase("out of date", "en")), + Box::new(ExactPhrase::from_phrase("out-of date", "en")), + Box::new(ExactPhrase::from_phrase("out of-date", "en")), ]); Self { @@ -58,6 +58,7 @@ mod tests { fn corrects_out_of_date() { assert_suggestion_result( "The software is out of date.", + "en", OutOfDate::default(), "The software is out-of-date.", ); @@ -67,6 +68,7 @@ mod tests { fn corrects_out_of_date_with_variation() { assert_suggestion_result( "This information is out of-date.", + "en", OutOfDate::default(), "This information is out-of-date.", ); @@ -76,6 +78,7 @@ mod tests { fn allows_correct_usage() { assert_suggestion_result( "The guidelines are out-of-date.", + "en", OutOfDate::default(), "The guidelines are out-of-date.", ); diff --git a/harper-core/src/linting/oxford_comma.rs b/harper-core/src/linting/oxford_comma.rs index a825c597c2..9ff9ed818a 100644 --- a/harper-core/src/linting/oxford_comma.rs +++ b/harper-core/src/linting/oxford_comma.rs @@ -115,6 +115,7 @@ mod tests { fn fruits() { assert_lint_count( "An apple, a banana and a pear walk into a bar.", + "en", OxfordComma::default(), 1, ); @@ -124,6 +125,7 @@ mod tests { fn people() { assert_suggestion_result( "Nancy, Steve and Carl are going to the coffee shop.", + "en", OxfordComma::default(), "Nancy, Steve, and Carl are going to the coffee shop.", ); @@ -133,6 +135,7 @@ mod tests { fn places() { assert_suggestion_result( "I've always wanted to visit Paris, Tokyo and Rome.", + "en", OxfordComma::default(), "I've always wanted to visit Paris, Tokyo, and Rome.", ); @@ -142,6 +145,7 @@ mod tests { fn foods() { assert_suggestion_result( "My favorite foods are pizza, sushi, tacos and burgers.", + "en", OxfordComma::default(), "My favorite foods are pizza, sushi, tacos, and burgers.", ); @@ -151,6 +155,7 @@ mod tests { fn allows_clean_music() { assert_lint_count( "I enjoy listening to pop music, rock, hip-hop, electronic dance, and classical music.", + "en", OxfordComma::default(), 0, ); @@ -160,6 +165,7 @@ mod tests { fn allows_clean_nations() { assert_lint_count( "The team consists of players from different countries: France, Germany, Italy, and Spain.", + "en", OxfordComma::default(), 0, ); @@ -169,6 +175,7 @@ mod tests { fn or_writing() { assert_suggestion_result( "Harper can be a lifesaver when writing technical documents, emails or other formal forms of communication.", + "en", OxfordComma::default(), "Harper can be a lifesaver when writing technical documents, emails, or other formal forms of communication.", ); @@ -178,6 +185,7 @@ mod tests { fn sports() { assert_suggestion_result( "They enjoy playing soccer, basketball or tennis.", + "en", OxfordComma::default(), "They enjoy playing soccer, basketball, or tennis.", ); @@ -187,6 +195,7 @@ mod tests { fn nor_vegetables() { assert_suggestion_result( "I like carrots, kale nor broccoli.", + "en", OxfordComma::default(), "I like carrots, kale, nor broccoli.", ); @@ -196,6 +205,7 @@ mod tests { fn allow_non_list_transportation() { assert_lint_count( "In transportation, autonomous vehicles and smart traffic management systems promise to reduce accidents and optimize travel routes.", + "en", OxfordComma::default(), 0, ); @@ -205,6 +215,7 @@ mod tests { fn allow_pill() { assert_lint_count( "Develop a pill that causes partial amnesia, affecting relationships and identity.", + "en", OxfordComma::default(), 0, ); @@ -214,6 +225,7 @@ mod tests { fn allow_at_first() { assert_lint_count( "In the heart of a bustling city, Sarah finds herself trapped in an endless cycle of the same day. Each morning, she awakens to find the date unchanged, her life on repeat. At first, confusion and frustration cloud her thoughts, but soon she notices something peculiar—each day has tiny differences, subtle changes that hint at a larger pattern.", + "en", OxfordComma::default(), 0, ); @@ -223,6 +235,7 @@ mod tests { fn allow_standoff() { assert_lint_count( "In a tense standoff, Alex and his reflection engage in a battle of wills.", + "en", OxfordComma::default(), 0, ); diff --git a/harper-core/src/linting/oxymorons.rs b/harper-core/src/linting/oxymorons.rs index 78e230b537..a2e6e67291 100644 --- a/harper-core/src/linting/oxymorons.rs +++ b/harper-core/src/linting/oxymorons.rs @@ -33,7 +33,7 @@ impl Oxymorons { // Build a vector of exact-match patterns for each oxymoron. let patterns: Vec> = phrases .into_iter() - .map(|s| Box::new(ExactPhrase::from_phrase(s)) as Box) + .map(|s| Box::new(ExactPhrase::from_phrase(s, "en")) as Box) .collect(); let pattern = Box::new(EitherPattern::new(patterns)); @@ -77,13 +77,19 @@ mod tests { #[test] fn detects_amateur_expert() { - assert_lint_count("The amateur expert gave his opinion.", Oxymorons::new(), 1); + assert_lint_count( + "The amateur expert gave his opinion.", + "en", + Oxymorons::new(), + 1, + ); } #[test] fn detects_increasingly_less() { assert_lint_count( "The solution was increasingly less effective.", + "en", Oxymorons::new(), 1, ); @@ -91,13 +97,19 @@ mod tests { #[test] fn detects_advancing_backwards() { - assert_lint_count("The project is advancing backwards?", Oxymorons::new(), 1); + assert_lint_count( + "The project is advancing backwards?", + "en", + Oxymorons::new(), + 1, + ); } #[test] fn detects_alludes_explicitly_to() { assert_lint_count( "The report alludes explicitly to several issues.", + "en", Oxymorons::new(), 1, ); @@ -107,6 +119,7 @@ mod tests { fn detects_explicitly_alludes_to() { assert_lint_count( "The report explicitly alludes to several issues.", + "en", Oxymorons::new(), 1, ); @@ -114,13 +127,19 @@ mod tests { #[test] fn does_not_flag_clean_text() { - assert_lint_count("The expert provided clear advice.", Oxymorons::new(), 0); + assert_lint_count( + "The expert provided clear advice.", + "en", + Oxymorons::new(), + 0, + ); } #[test] fn lowercase_match() { assert_lint_count( "the amateur expert is often unreliable.", + "en", Oxymorons::new(), 1, ); @@ -128,13 +147,14 @@ mod tests { #[test] fn phrase_with_extra_whitespace() { - assert_lint_count("An organized mess was found.", Oxymorons::new(), 1); + assert_lint_count("An organized mess was found.", "en", Oxymorons::new(), 1); } #[test] fn phrase_split_by_line_break() { assert_lint_count( "nonworking\nmother is not a term to be used.", + "en", Oxymorons::new(), 1, ); diff --git a/harper-core/src/linting/phrase_corrections.rs b/harper-core/src/linting/phrase_corrections.rs index 3fd326eac6..bf71466cc5 100644 --- a/harper-core/src/linting/phrase_corrections.rs +++ b/harper-core/src/linting/phrase_corrections.rs @@ -1,4 +1,4 @@ -use super::{LintGroup, MapPhraseLinter}; +use super::{LintGroup, MapPhraseLinterEn}; /// Produce a [`LintGroup`] that looks for errors in common phrases. /// Comes pre-configured with the recommended default settings. @@ -7,13 +7,14 @@ pub fn lint_group() -> LintGroup { macro_rules! add_exact_mappings { ($group:expr, { - $($name:expr => ($input:expr, $corrections:expr, $hint:expr, $description:expr)),+ $(,)? + $($name:expr => ($langiso639:expr, $input:expr, $corrections:expr, $hint:expr, $description:expr)),+ $(,)? }) => { $( $group.add_pattern_linter( $name, Box::new( - MapPhraseLinter::new_exact_phrases( + MapPhraseLinterEn::new_exact_phrases( + $langiso639, $input, $corrections, $hint, @@ -28,6 +29,7 @@ pub fn lint_group() -> LintGroup { add_exact_mappings!(group, { // The name of the rule "ChangeTack" => ( + "en", // The exact phrase(s) to look for. ["change tact", "change tacks", "change tacts"], // The corrections to provide. @@ -38,600 +40,700 @@ pub fn lint_group() -> LintGroup { "Locates errors in the idiom `to change tack` to convey the correct meaning of altering one's course or strategy." ), "ChangedTack" => ( + "en", ["changed tact", "changed tacks", "changed tacts"], ["changed tack"], "Did you mean `changed tack`? This idiom is commonly used to indicate a change in direction or approach.", "Locates errors in the idiom `to change tack` to convey the correct meaning of altering one's course or strategy." ), "ChangesTack" => ( + "en", ["changes tact", "changes tacks", "changes tacts"], ["changes tack"], "Did you mean `changes tack`? This idiom is commonly used to indicate a change in direction or approach.", "Locates errors in the idiom `to change tack` to convey the correct meaning of altering one's course or strategy." ), "ChangingTack" => ( + "en", ["changing tact", "changing tacks", "changing tacts"], ["changing tack"], "Did you mean `changing tack`? This idiom is commonly used to indicate a change in direction or approach.", "Locates errors in the idiom `to change tack` to convey the correct meaning of altering one's course or strategy." ), "ChangeOfTack" => ( + "en", ["change of tact", "change of tacks", "change of tacts"], ["change of tack"], "Did you mean `change of tack`? This idiom is commonly used to indicate a change in direction or approach.", "Locates errors in the idiom `change of tack` to convey the correct meaning of an alternative course or strategy." ), "ChangesOfTack" => ( + "en", ["changes of tact", "changes of tacks", "changes of tacts"], ["changes of tack"], "Did you mean `changes of tack`? This idiom is commonly used to indicate changes in direction or approach.", "Locates errors in the idiom `change of tack` to convey the correct meaning of an alternative course or strategy." ), "ChangingOfTack" => ( + "en", ["changing of tact", "changing of tacks", "changing of tacts"], ["changing of tack"], "Did you mean `changing of tack`? This idiom is commonly used to indicate a change in direction or approach.", "Locates errors in the idiom `to change of tack` to convey the correct meaning of altering one's course or strategy." ), "WantBe" => ( + "en", ["want be"], ["won't be", "want to be"], "Did you mean `won't be` or `want to be`?", "Detects incorrect usage of `want be` and suggests `won't be` or `want to be` based on context." ), "StateOfTheArt" => ( + "en", ["state of art"], ["state of the art"], "Did you mean `state of the art`?", "Detects incorrect usage of `state of art` and suggests `state of the art` as the correct phrase." ), "FaceFirst" => ( + "en", ["face first into"], ["face-first into"], "Should this be `face-first`?", "Ensures `face first` is correctly hyphenated as `face-first` when used before `into`." ), "EludedTo" => ( + "en", ["eluded to"], ["alluded to"], "Did you mean `alluded to`?", "Corrects `eluded to` to `alluded to` in contexts referring to indirect references." ), "BaitedBreath" => ( + "en", ["baited breath"], ["bated breath"], "Did you mean `bated breath`?", "Ensures `bated breath` is written correctly, as `baited breath` is incorrect." ), "BareInMind" => ( + "en", ["bare in mind"], ["bear in mind"], "Did you mean `bear in mind`?", "Ensures the phrase `bear in mind` is used correctly instead of `bare in mind`." ), "MutePoint" => ( + "en", ["mute point"], ["moot point"], "Did you mean `moot point`?", "Ensures `moot point` is used instead of `mute point`, as `moot` means debatable or irrelevant." ), "RoadMap" => ( + "en", ["roadmap"], ["road map"], "Did you mean `road map`?", "Detects when `roadmap` is used instead of `road map`, prompting the correct spacing." ), "SameAs" => ( + "en", ["same then"], ["same as"], "Did you mean `same as`?", "Corrects the incorrect phrase `same then` to the standard `same as`." ), "SoonerOrLater" => ( + "en", ["sooner than later"], ["sooner rather than later", "sooner or later"], "Did you mean `sooner rather than later` or `sooner or later`?", "Fixes the improper phrase `sooner than later` by suggesting standard alternatives." ), "HadOf" => ( + "en", ["had of"], ["had have", "had've"], "Did you mean `had have` or `had've`?", "Flags the unnecessary use of `of` after `had` and suggests the correct forms." ), "FatalOutcome" => ( + "en", ["fatal outcome"], ["death"], "Consider using `death` for clarity.", "Replaces `fatal outcome` with the more direct term `death` for conciseness." ), "NotTo" => ( + "en", ["no to"], ["not to"], "Did you mean `not to`?", "Corrects `no to` to `not to`, ensuring proper negation." ), "ThatThis" => ( + "en", ["the this"], ["that this"], "Did you mean `that this`?", "Fixes `the this` to the correct phrase `that this`." ), "CondenseAllThe" => ( + "en", ["all of the"], ["all the"], "Consider simplifying to `all the`.", "Suggests removing `of` in `all of the` for a more concise phrase." ), "AvoidAndAlso" => ( + "en", ["and also"], ["and"], "Consider using just `and`.", "Reduces redundancy by replacing `and also` with `and`." ), "AndIn" => ( + "en", ["an in"], ["and in"], "Did you mean `and in`?", "Fixes the incorrect phrase `an in` to `and in` for proper conjunction usage." ), "BeenThere" => ( + "en", ["bee there"], ["been there"], "Did you mean `been there`?", "Corrects the misspelling `bee there` to the proper phrase `been there`." ), "CanBeSeen" => ( + "en", ["can be seem"], ["can be seen"], "Did you mean `can be seen`?", "Corrects `can be seem` to the proper phrase `can be seen`." ), "GoingTo" => ( + "en", ["gong to"], ["going to"], "Did you mean `going to`?", "Corrects `gong to` to the intended phrase `going to`." ), "IAm" => ( + "en", ["I a m"], ["I am"], "Did you mean `I am`?", "Fixes the incorrect spacing in `I a m` to properly form `I am`." ), "ItCan" => ( + "en", ["It cam"], ["It can"], "Did you mean `It can`?", "Corrects the misspelling `It cam` to the proper phrase `It can`." ), "MyHouse" => ( + "en", ["mu house"], ["my house"], "Did you mean `my house`?", "Fixes the typo `mu house` to `my house`." ), "OperativeSystem" => ( + "en", ["operative system"], ["operating system"], "Did you mean `operating system`?", "Ensures `operating system` is used correctly instead of `operative system`." ), "OperativeSystems" => ( + "en", ["operative systems"], ["operating systems"], "Did you mean `operating systems`?", "Ensures `operating systems` is used correctly instead of `operative systems`." ), "BanTogether" => ( + "en", ["ban together"], ["band together"], "Did you mean `band together`?", "Detects and corrects the common error of using `ban together` instead of the idiom `band together`, which means to unite or join forces." ), "WaveFunction" => ( + "en", ["wavefunction"], ["wave function"], "Did you mean `wave function`?", "Identifies the mistake of merging `wave` and `function` into one word. In quantum mechanics, a `wave function` (written as two words) describes the mathematical function that represents the quantum state of a particle or system. Correct usage is crucial for clear and accurate scientific communication." ), "InThe" => ( + "en", ["int he"], ["in the"], "Did you mean `in the`?", "Detects and corrects a spacing error where `in the` is mistakenly written as `int he`. Proper spacing is essential for readability and grammatical correctness in common phrases." ), "WillContain" => ( + "en", ["will contains"], ["will contain"], "Did you mean `will contain`?", "Incorrect verb form: `will` should be followed by the base form `contain`." ), "IsKnownFor" => ( + "en", ["is know for"], ["is known for"], "Did you mean `is known for`?", "Typo: `known` is the correct past participle." ), "PointIsMoot" => ( + "en", ["your point is mute"], ["your point is moot"], "Did you mean `your point is moot`?", "Typo: `moot` (meaning debatable) is correct rather than `mute`." ), "ByAccident" => ( + "en", ["on accident"], ["by accident"], "Did you mean `by accident`?", "Incorrect preposition: `by accident` is the idiomatic expression." ), "ThatChallenged" => ( + "en", ["the challenged"], ["that challenged"], "Did you mean `that challenged`?", "Changes `the challenged` to `that challenged` to fix the misspelling." ), "TurnItOff" => ( + "en", ["turn it of", "turn i of"], ["turn it off"], "Did you mean `turn it off`?", "Fixes the mistake in the phrase `turn it off`." ), "HumanLife" => ( + "en", ["human live"], ["human life"], "Did you mean `human life`?", "Changes `human live` to `human life`." ), "NeedHelp" => ( + "en", ["ned help"], ["need help"], "Did you mean `need help`?", "Changes `ned help` to the correct `need help`." ), "AndTheLike" => ( + "en", ["an the like"], ["and the like"], "Did you mean `and the like`?", "Fixes the typo in `and the like`." ), "BatedBreath" => ( + "en", ["baited breath"], ["bated breath"], "Did you mean `bated breath`?", "Changes `baited breath` to the correct `bated breath`." ), "BeckAndCall" => ( + "en", ["back and call"], ["beck and call"], "Did you mean `beck and call`?", "Fixes `back and call` to `beck and call`." ), "LetAlone" => ( + "en", ["let along"], ["let alone"], "Did you mean `let alone`?", "Changes `let along` to `let alone`." ), "SneakingSuspicion" => ( + "en", ["sneaky suspicion"], ["sneaking suspicion"], "Did you mean `sneaking suspicion`?", "Changes `sneaky suspicion` to `sneaking suspicion`." ), "SpecialAttention" => ( + "en", ["spacial attention"], ["special attention"], "Did you mean `special attention`?", "Changes `spacial attention` to `special attention`." ), "SupposedTo" => ( + "en", ["suppose to"], ["supposed to"], "Did you mean `supposed to`?", "Fixes `suppose to` to the correct `supposed to`." ), "KindRegards" => ( + "en", ["kid regards"], ["kind regards"], "Did you mean `kind regards`?", "Changes `kid regards` to `kind regards`." ), "ThoughtProcess" => ( + "en", ["though process"], ["thought process"], "Did you mean `thought process`?", "Changes `though process` to `thought process`." ), "BadRap" => ( + "en", ["bed rap", "bad rep"], ["bad rap"], "Did you mean `bad rap`?", "Changes `bed rap` to the proper idiom `bad rap`." ), "OfCourse" => ( + "en", ["off course", "o course"], ["Of course"], "Did you mean `of course`?", "Detects the non‐idiomatic phrase `off course` and suggests the correct form `of course`." ), "FastPaste" => ( + "en", ["fast paste", "fast-paste"], ["fast-paced"], "Did you mean `fast-paced`?", "Detects incorrect usage of `fast paste` or `fast-paste` and suggests `fast-paced` as the correct phrase." ), "EnMasse" => ( + "en", ["on mass", "on masse", "in mass"], ["en masse"], "Did you mean `en masse`?", "Detects variants like `on mass` or `in mass` and suggests `en masse`." ), "HungerPang" => ( + "en", ["hunger pain"], ["hunger pang"], "Did you mean `hunger pang`?", "Corrects `hunger pain` to `hunger pang`." ), "GetRidOff" => ( + "en", ["get rid off", "get ride of", "get ride off"], ["get rid of"], "Did you mean `get rid of`?", "Ensures `get rid of` is used instead of `get rid off`." ), "GetsRidOff" => ( + "en", ["gets rid off", "gets ride of", "gets ride off"], ["gets rid of"], "Did you mean `gets rid of`?", "Ensures `gets rid of` is used instead of `gets rid off`." ), "GettingRidOff" => ( + "en", ["getting rid off", "getting ride of", "getting ride off"], ["getting rid of"], "Did you mean `getting rid of`?", "Ensures `getting rid of` is used instead of `getting rid off`." ), "GotRidOff" => ( + "en", ["got rid off", "got ride of", "got ride off"], ["got rid of"], "Did you mean `got rid of`?", "Ensures `got rid of` is used instead of `got rid off`." ), "GottenRidOff" => ( + "en", ["gotten rid off", "gotten ride of", "gotten ride off"], ["gotten rid of"], "Did you mean `gotten rid of`?", "Ensures `gotten rid of` is used instead of `gotten rid off`." ), "LastButNotLeast" => ( + "en", ["last but not the least", "last, but not the least", "last but, not least", "last but not last"], ["last but not least"], "Use the more idiomatic phrasing.", "Corrects common errors in the phrase `last but not least`." ), "BlanketStatement" => ( + "en", ["blanketed statement"], ["blanket statement"], "Use the more idiomatic phrasing.", "Corrects common errors in the phrase `blanket statement`." ), "SpokeTooSoon" => ( + "en", ["spoke to soon"], ["spoke too soon"], "Use the adverb `too` instead.", "Identifies common misuse of the preposition `to` in the phrase `spoke too soon`." ), "TakeItSeriously" => ( + "en", ["take it serious"], ["take it seriously"], "Did you mean `take it seriously`?", "Ensures the correct use of the adverb `seriously` instead of the adjective `serious` in phrases like `take it seriously`." ), "PiggyBag" => ( + "en", ["piggy bag"], ["piggyback"], "Did you mean `piggyback`?", "Corrects the eggcorn `piggy bag` to `piggyback`, which is the proper term for riding on someone’s back or using an existing system." ), "PiggyBagging" => ( + "en", ["piggy bagging"], ["piggybacking"], "Did you mean `piggybacking`?", "Corrects the eggcorn `piggy bagging` to `piggybacking`, the proper verb form for riding on someone’s back or leveraging an existing system." ), "PiggyBagged" => ( + "en", ["piggy bagged"], ["piggybacked"], "Did you mean `piggybacked`?", "Corrects the eggcorn `piggy bagged` to `piggybacked`, the proper past tense form for riding on someone’s back or making use of an existing system." ), "DampSquib" => ( + "en", ["damp squid"], ["damp squib"], "Use the correct phrase for a disappointing outcome.", "Corrects the eggcorn `damp squid` to `damp squib`, ensuring the intended meaning of a failed or underwhelming outcome." ), "Expatriate" => ( + "en", ["ex-patriot"], ["expatriate"], "Use the correct term for someone living abroad.", "Fixes the misinterpretation of `expatriate`, ensuring the correct term is used for individuals residing abroad." ), "FetalPosition" => ( + "en", ["the feeble position"], ["the fetal position"], "Use the correct term for a curled-up posture.", "Ensures the correct use of `fetal position`, avoiding confusion with `feeble position`, which is not a standard phrase." ), "ForAllIntentsAndPurposes" => ( + "en", ["for all intensive purposes"], ["for all intents and purposes"], "Use the correct phrase meaning 'in every practical sense'.", "Corrects `for all intensive purposes` to `for all intents and purposes`, ensuring the phrase conveys its intended meaning." ), "FreeRein" => ( + "en", ["free reign"], ["free rein"], "Use the correct phrase for unrestricted control.", "Ensures the correct use of `free rein`, avoiding confusion with `free reign`, which incorrectly suggests authority rather than freedom of action." ), "InOneFellSwoop" => ( + "en", ["in one foul swoop"], ["in one fell swoop"], "Use the correct phrase for something happening suddenly.", "Corrects `in one foul swoop` to `in one fell swoop`, preserving the phrase’s original meaning of sudden and complete action." ), "JawDropping" => ( + "en", ["jar-dropping"], ["jaw-dropping"], "Use the correct phrase for something astonishing.", "Corrects `jar-dropping` to `jaw-dropping`, ensuring the intended meaning of something that causes amazement." ), "JustDeserts" => ( + "en", ["just desserts"], ["just deserts"], "Use the correct phrase for receiving what one deserves.", "Ensures `just deserts` is used correctly, preserving its meaning of receiving an appropriate outcome for one's actions." ), "AlzheimersDisease" => ( + "en", ["old-timers' disease"], ["Alzheimer’s disease"], "Use the correct medical term.", "Fixes the common misnomer `old-timers' disease`, ensuring the correct medical term `Alzheimer’s disease` is used." ), "OldWivesTale" => ( + "en", ["old wise tale"], ["old wives' tale"], "Use the correct phrase for a superstition or myth.", "Corrects `old wise tale` to `old wives' tale`, preserving the phrase’s meaning as an unfounded traditional belief." ), "OnTheSpurOfTheMoment" => ( + "en", ["on the spurt of the moment"], ["on the spur of the moment"], "Use the correct phrase for acting spontaneously.", "Ensures the correct use of `on the spur of the moment`, avoiding confusion with the incorrect `spurt` variation." ), "PrayingMantis" => ( + "en", ["preying mantis"], ["praying mantis"], "Use the insect's correct name.", "Corrects `preying mantis` to `praying mantis`, ensuring accurate reference to the insect’s characteristic pose." ), "RealTrouper" => ( + "en", ["real trooper"], ["real trouper"], "Use the correct phrase for someone who perseveres.", "Ensures the correct use of `real trouper`, distinguishing it from `trooper`, which refers to a soldier or police officer." ), "RifeWith" => ( + "en", ["ripe with"], ["rife with"], "Use the correct phrase for something abundant.", "Corrects `ripe with` to `rife with`, preserving the phrase’s meaning of being filled with something, often undesirable." ), "ScantilyClad" => ( + "en", ["scandally clad"], ["scantily clad"], "Use the correct phrase for minimal attire.", "Fixes `scandally clad` to `scantily clad`, ensuring clarity in describing minimal attire." ), "ToTheMannerBorn" => ( + "en", ["to the manor born"], ["to the manner born"], "Use the correct phrase for being naturally suited to something.", "Corrects `to the manor born` to `to the manner born`, ensuring the intended meaning of being naturally suited to a way of life." ), "WhetYourAppetite" => ( + "en", ["wet your appetite"], ["whet your appetite"], "Use the correct phrase for stimulating desire.", "Ensures `whet your appetite` is used correctly, distinguishing it from the incorrect `wet` variation." ), "CaseSensitive" => ( + "en", ["case sensitive"], ["case-sensitive"], "Use the hyphenated form for `case-sensitive`.", "Ensures `case-sensitive` is correctly hyphenated." ), "ChockFull" => ( + "en", ["chock full"], ["chock-full"], "Use the hyphenated form for `chock-full`.", "Ensures `chock-full` is correctly hyphenated." ), "OffTheCuff" => ( + "en", ["off the cuff"], ["off-the-cuff"], "Use the hyphenated form for `off-the-cuff`.", "Ensures `off-the-cuff` is correctly hyphenated." ), "WellBeing" => ( + "en", ["wellbeing"], ["well-being"], "Use the hyphenated form for `well-being`.", "Ensures `well-being` is correctly hyphenated." ), "SimpleGrammatical" => ( + "en", ["simply grammatical"], ["simple grammatical"], "Use `simple grammatical` for correct adjective usage.", "Corrects `simply grammatical` to `simple grammatical` for proper adjective usage." ), "ThatChallenged" => ( + "en", ["the challenged"], ["that challenged"], "Use `that challenged` for correct relative clause.", "Corrects `the challenged` to `that challenged` for proper relative clause usage." ), "ToDoHyphen" => ( + "en", ["todo"], ["to-do"], "Hyphenate `to-do`.", "Ensures `to-do` is correctly hyphenated." ), "Discuss" => ( + "en", ["discuss about"], ["discuss"], "`About` is redundant", "Removes unnecessary `about` after `discuss`." ), "Discussed" => ( + "en", ["discussed about"], ["discussed"], "Use `discussed` without `about`.", "Removes unnecessary `about` after `discussed`." ), "Discusses" => ( + "en", ["discusses about"], ["discusses"], "`About` is redundant", "Removes unnecessary `about` after `discusses`." ), "Discussing" => ( + "en", ["discussing about"], ["discussing"], "`About` is redundant", "Removes unnecessary `about` after `discussing`." ), "WorldWarII" => ( + "en", ["world war 2", "world war ii", "world war ii", "world war ii", "world war ii"], ["World War II"], "Use the correct capitalization for `World War II`.", "Ensures `World War II` is correctly capitalized." ), "Towards" => ( + "en", ["to towards"], ["towards"], "Use `towards` without the preceding `to`.", "Removes redundant `to` before `towards`." ), "Haphazard" => ( + "en", ["half hazard", "half-hazard", "halfhazard"], ["haphazard"], "Use `haphazard` for randomness or lack of organization.", "Corrects the eggcorn `half hazard` to `haphazard`, which properly means lacking organization or being random." ), "DayAndAge" => ( + "en", ["day in age"], ["day and age"], "Use `day and age` for referring to the present time.", @@ -643,6 +745,7 @@ pub fn lint_group() -> LintGroup { // Note: See linting/matcher.rs for case corrections // Note: $input must already be the correct case // Note: do not add other case variants here + "en", ["Guinea Bissau"], ["Guinea-Bissau"], "The official spelling is hyphenated.", @@ -654,6 +757,7 @@ pub fn lint_group() -> LintGroup { // Note: See linting/matcher.rs for case corrections // Note: $input must already be the correct case // Note: do not add other case variants here + "en", ["Port au Prince"], ["Port-au-Prince"], "The official spelling is hyphenated.", @@ -665,12 +769,14 @@ pub fn lint_group() -> LintGroup { // Note: See linting/matcher.rs for case corrections // Note: $input must already be the correct case // Note: do not add other case variants here + "en", ["Porto Novo"], ["Porto-Novo"], "The official spelling is hyphenated.", "Checks for the correct official name of the capital of Benin." ), "NerveRacking" => ( + "en", ["nerve racking", "nerve wracking", "nerve wrecking", "nerve-wracking", "nerve-wrecking"], ["nerve-racking"], "Use `nerve-racking` for something that causes anxiety or tension.", @@ -678,72 +784,84 @@ pub fn lint_group() -> LintGroup { ), // Avoid suggestions resulting in "a entire ...." "AWholeEntire" => ( + "en", ["a whole entire"], ["a whole", "an entire"], "Avoid redundancy. Use either `whole` or `entire` for referring to the complete amount or extent.", "Corrects the redundancy in `whole entire` to `whole` or `entire`." ), "WholeEntire" => ( + "en", ["whole entire"], ["whole", "entire"], "Avoid redundancy. Use either `whole` or `entire` for referring to the complete amount or extent.", "Corrects the redundancy in `whole entire` to `whole` or `entire`." ), "InDetail" => ( + "en", ["in details"], ["in detail"], "Use singular `in detail` for referring to a detailed description.", "Correct unidiomatic plural `in details` to `in detail`." ), "InMoreDetail" => ( + "en", ["in more details"], ["in more detail"], "Use singular `in more detail` for referring to a detailed description.", "Correct unidiomatic plural `in more details` to `in more detail`." ), "TickingTimeClock" => ( + "en", ["ticking time clock"], ["ticking time bomb", "ticking clock"], "Use `ticking time bomb` for disastrous consequences, otherwise avoid redundancy with just `ticking clock`.", "Corrects `ticking time clock` to `ticking time bomb` for idiomatic urgency or `ticking clock` otherwise." ), "InAndOfItself" => ( + "en", ["in of itself"], ["in and of itself"], "Use `in and of itself` for referring to something's inherent or intrinsic quality.", "Corrects nonstandard `in of itself` to standard `in and of itself`." ), "ALotWorst" => ( + "en", ["a lot worst", "alot worst"], ["a lot worse"], "Use `worse` for comparing. (`Worst` is for the extreme case)", "Corrects `a lot worst` to `a lot worse` for proper comparative usage." ), "FarWorse" => ( + "en", ["far worst"], ["far worse"], "Use `worse` for comparing. (`Worst` is for the extreme case)", "Corrects `far worst` to `far worse` for proper comparative usage." ), "MuchWorse" => ( + "en", ["much worst"], ["much worse"], "Use `worse` for comparing. (`Worst` is for the extreme case)", "Corrects `much worst` to `much worse` for proper comparative usage." ), "TurnForTheWorse" => ( + "en", ["turn for the worst"], ["turn for the worse"], "Use `turn for the worse` for a negative change in circumstances. Avoid the incorrect `turn for the worst`.", "Corrects the nonstandard `turn for the worst` to the idiomatic `turn for the worse`, used to describe a situation that has deteriorated." ), "WorseAndWorse" => ( + "en", ["worst and worst", "worse and worst", "worst and worse"], ["worse and worse"], "Use `worse` for comparing. (`Worst` is for the extreme case)", "Corrects `worst and worst` to `worse and worse` for proper comparative usage." ), "WorseCaseScenario" => ( + "en", ["worse case scenario", "worse-case scenario", "worse-case-scenario", "worst case scenario", "worst-case-scenario"], ["worst-case scenario"], @@ -751,210 +869,245 @@ pub fn lint_group() -> LintGroup { "Corrects `worst-case scenario` when the hyphen is missing or `worse` is used instead of `worst`." ), "WorseThan" => ( + "en", ["worst than"], ["worse than"], "Use `worse` for comparing. (`Worst` is for the extreme case)", "Corrects `worst than` to `worse than` for proper comparative usage." ), "WorstEver" => ( + "en", ["worse ever"], ["worst ever"], "Use `worst` for the extreme case. (`Worse` is for comparing)", "Corrects `worse ever` to `worst ever` for proper comparative usage." ), "Monumentous" => ( + "en", ["monumentous"], ["momentous", "monumental"], "Retain `monumentous` for jocular effect. Otherwise `momentous` indicates great signifcance while `monumental` indicates imposing size.", "Advises using `momentous` or `monumental` instead of `monumentous` for serious usage." ), "InAnyWay" => ( + "en", ["in anyway"], ["in any way"], "Use `in any way` for emphasizing a point.", "Corrects ungrammatical `in anyway` to `in any way`." ), "ExplanationMark" => ( + "en", ["explanation mark"], ["exclamation mark"], "The correct name for the `!` punctuation is `exclamation mark`.", "Corrects the eggcorn `explanation mark` to `exclamation mark`." ), "ExplanationMarks" => ( + "en", ["explanation marks"], ["exclamation marks"], "The correct name for the `!` punctuation is `exclamation mark`.", "Corrects the eggcorn `explanation mark` to `exclamation mark`." ), "ExplanationPoint" => ( + "en", ["explanation point"], ["exclamation point"], "The correct name for the `!` punctuation is `exclamation point`.", "Corrects the eggcorn `explanation point` to `exclamation point`." ), "AsFarBackAs" => ( + "en", ["as early back as"], ["as far back as"], "Use `as far back as` for referring to a time in the past.", "Corrects nonstandard `as early back as` to `as far back as`." ), "ALongTime" => ( + "en", ["along time"], ["a long time"], "Use `a long time` for referring to a duration of time.", "Corrects `along time` to `a long time`." ), "EachAndEveryOne" => ( + "en", ["each and everyone"], ["each and every one"], "Use `each and every one` for referring to a group of people or things.", "Corrects `each and everyone` to `each and every one`." ), "InsteadOf" => ( + "en", ["in stead of"], ["instead of"], "Use the modern single word `instead of` to indicate a replacement.", "Corrects the archaic or mistaken separation `in stead of` to `instead of` in everyday usage." ), "Intact" => ( + "en", ["in tact"], ["intact"], "Use `intact` to mean undamaged or whole.", "Prevents the erroneous spacing in `in tact`; `intact` is the single correct word." ), "IveGotTo" => ( + "en", ["I've go to"], ["I've got to"], "Use `I've got to` for necessity or obligation.", "Corrects the slip `I've go to` to the idiomatic `I've got to`." ), "ForALongTime" => ( + "en", ["for along time"], ["for a long time"], "Use the standard phrase `for a long time` to indicate an extended duration.", "Eliminates the incorrect merging in `for along time`." ), "InAWhile" => ( + "en", ["in awhile", "in while"], ["in a while"], "When describing a timeframe, use `a while`.", "Corrects the missing article in `in while` or `in awhile`, forming `in a while`." ), "QuiteAWhile" => ( + "en", ["quite awhile"], ["quite a while"], "Add `a` to form `quite a while`, clarifying the duration.", "Corrects `quite awhile` => `quite a while` by inserting the missing article." ), "ForAWhile" => ( + "en", ["for awhile", "for while"], ["for a while"], "When describing a timeframe, use `a while`.", "Corrects the missing article in `for while` or `for awhile`, forming `for a while`." ), "AfterAWhile" => ( + "en", ["after awhile", "after while"], ["after a while"], "When describafterg a timeframe, use `a while`.", "Corrects the missing article after `after while` or `after awhile`, forming `after a while`." ), "HumanBeings" => ( + "en", ["human's beings", "humans beings"], ["human beings"], "Use `human beings` to refer to people collectively.", "Eliminates the incorrect possessive/plural usage like `human's beings` or `humans beings`." ), "HalfAnHour" => ( + "en", ["half an our"], ["half an hour"], "Remember the silent 'h' when writing `hour`: `half an hour`.", "Fixes the eggcorn `half an our` to the accepted `half an hour`." ), "AnAnother" => ( + "en", ["an another", "a another"], ["another"], "Use `another` on its own.", "Corrects `an another` and `a another`." ), "AnotherAn" => ( + "en", ["another an"], ["another"], "Use `another` on its own.", "Corrects `another an` to `another`." ), "AnotherOnes" => ( + "en", ["another ones"], ["another one", "another one's", "other ones"], "`another` is singular but `ones` is plural. Or maybe you meant the possessive `one's`.", "Corrects `another ones`." ), "AnotherThings" => ( + "en", ["another things"], ["another thing", "other things"], "`another` is singular but `things` is plural.", "Corrects `another things`." ), "TheAnother" => ( + "en", ["the another"], ["the other", "another"], "Use `the other` or `another`, not both.", "Corrects `the another`." ), "ExpandDependency" => ( + "en", ["dep"], ["dependency"], "Use `dependency` instead of `dep`", "Expands the abbreviation `dep` to the full word `dependency` for clarity." ), "ExpandDependencies" => ( + "en", ["deps"], ["dependencies"], "Use `dependencies` instead of `deps`", "Expands the abbreviation `deps` to the full word `dependencies` for clarity." ), "ExpandMinimum" => ( + "en", ["min"], ["minimum"], "Use `minimum` instead of `min`", "Expands the abbreviation `min` to the full word `minimum` for clarity." ), "ExpandStandardInput" => ( + "en", ["stdin"], ["standard input"], "Use `standard input` instead of `stdin`", "Expands the abbreviation `stdin` to `standard input` for clarity." ), "ExpandStandardOutput" => ( + "en", ["stdout"], ["standard output"], "Use `standard output` instead of `stdout`", "Expands the abbreviation `stdout` to `standard output` for clarity." ), "ExpandWith" => ( + "en", ["w/"], ["with"], "Use `with` instead of `w/`", "Expands the abbreviation `w/` to the full word `with` for clarity." ), "ExpandWithout" => ( + "en", ["w/o"], ["without"], "Use `without` instead of `w/o`", "Expands the abbreviation `w/o` to the full word `without` for clarity." ), "OnSecondThought" => ( + "en", ["on second though"], ["on second thought"], "Idiomatic expression: use `on second thought` instead of `on second though`", "Replaces the nonstandard `on second though` with the common idiom `on second thought` to indicate reconsideration." ), "Excellent" => ( + "en", ["very good"], ["excellent"], "Vocabulary enhancement: use `excellent` instead of `very good`", "Provides a stronger word choice by replacing `very good` with `excellent` for clarity and emphasis." ), "WellKept" => ( + "en", ["highly-kept", "highly kept"], // There may be other good alternatives such as closely-guarded or tightly-held ["well-kept"], @@ -962,168 +1115,196 @@ pub fn lint_group() -> LintGroup { "Flags `highly-kept` and recommends `well-kept` as an alternative." ), "ExpandBecause" => ( + "en", ["cuz"], ["because"], "Use `because` instead of informal `cuz`", "Expands the informal abbreviation `cuz` to the full word `because` for formality." ), "AtFaceValue" => ( + "en", ["on face value"], ["at face value"], "`at face value is more idiomatic and more common.", "Corrects `on face value` to the more usual `at face value`." ), "TrialAndError" => ( + "en", ["trail and error"], ["trial and error"], "You misspelled `trial`.", "Corrects `trail` to `trial` in `trial and error`." ), "HomeInOn" => ( + "en", ["hone in on"], ["home in on"], "Use `home in on` rather than `hone in on`", "Corrects `hone in on` to `home in on`." ), "HomesInOn" => ( + "en", ["hones in on"], ["homes in on"], "Use `home in on` rather than `hone in on`", "Corrects `hone in on` to `home in on`." ), "HomedInOn" => ( + "en", ["honed in on"], ["homed in on"], "Use `home in on` rather than `hone in on`", "Corrects `hone in on` to `home in on`." ), "HomingInOn" => ( + "en", ["honing in on"], ["homing in on"], "Use `home in on` rather than `hone in on`", "Corrects `hone in on` to `home in on`." ), "Unless" => ( + "en", ["unless if"], ["unless"], "Use `unless` on its own.", "Corrects `unless if` to `unless`." ), "SufficeItToSay" => ( + "en", ["suffice to say"], ["suffice it to say"], "`Suffice it to say` is more standard and more common variant.", "Corrects `suffice to say` to `suffice it to say`." ), "LikeThePlague" => ( + "en", ["like a plague"], ["like the plague"], "`Things are avoided `like the plague` not `like a plague`.", "Corrects `like a plague` to `like the plague`." ), "HaveGone" => ( + "en", ["have went"], ["have gone"], "`Have gone` is the correct form.", "Corrects `have went` to `have gone`." ), "HadGone" => ( + "en", ["had went"], ["had gone"], "`Had gone` is the correct form.", "Corrects `had went` to `had gone`." ), "HavingGone" => ( + "en", ["having went"], ["having gone"], "`Having gone` is the correct form.", "Corrects `having went` to `having gone`." ), "HasGone" => ( + "en", ["has went"], ["has gone"], "`Has gone` is the correct form.", "Corrects `has went` to `has gone`." ), "CaseInPoint" => ( + "en", ["case and point"], ["case in point"], "`Case in point` is the correct form of the phrase.", "Corrects `case and point` to `case in point`." ), "AsWell" => ( + "en", ["aswell"], ["as well"], "`as well` should be written as two words.", "Corrects `aswell` to `as well`." ), "HasPassed" => ( + "en", ["has past"], ["has passed"], "Did you mean the verb `passed`?", "Suggests `past` for `passed` in case a verb was intended." ), "HavePassed" => ( + "en", ["have past"], ["have passed"], "Did you mean the verb `passed`?", "Suggests `past` for `passed` in case a verb was intended." ), "HadPassed" => ( + "en", ["had past"], ["had passed"], "Did you mean the verb `passed`?", "Suggests `past` for `passed` in case a verb was intended." ), "HavingPassed" => ( + "en", ["having past"], ["having passed"], "Did you mean the verb `passed`?", "Suggests `past` for `passed` in case a verb was intended." ), "ClientSide" => ( + "en", ["client's side"], ["client-side"], "In client-server contexts, use `client-side` rather than `client's side`.", "Corrects `client's side` to `client-side`, which is usual in `client-server contexts`." ), "ServerSide" => ( + "en", ["server's side"], ["server-side"], "In client-server contexts, use `server-side` rather than `server's side`.", "Corrects `server's side` to `server-side`, which is usual in `client-server contexts`." ), "InCase" => ( + "en", ["incase"], ["in case"], "`In case` should be written as two words.", "Corrects `incase` to `in case`." ), "DoNotWant" => ( + "en", ["don't wan", "do not wan"], ["don't want", "do not want"], "Use the full verb “want” after negation: “don't want” or “do not want.”", "In English, negation still requires the complete verb form (“want”), so avoid truncating it to “wan.”" ), "CoursingThroughVeins" => ( + "en", ["cursing through veins"], ["coursing through veins"], "In this idiom, blood “courses” (flows) through veins, not “curses”.", "In English idioms, “to course” means to flow rapidly—so avoid the eggcorn `cursing through veins.`" ), "BestRegards" => ( + "en", ["beat regards"], ["best regards"], "Use `best regards` to convey sincere well wishes in a closing.", "In valedictions, `best` expresses your highest regard—avoid the typo `beat regards`." ), "Freezing" => ( + "en", ["very cold", "really cold", "extremely cold"], ["freezing"], "A more vivid adjective would better capture extreme cold.", "Encourages vivid writing by suggesting `freezing` instead of weaker expressions like `very cold.`" ), "Starving" => ( + "en", ["very hungry", "really hungry", "extremely hungry"], ["starving"], "A more vivid adjective would better convey intense hunger.", @@ -1148,6 +1329,7 @@ mod tests { fn get_rid_off() { assert_suggestion_result( "Please bump axios version to get rid off npm warning #624", + "en", lint_group(), "Please bump axios version to get rid of npm warning #624", ); @@ -1157,6 +1339,7 @@ mod tests { fn gets_rid_off() { assert_suggestion_result( "Adding at as a runtime dependency gets rid off that error", + "en", lint_group(), "Adding at as a runtime dependency gets rid of that error", ); @@ -1166,6 +1349,7 @@ mod tests { fn getting_rid_off() { assert_suggestion_result( "getting rid off of all the complexity of the different accesses method of API service providers", + "en", lint_group(), "getting rid of of all the complexity of the different accesses method of API service providers", ); @@ -1175,6 +1359,7 @@ mod tests { fn got_rid_off() { assert_suggestion_result( "For now we got rid off circular deps in model tree structure and it's API.", + "en", lint_group(), "For now we got rid of circular dependencies in model tree structure and it's API.", ); @@ -1184,6 +1369,7 @@ mod tests { fn gotten_rid_off() { assert_suggestion_result( "The baX variable thingy I have gotten rid off, that was due to a bad character in the encryption key.", + "en", lint_group(), "The baX variable thingy I have gotten rid of, that was due to a bad character in the encryption key.", ); @@ -1193,6 +1379,7 @@ mod tests { fn get_ride_of() { assert_suggestion_result( "Get ride of \"WARNING Deprecated: markdown_github. Use gfm\"", + "en", lint_group(), "Get rid of \"WARNING Deprecated: markdown_github. Use gfm\"", ); @@ -1202,6 +1389,7 @@ mod tests { fn get_ride_off() { assert_suggestion_result( "This exact hack was what I trying to get ride off. ", + "en", lint_group(), "This exact hack was what I trying to get rid of. ", ); @@ -1211,6 +1399,7 @@ mod tests { fn getting_ride_of() { assert_suggestion_result( "If you have any idea how to fix this without getting ride of bootstrap I would be thankfull.", + "en", lint_group(), "If you have any idea how to fix this without getting rid of bootstrap I would be thankfull.", ); @@ -1220,6 +1409,7 @@ mod tests { fn gets_ride_of() { assert_suggestion_result( ".. gets ride of a central back-end/server and eliminates all the risks associated to it.", + "en", lint_group(), ".. gets rid of a central back-end/server and eliminates all the risks associated to it.", ); @@ -1229,6 +1419,7 @@ mod tests { fn gotten_ride_of() { assert_suggestion_result( "I have gotten ride of the react-table and everything works just fine.", + "en", lint_group(), "I have gotten rid of the react-table and everything works just fine.", ); @@ -1238,6 +1429,7 @@ mod tests { fn got_ride_of() { assert_suggestion_result( "I had to adjust the labels on the free version because you guys got ride of ...", + "en", lint_group(), "I had to adjust the labels on the free version because you guys got rid of ...", ); @@ -1245,33 +1437,34 @@ mod tests { #[test] fn issue_574() { - assert_lint_count("run by one", lint_group(), 0); + assert_lint_count("run by one", "en", lint_group(), 0); } #[test] fn turn_it_off_clean_lower() { - assert_lint_count("turn it off", lint_group(), 0); + assert_lint_count("turn it off", "en", lint_group(), 0); } #[test] fn turn_it_off_clean_upper() { - assert_lint_count("Turn it off", lint_group(), 0); + assert_lint_count("Turn it off", "en", lint_group(), 0); } #[test] fn of_confusion() { - assert_suggestion_result("Turn it of", lint_group(), "Turn it off"); + assert_suggestion_result("Turn it of", "en", lint_group(), "Turn it off"); } #[test] fn i_and_of_confusion() { - assert_suggestion_result("Turn i of", lint_group(), "Turn it off"); + assert_suggestion_result("Turn i of", "en", lint_group(), "Turn it off"); } #[test] fn off_course() { assert_suggestion_result( "Yes, off course we should do that.", + "en", lint_group(), "Yes, of course we should do that.", ); @@ -1281,6 +1474,7 @@ mod tests { fn o_course() { assert_suggestion_result( "Yes, o course we should do that.", + "en", lint_group(), "Yes, of course we should do that.", ); @@ -1288,43 +1482,44 @@ mod tests { #[test] fn bad_rep() { - assert_suggestion_result("bad rep", lint_group(), "bad rap"); + assert_suggestion_result("bad rep", "en", lint_group(), "bad rap"); } #[test] fn baited_breath() { - assert_suggestion_result("baited breath", lint_group(), "bated breath"); + assert_suggestion_result("baited breath", "en", lint_group(), "bated breath"); } #[test] fn change_tact_atomic() { - assert_suggestion_result("change tact", lint_group(), "change tack"); + assert_suggestion_result("change tact", "en", lint_group(), "change tack"); } #[test] fn changed_tacks_atomic() { - assert_suggestion_result("changed tacks", lint_group(), "changed tack"); + assert_suggestion_result("changed tacks", "en", lint_group(), "changed tack"); } #[test] fn changes_tacts_atomic() { - assert_suggestion_result("changes tacts", lint_group(), "changes tack"); + assert_suggestion_result("changes tacts", "en", lint_group(), "changes tack"); } #[test] fn changing_tact_atomic() { - assert_suggestion_result("changing tact", lint_group(), "changing tack"); + assert_suggestion_result("changing tact", "en", lint_group(), "changing tack"); } #[test] fn change_of_tacks_atomic() { - assert_suggestion_result("change of tacks", lint_group(), "change of tack"); + assert_suggestion_result("change of tacks", "en", lint_group(), "change of tack"); } #[test] fn change_of_tact_real_world() { assert_suggestion_result( "Change of tact : come give your concerns - Death Knight", + "en", lint_group(), "Change of tack : come give your concerns - Death Knight", ); @@ -1334,6 +1529,7 @@ mod tests { fn change_of_tacts_real_world() { assert_suggestion_result( "2013.08.15 - A Change of Tacts | Hero MUX Wiki | Fandom", + "en", lint_group(), "2013.08.15 - A Change of Tack | Hero MUX Wiki | Fandom", ); @@ -1343,6 +1539,7 @@ mod tests { fn changing_of_tacks_real_world() { assert_suggestion_result( "Duffy's changing of tacks hidden in her poetry collection ...", + "en", lint_group(), "Duffy's changing of tack hidden in her poetry collection ...", ); @@ -1352,6 +1549,7 @@ mod tests { fn changes_of_tact_real_world() { assert_suggestion_result( "While the notes and the changes of tact started to ...", + "en", lint_group(), "While the notes and the changes of tack started to ...", ); @@ -1359,43 +1557,44 @@ mod tests { #[test] fn hunger_pain() { - assert_suggestion_result("hunger pain", lint_group(), "hunger pang"); + assert_suggestion_result("hunger pain", "en", lint_group(), "hunger pang"); } #[test] fn in_mass() { - assert_suggestion_result("in mass", lint_group(), "en masse"); + assert_suggestion_result("in mass", "en", lint_group(), "en masse"); } #[test] fn let_along() { - assert_suggestion_result("let along", lint_group(), "let alone"); + assert_suggestion_result("let along", "en", lint_group(), "let alone"); } #[test] fn sneaky_suspicion() { - assert_suggestion_result("sneaky suspicion", lint_group(), "sneaking suspicion"); + assert_suggestion_result("sneaky suspicion", "en", lint_group(), "sneaking suspicion"); } #[test] fn supposed_to() { - assert_suggestion_result("suppose to", lint_group(), "supposed to"); + assert_suggestion_result("suppose to", "en", lint_group(), "supposed to"); } #[test] fn spacial_attention() { - assert_suggestion_result("spacial attention", lint_group(), "special attention"); + assert_suggestion_result("spacial attention", "en", lint_group(), "special attention"); } #[test] fn now_on_hold() { - assert_lint_count("Those are now on hold for month.", lint_group(), 0); + assert_lint_count("Those are now on hold for month.", "en", lint_group(), 0); } #[test] fn operative_system() { assert_suggestion_result( "COS is a operative system made with the COSMOS Kernel and written in C#, COS its literally the same than MS-DOS but written in C# and open-source.", + "en", lint_group(), "COS is a operating system made with the COSMOS Kernel and written in C#, COS its literally the same than MS-DOS but written in C# and open-source.", ); @@ -1405,6 +1604,7 @@ mod tests { fn operative_systems() { assert_suggestion_result( "My dotfiles for my operative systems and other configurations.", + "en", lint_group(), "My dotfiles for my operating systems and other configurations.", ); @@ -1412,13 +1612,19 @@ mod tests { #[test] fn point_is_moot() { - assert_suggestion_result("Your point is mute.", lint_group(), "Your point is moot."); + assert_suggestion_result( + "Your point is mute.", + "en", + lint_group(), + "Your point is moot.", + ); } #[test] fn issue_777() { assert_suggestion_result( "Last but not the least, with VS2013 you can use Web Essentials 2013", + "en", lint_group(), "Last but not least, with VS2013 you can use Web Essentials 2013", ); @@ -1428,6 +1634,7 @@ mod tests { fn issue_790() { assert_suggestion_result( "This seems like a blanketed statement and I have not found any info to back up whether PyJWT is affected.", + "en", lint_group(), "This seems like a blanket statement and I have not found any info to back up whether PyJWT is affected.", ); @@ -1435,12 +1642,13 @@ mod tests { #[test] fn guinea_bissau_missing_hyphen_only() { - assert_suggestion_result("Guinea Bissau", lint_group(), "Guinea-Bissau"); + assert_suggestion_result("Guinea Bissau", "en", lint_group(), "Guinea-Bissau"); } fn detect_nerve_wracking_hyphen() { assert_suggestion_result( "We've gone through several major changes / upgrades to atlantis, and it's always a little bit nerve-wracking because if we mess something up we ...", + "en", lint_group(), "We've gone through several major changes / upgrades to atlantis, and it's always a little bit nerve-racking because if we mess something up we ...", ); @@ -1450,6 +1658,7 @@ mod tests { fn detect_nerve_wrecking_hyphen() { assert_suggestion_result( "The issue happens to me on a daily basis, and it is nerve-wrecking because I become unsure if I have actually saved the diagram, but every time ...", + "en", lint_group(), "The issue happens to me on a daily basis, and it is nerve-racking because I become unsure if I have actually saved the diagram, but every time ...", ); @@ -1459,6 +1668,7 @@ mod tests { fn detect_nerve_wracking_no_hyphen() { assert_suggestion_result( "Very nerve wracking landing in an unfamiliar mountainous airport in dead of night with no radar to show surrounding terrain.", + "en", lint_group(), "Very nerve-racking landing in an unfamiliar mountainous airport in dead of night with no radar to show surrounding terrain.", ); @@ -1468,6 +1678,7 @@ mod tests { fn detect_nerve_wrecking_no_hyphen() { assert_suggestion_result( "I appreciate any kind of help since this is kind of nerve wrecking.", + "en", lint_group(), "I appreciate any kind of help since this is kind of nerve-racking.", ); @@ -1477,6 +1688,7 @@ mod tests { fn detect_nerve_racking_no_hyphen() { assert_suggestion_result( "It's nerve racking to think about it because I have code inside the callback that resolves the member and somehow I feel like it's so ..", + "en", lint_group(), "It's nerve-racking to think about it because I have code inside the callback that resolves the member and somehow I feel like it's so ..", ); @@ -1484,23 +1696,24 @@ mod tests { #[test] fn detect_atomic_whole_entire() { - assert_suggestion_result("whole entire", lint_group(), "whole"); + assert_suggestion_result("whole entire", "en", lint_group(), "whole"); } #[test] fn correct_atomic_a_whole_entire_to_a_whole() { - assert_suggestion_result("a whole entire", lint_group(), "a whole"); + assert_suggestion_result("a whole entire", "en", lint_group(), "a whole"); } #[test] fn correct_atomic_a_whole_entire_to_an_entire() { - assert_nth_suggestion_result("a whole entire", lint_group(), "an entire", 1); + assert_nth_suggestion_result("a whole entire", "en", lint_group(), "an entire", 1); } #[test] fn correct_real_world_whole_entire() { assert_suggestion_result( "[FR] support use system dns in whole entire app", + "en", lint_group(), "[FR] support use system dns in whole app", ); @@ -1510,6 +1723,7 @@ mod tests { fn correct_real_world_a_whole_entire_to_a_whole() { assert_suggestion_result( "Start mapping a whole entire new planet using NASA’s MOLA.", + "en", lint_group(), "Start mapping a whole new planet using NASA’s MOLA.", ); @@ -1519,6 +1733,7 @@ mod tests { fn correct_real_world_a_whole_entire_to_an_entire() { assert_nth_suggestion_result( "I am not sure I can pass in a whole entire query via the include.", + "en", lint_group(), "I am not sure I can pass in an entire query via the include.", 1, @@ -1526,18 +1741,19 @@ mod tests { } fn in_detail_atomic() { - assert_suggestion_result("in details", lint_group(), "in detail"); + assert_suggestion_result("in details", "en", lint_group(), "in detail"); } #[test] fn in_more_detail_atomic() { - assert_suggestion_result("in more details", lint_group(), "in more detail"); + assert_suggestion_result("in more details", "en", lint_group(), "in more detail"); } #[test] fn in_detail_real_world() { assert_suggestion_result( "c++ - who can tell me \"*this pointer\" in details?", + "en", lint_group(), "c++ - who can tell me \"*this pointer\" in detail?", ) @@ -1547,6 +1763,7 @@ mod tests { fn suggests_ticking_time_bomb() { assert_suggestion_result( "One element that can help up the stakes (and tension!) is a “ticking time clock.”", + "en", lint_group(), "One element that can help up the stakes (and tension!) is a “ticking time bomb.”", ); @@ -1556,6 +1773,7 @@ mod tests { fn in_more_detail_real_world() { assert_suggestion_result( "Document the interface in more details · Issue #3 · owlbarn ...", + "en", lint_group(), "Document the interface in more detail · Issue #3 · owlbarn ...", ); @@ -1563,13 +1781,14 @@ mod tests { #[test] fn detect_atomic_in_of_itself() { - assert_suggestion_result("in of itself", lint_group(), "in and of itself"); + assert_suggestion_result("in of itself", "en", lint_group(), "in and of itself"); } #[test] fn correct_real_world_in_of_itself() { assert_suggestion_result( "This is not entirely unexpected in of itself, as Git and GitHub Desktop both generally prove fairly bad at delineating context intelligently...", + "en", lint_group(), "This is not entirely unexpected in and of itself, as Git and GitHub Desktop both generally prove fairly bad at delineating context intelligently...", ) @@ -1577,13 +1796,14 @@ mod tests { #[test] fn detect_a_lot_worse_atomic() { - assert_suggestion_result("a lot worst", lint_group(), "a lot worse"); + assert_suggestion_result("a lot worst", "en", lint_group(), "a lot worse"); } #[test] fn detect_a_lot_worse_real_world() { assert_suggestion_result( "On a debug build, it's even a lot worst.", + "en", lint_group(), "On a debug build, it's even a lot worse.", ); @@ -1593,6 +1813,7 @@ mod tests { fn suggests_ticking_clock() { assert_nth_suggestion_result( "The opportunity itself has a ticking time clock as all great opportunities do.", + "en", lint_group(), "The opportunity itself has a ticking clock as all great opportunities do.", 1, @@ -1601,13 +1822,14 @@ mod tests { #[test] fn detect_far_worse_atomic() { - assert_suggestion_result("far worst", lint_group(), "far worse"); + assert_suggestion_result("far worst", "en", lint_group(), "far worse"); } #[test] fn detect_far_worse_real_world() { assert_suggestion_result( "I mainly use Firefox (personal preference) and have noticed it has far worst performance than Chrome", + "en", lint_group(), "I mainly use Firefox (personal preference) and have noticed it has far worse performance than Chrome", ); @@ -1615,13 +1837,14 @@ mod tests { #[test] fn detect_much_worse_atomic() { - assert_suggestion_result("much worst", lint_group(), "much worse"); + assert_suggestion_result("much worst", "en", lint_group(), "much worse"); } #[test] fn detect_much_worse_real_world() { assert_suggestion_result( "the generated image quality is much worst (actually nearly broken)", + "en", lint_group(), "the generated image quality is much worse (actually nearly broken)", ); @@ -1629,13 +1852,19 @@ mod tests { #[test] fn detect_turn_for_the_worse_atomic() { - assert_suggestion_result("turn for the worst", lint_group(), "turn for the worse"); + assert_suggestion_result( + "turn for the worst", + "en", + lint_group(), + "turn for the worse", + ); } #[test] fn detect_turn_for_the_worse_real_world() { assert_suggestion_result( "Very surprised to see this repo take such a turn for the worst.", + "en", lint_group(), "Very surprised to see this repo take such a turn for the worse.", ); @@ -1643,13 +1872,14 @@ mod tests { #[test] fn detect_worst_and_worst_atomic() { - assert_suggestion_result("worst and worst", lint_group(), "worse and worse"); + assert_suggestion_result("worst and worst", "en", lint_group(), "worse and worse"); } #[test] fn detect_worst_and_worst_real_world() { assert_suggestion_result( "This control-L trick does not work for me. The padding is getting worst and worst.", + "en", lint_group(), "This control-L trick does not work for me. The padding is getting worse and worse.", ); @@ -1659,6 +1889,7 @@ mod tests { fn detect_worse_and_worst_real_world() { assert_suggestion_result( "This progressively got worse and worst to the point that the machine (LEAD 1010) stopped moving alltogether.", + "en", lint_group(), "This progressively got worse and worse to the point that the machine (LEAD 1010) stopped moving alltogether.", ); @@ -1666,13 +1897,14 @@ mod tests { #[test] fn detect_worse_than_atomic() { - assert_suggestion_result("worst than", lint_group(), "worse than"); + assert_suggestion_result("worst than", "en", lint_group(), "worse than"); } #[test] fn detect_worse_than_real_world() { assert_suggestion_result( "Project real image - inversion quality is worst than in StyleGAN2", + "en", lint_group(), "Project real image - inversion quality is worse than in StyleGAN2", ); @@ -1680,13 +1912,14 @@ mod tests { #[test] fn detect_worst_ever_atomic() { - assert_suggestion_result("worse ever", lint_group(), "worst ever"); + assert_suggestion_result("worse ever", "en", lint_group(), "worst ever"); } #[test] fn detect_worst_ever_real_world() { assert_suggestion_result( "The Bcl package family is one of the worse ever published by Microsoft.", + "en", lint_group(), "The Bcl package family is one of the worst ever published by Microsoft.", ); @@ -1694,13 +1927,14 @@ mod tests { #[test] fn detect_monumentous_atomic() { - assert_suggestion_result("monumentous", lint_group(), "momentous"); + assert_suggestion_result("monumentous", "en", lint_group(), "momentous"); } #[test] fn detect_monumentous_real_world() { assert_suggestion_result( "I think that would be a monumentous step in the right direction, and would DEFINATLY turn heads in not just the music industry, but every ...", + "en", lint_group(), "I think that would be a momentous step in the right direction, and would DEFINATLY turn heads in not just the music industry, but every ...", ); @@ -1708,13 +1942,14 @@ mod tests { #[test] fn detect_in_anyway_atomic() { - assert_suggestion_result("in anyway", lint_group(), "in any way"); + assert_suggestion_result("in anyway", "en", lint_group(), "in any way"); } #[test] fn detect_in_anyway_real_world() { assert_suggestion_result( "The names should not affect your application in anyway and you can override extension names.", + "en", lint_group(), "The names should not affect your application in any way and you can override extension names.", ); @@ -1722,18 +1957,19 @@ mod tests { #[test] fn detect_explanation_mark_atomic() { - assert_suggestion_result("explanation mark", lint_group(), "exclamation mark"); + assert_suggestion_result("explanation mark", "en", lint_group(), "exclamation mark"); } #[test] fn detect_explanation_marks_atomic() { - assert_suggestion_result("explanation marks", lint_group(), "exclamation marks"); + assert_suggestion_result("explanation marks", "en", lint_group(), "exclamation marks"); } #[test] fn detect_explanation_mark_real_world() { assert_suggestion_result( "Note that circled explanation mark, question mark, plus and arrows may be significantly harder to distinguish than their uncircled variants.", + "en", lint_group(), "Note that circled exclamation mark, question mark, plus and arrows may be significantly harder to distinguish than their uncircled variants.", ); @@ -1743,6 +1979,7 @@ mod tests { fn detect_explanation_marks_real_world() { assert_suggestion_result( "this issue: html: properly handle explanation marks in comments", + "en", lint_group(), "this issue: html: properly handle exclamation marks in comments", ); @@ -1750,13 +1987,14 @@ mod tests { #[test] fn detect_explanation_point_atomic() { - assert_suggestion_result("explanation point", lint_group(), "exclamation point"); + assert_suggestion_result("explanation point", "en", lint_group(), "exclamation point"); } #[test] fn detect_explanation_point_real_world() { assert_suggestion_result( "js and makes an offhand mention that you can disable inbuilt plugin with an explanation point (e.g. !error ).", + "en", lint_group(), "js and makes an offhand mention that you can disable inbuilt plugin with an exclamation point (e.g. !error ).", ); @@ -1764,13 +2002,14 @@ mod tests { #[test] fn detect_as_early_back_as() { - assert_suggestion_result("as early back as", lint_group(), "as far back as"); + assert_suggestion_result("as early back as", "en", lint_group(), "as far back as"); } #[test] fn detect_as_early_back_as_real_world() { assert_suggestion_result( "skin overrides also supports a wide variety of minecraft versions - as early back as 1.14.4.", + "en", lint_group(), "skin overrides also supports a wide variety of minecraft versions - as far back as 1.14.4.", ); @@ -1778,13 +2017,14 @@ mod tests { #[test] fn detect_a_long_time() { - assert_suggestion_result("along time", lint_group(), "a long time"); + assert_suggestion_result("along time", "en", lint_group(), "a long time"); } #[test] fn detect_a_long_time_real_world() { assert_suggestion_result( "Fast refreshing is very slow had to wait along time for it to update.", + "en", lint_group(), "Fast refreshing is very slow had to wait a long time for it to update.", ); @@ -1792,13 +2032,19 @@ mod tests { #[test] fn detect_each_and_everyone() { - assert_suggestion_result("each and everyone", lint_group(), "each and every one"); + assert_suggestion_result( + "each and everyone", + "en", + lint_group(), + "each and every one", + ); } #[test] fn detect_each_and_everyone_real_world() { assert_suggestion_result( "I have modified each and everyone of them to keep only the best of the best!", + "en", lint_group(), "I have modified each and every one of them to keep only the best of the best!", ); @@ -1808,6 +2054,7 @@ mod tests { fn test_instead_of() { assert_suggestion_result( "He used water in stead of soda.", + "en", lint_group(), "He used water instead of soda.", ); @@ -1817,6 +2064,7 @@ mod tests { fn correct_an_another() { assert_suggestion_result( "Render shader to use it as texture in an another shader.", + "en", lint_group(), "Render shader to use it as texture in another shader.", ); @@ -1825,13 +2073,14 @@ mod tests { #[test] fn test_instead_of_clean() { // Ensure no lint is triggered when it's already correct - assert_lint_count("He used water instead of soda.", lint_group(), 0); + assert_lint_count("He used water instead of soda.", "en", lint_group(), 0); } #[test] fn test_intact() { assert_suggestion_result( "The code remains in tact after the merge.", + "en", lint_group(), "The code remains intact after the merge.", ); @@ -1841,6 +2090,7 @@ mod tests { fn correct_a_another() { assert_suggestion_result( "Audit login is a another package for laravel framework.", + "en", lint_group(), "Audit login is another package for laravel framework.", ); @@ -1848,13 +2098,14 @@ mod tests { #[test] fn test_intact_clean() { - assert_lint_count("The data set remains intact.", lint_group(), 0); + assert_lint_count("The data set remains intact.", "en", lint_group(), 0); } #[test] fn test_ive_got_to() { assert_suggestion_result( "I've go to finish this before Monday.", + "en", lint_group(), "I've got to finish this before Monday.", ); @@ -1864,6 +2115,7 @@ mod tests { fn correct_another_an() { assert_suggestion_result( "Yet another an atomic deployment tool.", + "en", lint_group(), "Yet another atomic deployment tool.", ); @@ -1873,6 +2125,7 @@ mod tests { fn test_for_a_long_time() { assert_suggestion_result( "I was stuck there for along time.", + "en", lint_group(), "I was stuck there for a long time.", ); @@ -1882,6 +2135,7 @@ mod tests { fn correct_another_ones() { assert_nth_suggestion_result( "Change list params of a resource, another ones change too", + "en", lint_group(), "Change list params of a resource, other ones change too", 2, @@ -1892,11 +2146,13 @@ mod tests { fn test_in_a_while() { assert_suggestion_result( "I haven't checked in awhile.", + "en", lint_group(), "I haven't checked in a while.", ); assert_suggestion_result( "We’ll talk again in while.", + "en", lint_group(), "We’ll talk again in a while.", ); @@ -1906,6 +2162,7 @@ mod tests { fn correct_another_things() { assert_nth_suggestion_result( "Another things to fix in the Mask editor", + "en", lint_group(), "Other things to fix in the Mask editor", 1, @@ -1916,6 +2173,7 @@ mod tests { fn test_in_quite_a_while() { assert_suggestion_result( "I haven’t seen him in quite awhile.", + "en", lint_group(), "I haven’t seen him in quite a while.", ); @@ -1925,11 +2183,13 @@ mod tests { fn test_human_beings() { assert_suggestion_result( "All humans beings deserve empathy.", + "en", lint_group(), "All human beings deserve empathy.", ); assert_suggestion_result( "We should respect a human's beings fundamental rights.", + "en", lint_group(), "We should respect a human beings fundamental rights.", ); @@ -1939,6 +2199,7 @@ mod tests { fn test_last_but_not_least() { assert_suggestion_result( "Last but not last, I'd like to thank my parents.", + "en", lint_group(), "Last but not least, I'd like to thank my parents.", ); @@ -1948,6 +2209,7 @@ mod tests { fn test_half_an_hour() { assert_suggestion_result( "It took half an our to get there.", + "en", lint_group(), "It took half an hour to get there.", ); @@ -1957,6 +2219,7 @@ mod tests { fn correct_the_another() { assert_suggestion_result( "Another possible cause is simply that the application does not have file creation permissions on the another machine.", + "en", lint_group(), "Another possible cause is simply that the application does not have file creation permissions on the other machine.", ); @@ -1966,6 +2229,7 @@ mod tests { fn on_second_thought_clean() { assert_lint_count( "She considered driving home, but on second thought, she decided to walk.", + "en", lint_group(), 0, ); @@ -1975,6 +2239,7 @@ mod tests { fn on_second_thought_incorrect() { assert_suggestion_result( "I was going to buy it, but on second though, maybe I'll wait.", + "en", lint_group(), "I was going to buy it, but on second thought, maybe I'll wait.", ); @@ -1984,6 +2249,7 @@ mod tests { fn correct_highly_kept_space() { assert_suggestion_result( "I assure you that frequency/angle dependence is a highly kept secret.", + "en", lint_group(), "I assure you that frequency/angle dependence is a well-kept secret.", ); @@ -1993,6 +2259,7 @@ mod tests { fn expand_cuz() { assert_suggestion_result( "Stick around cuz I got a surprise for you at the end.", + "en", lint_group(), "Stick around because I got a surprise for you at the end.", ); @@ -2002,6 +2269,7 @@ mod tests { fn on_second_thought_no_false_positive() { assert_lint_count( "My second though is that I'd prefer something else entirely.", + "en", lint_group(), 0, ); @@ -2011,6 +2279,7 @@ mod tests { fn excellent_clean() { assert_lint_count( "The performance was excellent, drawing praise from all critics.", + "en", lint_group(), 0, ); @@ -2020,6 +2289,7 @@ mod tests { fn excellent_incorrect() { assert_suggestion_result( "Her results were very good this semester.", + "en", lint_group(), "Her results were excellent this semester.", ); @@ -2029,6 +2299,7 @@ mod tests { fn excellent_no_false_positive() { assert_lint_count( "He radiated a sense of very goodness in his charitable acts.", + "en", lint_group(), 0, ); @@ -2038,6 +2309,7 @@ mod tests { fn correct_highly_kept_no_hyphen() { assert_suggestion_result( "Well, Kushina's giving birth was already a highly-kept secret so it makes sense to operate with only the completely necessary personnel.", + "en", lint_group(), "Well, Kushina's giving birth was already a well-kept secret so it makes sense to operate with only the completely necessary personnel.", ); @@ -2047,6 +2319,7 @@ mod tests { fn correct_on_face_value() { assert_suggestion_result( "Obviously what you want is possible and on face value it's a trivial change on our end.", + "en", lint_group(), "Obviously what you want is possible and at face value it's a trivial change on our end.", ); @@ -2056,6 +2329,7 @@ mod tests { fn correct_trail_and_error() { assert_suggestion_result( "It was produced through trail and error.", + "en", lint_group(), "It was produced through trial and error.", ); @@ -2065,6 +2339,7 @@ mod tests { fn correct_hone_in_on() { assert_suggestion_result( "This way you can use an object detector algorithm to hone in on subjects and tell sam to only focus in certain areas when looking to extend ...", + "en", lint_group(), "This way you can use an object detector algorithm to home in on subjects and tell sam to only focus in certain areas when looking to extend ...", ); @@ -2074,6 +2349,7 @@ mod tests { fn correct_honing_in_on() { assert_suggestion_result( "I think I understand the syntax limitation you're honing in on.", + "en", lint_group(), "I think I understand the syntax limitation you're homing in on.", ); @@ -2083,6 +2359,7 @@ mod tests { fn correct_hones_in_on() { assert_suggestion_result( "[FEATURE] Add a magnet that hones in on mobs", + "en", lint_group(), "[FEATURE] Add a magnet that homes in on mobs", ); @@ -2092,6 +2369,7 @@ mod tests { fn correct_honed_in_on() { assert_suggestion_result( "But it took me quite a bit of faffing about checking things out before I honed in on the session as the problem and tried to dump out the ...", + "en", lint_group(), "But it took me quite a bit of faffing about checking things out before I homed in on the session as the problem and tried to dump out the ...", ); @@ -2101,6 +2379,7 @@ mod tests { fn correct_unless_if() { assert_suggestion_result( "Simplex does not interpret the following invite link as an invite link unless if it has https:// in front of it.", + "en", lint_group(), "Simplex does not interpret the following invite link as an invite link unless it has https:// in front of it.", ); @@ -2110,6 +2389,7 @@ mod tests { fn suffice_it_to_say() { assert_suggestion_result( "I don't fully grok the bug, but suffice to say it is not an RCD issue.", + "en", lint_group(), "I don't fully grok the bug, but suffice it to say it is not an RCD issue.", ); @@ -2119,6 +2399,7 @@ mod tests { fn correct_for_awhile() { assert_suggestion_result( "Video Element Error: MEDA_ERR_DECODE when chrome is left open for awhile", + "en", lint_group(), "Video Element Error: MEDA_ERR_DECODE when chrome is left open for a while", ); @@ -2128,6 +2409,7 @@ mod tests { fn correct_after_awhile() { assert_suggestion_result( "Links on portal stop working after awhile, requiring page refresh.", + "en", lint_group(), "Links on portal stop working after a while, requiring page refresh.", ); @@ -2137,6 +2419,7 @@ mod tests { fn correct_after_while() { assert_suggestion_result( "bromite Crashes on all sites after while.", + "en", lint_group(), "bromite Crashes on all sites after a while.", ); @@ -2146,6 +2429,7 @@ mod tests { fn correct_for_while() { assert_suggestion_result( "Build flutter releases in github actions for production only android for while.", + "en", lint_group(), "Build flutter releases in github actions for production only android for a while.", ); @@ -2155,6 +2439,7 @@ mod tests { fn correct_like_a_plague() { assert_suggestion_result( "Below is the worst example of them all (avoid such coding like a plague):", + "en", lint_group(), "Below is the worst example of them all (avoid such coding like the plague):", ); @@ -2164,6 +2449,7 @@ mod tests { fn correct_have_went() { assert_suggestion_result( "I have went into the btle.py file and added a print statement in _connect()", + "en", lint_group(), "I have gone into the btle.py file and added a print statement in _connect()", ); @@ -2173,6 +2459,7 @@ mod tests { fn correct_had_went() { assert_suggestion_result( "Not sure if TroLoos had went from Tasmota->minimal->Tasmota, or directly Minimal->Tasmota, but going ESPHome->Minimal->Tasmota is not possible", + "en", lint_group(), "Not sure if TroLoos had gone from Tasmota->minimal->Tasmota, or directly Minimal->Tasmota, but going ESPHome->Minimal->Tasmota is not possible", ); @@ -2182,6 +2469,7 @@ mod tests { fn correct_having_went() { assert_suggestion_result( "Having went through the setup guidelines and picking react starter, running npm run watch results in an error", + "en", lint_group(), "Having gone through the setup guidelines and picking react starter, running npm run watch results in an error", ); @@ -2191,6 +2479,7 @@ mod tests { fn correct_has_went() { assert_suggestion_result( "I would like to report that the package request which you are loading has went into maintenance mode.", + "en", lint_group(), "I would like to report that the package request which you are loading has gone into maintenance mode.", ); @@ -2200,6 +2489,7 @@ mod tests { fn correct_case_and_point_spaced() { assert_suggestion_result( "They are just not as high of a priority as other tasks that user's are requesting for, a case and point is I have never ran into this issue.", + "en", lint_group(), "They are just not as high of a priority as other tasks that user's are requesting for, a case in point is I have never ran into this issue.", ); @@ -2209,6 +2499,7 @@ mod tests { fn correct_aswell() { assert_suggestion_result( "'wejoy' is a tool to read physical joystick devices, aswell as keyboards, create virtual joystick devices and output keyboard presses on a Linux system.", + "en", lint_group(), "'wejoy' is a tool to read physical joystick devices, as well as keyboards, create virtual joystick devices and output keyboard presses on a Linux system.", ); @@ -2218,6 +2509,7 @@ mod tests { fn correct_has_past() { assert_suggestion_result( "Track the amount of time that has past since a point in time.", + "en", lint_group(), "Track the amount of time that has passed since a point in time.", ); @@ -2227,6 +2519,7 @@ mod tests { fn correct_have_past() { assert_suggestion_result( "Another 14+ days have past, any updates on this?", + "en", lint_group(), "Another 14+ days have passed, any updates on this?", ); @@ -2236,6 +2529,7 @@ mod tests { fn correct_had_past() { assert_suggestion_result( "Few days had past, so im starting to thinks there is a problem in my local version.", + "en", lint_group(), "Few days had passed, so im starting to thinks there is a problem in my local version.", ); @@ -2245,6 +2539,7 @@ mod tests { fn correct_having_past() { assert_suggestion_result( "Return to computer, with enough time having past for the computer to go to full sleep.", + "en", lint_group(), "Return to computer, with enough time having passed for the computer to go to full sleep.", ); @@ -2254,6 +2549,7 @@ mod tests { fn correct_in_case() { assert_suggestion_result( "Support for enum variable incase of reusable enum class", + "en", lint_group(), "Support for enum variable in case of reusable enum class", ); @@ -2263,6 +2559,7 @@ mod tests { fn correct_worse_case_space() { assert_suggestion_result( "In the worse case scenario, remote code execution could be achieved.", + "en", lint_group(), "In the worst-case scenario, remote code execution could be achieved.", ); @@ -2272,6 +2569,7 @@ mod tests { fn correct_worse_case_hyphen() { assert_suggestion_result( "Basically I want my pods to get the original client IP address... or at least have X-Forwarded-For header, in a worse-case scenario.", + "en", lint_group(), "Basically I want my pods to get the original client IP address... or at least have X-Forwarded-For header, in a worst-case scenario.", ); @@ -2281,6 +2579,7 @@ mod tests { fn correct_worse_case_two_hyphens() { assert_suggestion_result( "In a worse-case-scenario, the scenario class code and the results being analysed, become out of sync, and so the wrong labels are applied.", + "en", lint_group(), "In a worst-case scenario, the scenario class code and the results being analysed, become out of sync, and so the wrong labels are applied.", ); @@ -2290,6 +2589,7 @@ mod tests { fn correct_worst_case_space() { assert_suggestion_result( "The worst case scenario can be calculated without looking at streams of data.", + "en", lint_group(), "The worst-case scenario can be calculated without looking at streams of data.", ); @@ -2299,6 +2599,7 @@ mod tests { fn correct_worst_case_two_hyphens() { assert_suggestion_result( "CAPD worst-case-scenario cloud simulator for naughty clouds.", + "en", lint_group(), "CAPD worst-case scenario cloud simulator for naughty clouds.", ); @@ -2308,6 +2609,7 @@ mod tests { fn corrects_dont_wan() { assert_suggestion_result( "I don't wan to pay for this.", + "en", lint_group(), "I don't want to pay for this.", ); @@ -2317,6 +2619,7 @@ mod tests { fn correct_clients_side() { assert_suggestion_result( "I want to debug this server-side as I cannot find out why the connection is being refused from the client's side.", + "en", lint_group(), "I want to debug this server-side as I cannot find out why the connection is being refused from the client-side.", ); @@ -2326,6 +2629,7 @@ mod tests { fn corrects_mixed_case() { assert_suggestion_result( "Don't Wan that option.", + "en", lint_group(), "Don't Want that option.", ); @@ -2333,13 +2637,14 @@ mod tests { #[test] fn does_not_flag_already_correct() { - assert_lint_count("I don't want to leave.", lint_group(), 0); + assert_lint_count("I don't want to leave.", "en", lint_group(), 0); } #[test] fn detect_cursing_through_veins_atomic() { assert_suggestion_result( "cursing through veins", + "en", lint_group(), "coursing through veins", ); @@ -2349,6 +2654,7 @@ mod tests { fn detect_cursing_through_veins_real_world() { assert_suggestion_result( "It felt like the drugs were cursing through veins.", + "en", lint_group(), "It felt like the drugs were coursing through veins.", ); @@ -2358,6 +2664,7 @@ mod tests { fn does_not_flag_other_contexts() { assert_lint_count( "He was cursing through the entire meeting.", + "en", lint_group(), 0, ); @@ -2367,6 +2674,7 @@ mod tests { fn correct_servers_side() { assert_suggestion_result( "A client-server model where the client can execute commands in a terminal on the server's side", + "en", lint_group(), "A client-server model where the client can execute commands in a terminal on the server-side", ); diff --git a/harper-core/src/linting/pique_interest.rs b/harper-core/src/linting/pique_interest.rs index e2c128121d..957a02c913 100644 --- a/harper-core/src/linting/pique_interest.rs +++ b/harper-core/src/linting/pique_interest.rs @@ -81,6 +81,7 @@ mod tests { fn corrects_peak_interest() { assert_suggestion_result( "The story managed to peak his interest.", + "en", PiqueInterest::default(), "The story managed to pique his interest.", ); @@ -90,6 +91,7 @@ mod tests { fn corrects_peeked_interest_at_start() { assert_suggestion_result( "Peeked his interest, did she?", + "en", PiqueInterest::default(), "Piqued his interest, did she?", ); @@ -99,6 +101,7 @@ mod tests { fn corrects_peak_interest_in_middle() { assert_suggestion_result( "She tried to peak his interest during the lecture.", + "en", PiqueInterest::default(), "She tried to pique his interest during the lecture.", ); @@ -108,6 +111,7 @@ mod tests { fn corrects_peaked_interest_at_end() { assert_suggestion_result( "All along, she hoped she peaked his interest.", + "en", PiqueInterest::default(), "All along, she hoped she piqued his interest.", ); @@ -117,6 +121,7 @@ mod tests { fn does_not_correct_unrelated_peak() { assert_suggestion_result( "He reached the peak of the mountain.", + "en", PiqueInterest::default(), "He reached the peak of the mountain.", ); @@ -126,6 +131,7 @@ mod tests { fn corrects_peaking_interest() { assert_suggestion_result( "She was peaking his interest with her stories.", + "en", PiqueInterest::default(), "She was piquing his interest with her stories.", ); diff --git a/harper-core/src/linting/possessive_your.rs b/harper-core/src/linting/possessive_your.rs index b89ec02585..d738cff74d 100644 --- a/harper-core/src/linting/possessive_your.rs +++ b/harper-core/src/linting/possessive_your.rs @@ -63,6 +63,7 @@ mod tests { fn your_comments() { assert_suggestion_result( "You comments may end up in the documentation.", + "en", PossessiveYour::default(), "Your comments may end up in the documentation.", ); @@ -72,6 +73,7 @@ mod tests { fn allow_intro_page() { assert_lint_count( "You can try out an editor that uses Harper under-the-hood here.", + "en", PossessiveYour::default(), 0, ); @@ -81,6 +83,7 @@ mod tests { fn allow_you_guys() { assert_lint_count( "I mean I'm pretty sure you guys can't do anything with this stuff.", + "en", PossessiveYour::default(), 0, ); diff --git a/harper-core/src/linting/pronoun_contraction/mod.rs b/harper-core/src/linting/pronoun_contraction/mod.rs index 18fc1b8fde..ade00922a2 100644 --- a/harper-core/src/linting/pronoun_contraction/mod.rs +++ b/harper-core/src/linting/pronoun_contraction/mod.rs @@ -17,6 +17,7 @@ mod tests { fn issue_225() { assert_suggestion_result( "Your the man", + "en", PronounContraction::default(), "You're the man", ); @@ -26,6 +27,7 @@ mod tests { fn were_team() { assert_suggestion_result( "Were the best team.", + "en", PronounContraction::default(), "We're the best team.", ); @@ -35,6 +37,7 @@ mod tests { fn issue_139() { assert_suggestion_result( "it would be great if you're PR was merged into tower-lsp", + "en", PronounContraction::default(), "it would be great if your PR was merged into tower-lsp", ); @@ -44,6 +47,7 @@ mod tests { fn car() { assert_suggestion_result( "You're car is black.", + "en", PronounContraction::default(), "Your car is black.", ); @@ -53,6 +57,7 @@ mod tests { fn allows_you_are_still() { assert_lint_count( "In case you're still not convinced.", + "en", PronounContraction::default(), 0, ); @@ -62,12 +67,14 @@ mod tests { fn issue_576() { assert_lint_count( "If you're not happy you try again.", + "en", PronounContraction::default(), 0, ); - assert_lint_count("No you're not.", PronounContraction::default(), 0); + assert_lint_count("No you're not.", "en", PronounContraction::default(), 0); assert_lint_count( "Even if you're not fluent in arm assembly, you surely noticed this.", + "en", PronounContraction::default(), 0, ); diff --git a/harper-core/src/linting/pronoun_contraction/should_contract.rs b/harper-core/src/linting/pronoun_contraction/should_contract.rs index a47888e54e..e3c4ae26ea 100644 --- a/harper-core/src/linting/pronoun_contraction/should_contract.rs +++ b/harper-core/src/linting/pronoun_contraction/should_contract.rs @@ -75,6 +75,7 @@ mod tests { fn contracts_your_correctly() { assert_suggestion_result( "your the best", + "en", ShouldContract::default(), "you're the best", ); @@ -84,6 +85,7 @@ mod tests { fn contracts_were_complex_correctly() { assert_suggestion_result( "were a good team", + "en", ShouldContract::default(), "we're a good team", ); @@ -93,6 +95,7 @@ mod tests { fn case_insensitive_handling() { assert_suggestion_result( "Your the best", + "en", ShouldContract::default(), "You're the best", ); @@ -100,19 +103,20 @@ mod tests { #[test] fn no_match_without_the() { - assert_lint_count("your best", ShouldContract::default(), 0); - assert_lint_count("were best", ShouldContract::default(), 0); + assert_lint_count("your best", "en", ShouldContract::default(), 0); + assert_lint_count("were best", "en", ShouldContract::default(), 0); } #[test] fn no_match_with_punctuation() { - assert_lint_count("your, the best", ShouldContract::default(), 0); + assert_lint_count("your, the best", "en", ShouldContract::default(), 0); } #[test] fn allow_norm() { assert_lint_count( "Let's start this story by going back to the dark ages before internet applications were the norm.", + "en", ShouldContract::default(), 0, ); diff --git a/harper-core/src/linting/pronoun_knew.rs b/harper-core/src/linting/pronoun_knew.rs index 3721368fb7..5fd937c8a6 100644 --- a/harper-core/src/linting/pronoun_knew.rs +++ b/harper-core/src/linting/pronoun_knew.rs @@ -69,6 +69,7 @@ mod tests { fn simple_pronoun_new() { assert_suggestion_result( "I new you would say that.", + "en", PronounKnew::default(), "I knew you would say that.", ); @@ -78,6 +79,7 @@ mod tests { fn with_adverb() { assert_suggestion_result( "She often new the answer.", + "en", PronounKnew::default(), "She often knew the answer.", ); @@ -85,11 +87,11 @@ mod tests { #[test] fn does_not_flag_without_pronoun() { - assert_lint_count("The software is new.", PronounKnew::default(), 0); + assert_lint_count("The software is new.", "en", PronounKnew::default(), 0); } #[test] fn does_not_flag_other_context() { - assert_lint_count("They called it \"new\".", PronounKnew::default(), 0); + assert_lint_count("They called it \"new\".", "en", PronounKnew::default(), 0); } } diff --git a/harper-core/src/linting/proper_noun_capitalization_linters.rs b/harper-core/src/linting/proper_noun_capitalization_linters.rs index 55438a8d75..807d285f00 100644 --- a/harper-core/src/linting/proper_noun_capitalization_linters.rs +++ b/harper-core/src/linting/proper_noun_capitalization_linters.rs @@ -148,12 +148,14 @@ mod tests { fn americas_lowercase() { assert_suggestion_result( "south america", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "South America", ); assert_suggestion_result( "north america", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "North America", ); } @@ -162,27 +164,40 @@ mod tests { fn americas_uppercase() { assert_suggestion_result( "SOUTH AMERICA", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "South America", ); assert_suggestion_result( "NORTH AMERICA", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "North America", ); } #[test] fn americas_allow_correct() { - assert_lint_count("South America", lint_group(FstDictionary::curated()), 0); - assert_lint_count("North America", lint_group(FstDictionary::curated()), 0); + assert_lint_count( + "South America", + "en", + lint_group(FstDictionary::curated("en")), + 0, + ); + assert_lint_count( + "North America", + "en", + lint_group(FstDictionary::curated("en")), + 0, + ); } #[test] fn issue_798() { assert_suggestion_result( "The United states is a big country.", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "The United States is a big country.", ); } @@ -191,7 +206,8 @@ mod tests { fn united_nations_uppercase() { assert_suggestion_result( "UNITED NATIONS", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "United Nations", ); } @@ -200,26 +216,38 @@ mod tests { fn united_arab_emirates_lowercase() { assert_suggestion_result( "UNITED ARAB EMIRATES", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "United Arab Emirates", ); } #[test] fn united_nations_allow_correct() { - assert_lint_count("United Nations", lint_group(FstDictionary::curated()), 0); + assert_lint_count( + "United Nations", + "en", + lint_group(FstDictionary::curated("en")), + 0, + ); } #[test] fn meta_allow_correct() { - assert_lint_count("Meta Quest", lint_group(FstDictionary::curated()), 0); + assert_lint_count( + "Meta Quest", + "en", + lint_group(FstDictionary::curated("en")), + 0, + ); } #[test] fn microsoft_lowercase() { assert_suggestion_result( "microsoft visual studio", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "Microsoft Visual Studio", ); } @@ -228,46 +256,63 @@ mod tests { fn microsoft_first_word_is_correct() { assert_suggestion_result( "Microsoft visual studio", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "Microsoft Visual Studio", ); } #[test] fn test_atlantic_ocean_lowercase() { - let dictionary = FstDictionary::curated(); - assert_suggestion_result("atlantic ocean", lint_group(dictionary), "Atlantic Ocean"); + let dictionary = FstDictionary::curated("en"); + assert_suggestion_result( + "atlantic ocean", + "en", + lint_group(dictionary), + "Atlantic Ocean", + ); } #[test] fn test_pacific_ocean_lowercase() { - let dictionary = FstDictionary::curated(); - assert_suggestion_result("pacific ocean", lint_group(dictionary), "Pacific Ocean"); + let dictionary = FstDictionary::curated("en"); + assert_suggestion_result( + "pacific ocean", + "en", + lint_group(dictionary), + "Pacific Ocean", + ); } #[test] fn test_indian_ocean_lowercase() { - let dictionary = FstDictionary::curated(); - assert_suggestion_result("indian ocean", lint_group(dictionary), "Indian Ocean"); + let dictionary = FstDictionary::curated("en"); + assert_suggestion_result("indian ocean", "en", lint_group(dictionary), "Indian Ocean"); } #[test] fn test_southern_ocean_lowercase() { - let dictionary = FstDictionary::curated(); - assert_suggestion_result("southern ocean", lint_group(dictionary), "Southern Ocean"); + let dictionary = FstDictionary::curated("en"); + assert_suggestion_result( + "southern ocean", + "en", + lint_group(dictionary), + "Southern Ocean", + ); } #[test] fn test_arctic_ocean_lowercase() { - let dictionary = FstDictionary::curated(); - assert_suggestion_result("arctic ocean", lint_group(dictionary), "Arctic Ocean"); + let dictionary = FstDictionary::curated("en"); + assert_suggestion_result("arctic ocean", "en", lint_group(dictionary), "Arctic Ocean"); } #[test] fn test_mediterranean_sea_lowercase() { - let dictionary = FstDictionary::curated(); + let dictionary = FstDictionary::curated("en"); assert_suggestion_result( "mediterranean sea", + "en", lint_group(dictionary), "Mediterranean Sea", ); @@ -275,51 +320,62 @@ mod tests { #[test] fn test_caribbean_sea_lowercase() { - let dictionary = FstDictionary::curated(); - assert_suggestion_result("caribbean sea", lint_group(dictionary), "Caribbean Sea"); + let dictionary = FstDictionary::curated("en"); + assert_suggestion_result( + "caribbean sea", + "en", + lint_group(dictionary), + "Caribbean Sea", + ); } #[test] fn test_south_china_sea_lowercase() { - let dictionary = FstDictionary::curated(); - assert_suggestion_result("south china sea", lint_group(dictionary), "South China Sea"); + let dictionary = FstDictionary::curated("en"); + assert_suggestion_result( + "south china sea", + "en", + lint_group(dictionary), + "South China Sea", + ); } #[test] fn test_atlantic_ocean_correct() { - let dictionary = FstDictionary::curated(); - assert_lint_count("Atlantic Ocean", lint_group(dictionary), 0); + let dictionary = FstDictionary::curated("en"); + assert_lint_count("Atlantic Ocean", "en", lint_group(dictionary), 0); } #[test] fn test_pacific_ocean_correct() { - let dictionary = FstDictionary::curated(); - assert_lint_count("Pacific Ocean", lint_group(dictionary), 0); + let dictionary = FstDictionary::curated("en"); + assert_lint_count("Pacific Ocean", "en", lint_group(dictionary), 0); } #[test] fn test_indian_ocean_correct() { - let dictionary = FstDictionary::curated(); - assert_lint_count("Indian Ocean", lint_group(dictionary), 0); + let dictionary = FstDictionary::curated("en"); + assert_lint_count("Indian Ocean", "en", lint_group(dictionary), 0); } #[test] fn test_mediterranean_sea_correct() { - let dictionary = FstDictionary::curated(); - assert_lint_count("Mediterranean Sea", lint_group(dictionary), 0); + let dictionary = FstDictionary::curated("en"); + assert_lint_count("Mediterranean Sea", "en", lint_group(dictionary), 0); } #[test] fn test_south_china_sea_correct() { - let dictionary = FstDictionary::curated(); - assert_lint_count("South China Sea", lint_group(dictionary), 0); + let dictionary = FstDictionary::curated("en"); + assert_lint_count("South China Sea", "en", lint_group(dictionary), 0); } #[test] fn day_one_in_sentence() { assert_suggestion_result( "I love day one. It is the best journaling app.", - lint_group(FstDictionary::curated()), + "en", + lint_group(FstDictionary::curated("en")), "I love Day One. It is the best journaling app.", ); } diff --git a/harper-core/src/linting/repeated_words.rs b/harper-core/src/linting/repeated_words.rs index 2d8c021782..a3b1479fe3 100644 --- a/harper-core/src/linting/repeated_words.rs +++ b/harper-core/src/linting/repeated_words.rs @@ -84,23 +84,39 @@ mod tests { #[test] fn catches_basic() { - assert_lint_count("I wanted the the banana.", RepeatedWords::default(), 1) + assert_lint_count( + "I wanted the the banana.", + "en", + RepeatedWords::default(), + 1, + ) } #[test] fn does_not_lint_homographs_address() { - assert_lint_count("To address address problems.", RepeatedWords::default(), 0); + assert_lint_count( + "To address address problems.", + "en", + RepeatedWords::default(), + 0, + ); } #[test] fn does_not_lint_homographs_record() { - assert_lint_count("To record record profits.", RepeatedWords::default(), 0); + assert_lint_count( + "To record record profits.", + "en", + RepeatedWords::default(), + 0, + ); } #[test] fn issue_253() { assert_lint_count( "this paper shows that, while the method may be more accurate accurate, the turnout overestimate suggests that self-selection bias is not sufficiently reduced", + "en", RepeatedWords::default(), 1, ); @@ -110,6 +126,7 @@ mod tests { fn issue_333() { assert_suggestion_result( "This is is a test", + "en", RepeatedWords::default(), "This is a test", ); @@ -119,6 +136,7 @@ mod tests { fn double_a() { assert_suggestion_result( "This is a a test", + "en", RepeatedWords::default(), "This is a test", ); @@ -128,6 +146,7 @@ mod tests { fn double_and() { assert_suggestion_result( "And and this is also a test", + "en", RepeatedWords::default(), "And this is also a test", ); @@ -137,6 +156,7 @@ mod tests { fn on_on_github() { assert_suggestion_result( "Take a look at the project on on GitHub.", + "en", RepeatedWords::default(), "Take a look at the project on GitHub.", ); diff --git a/harper-core/src/linting/sentence_capitalization.rs b/harper-core/src/linting/sentence_capitalization.rs index 96cbb80550..47e43434e7 100644 --- a/harper-core/src/linting/sentence_capitalization.rs +++ b/harper-core/src/linting/sentence_capitalization.rs @@ -127,7 +127,8 @@ mod tests { fn catches_basic() { assert_lint_count( "there is no way she is not guilty.", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 1, ) } @@ -136,7 +137,8 @@ mod tests { fn no_period() { assert_lint_count( "there is no way she is not guilty", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 1, ) } @@ -145,7 +147,8 @@ mod tests { fn two_sentence() { assert_lint_count( "i have complete conviction in this. she is absolutely guilty", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 2, ) } @@ -154,7 +157,8 @@ mod tests { fn start_with_number() { assert_lint_count( "53 is the length of the longest word.", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -163,7 +167,8 @@ mod tests { fn ignores_unlintable() { assert_lint_count( "[`misspelled_word`] is assumed to be quite small (n < 100). ", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 0, ) } @@ -172,7 +177,8 @@ mod tests { fn unfazed_unlintable() { assert_lint_count( "the linter should not be affected by `this` unlintable.", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 1, ) } @@ -181,7 +187,8 @@ mod tests { fn unfazed_ellipsis() { assert_lint_count( "the linter should not be affected by... that ellipsis.", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 1, ) } @@ -190,7 +197,8 @@ mod tests { fn unfazed_comma() { assert_lint_count( "the linter should not be affected by, that comma.", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 1, ) } @@ -199,7 +207,8 @@ mod tests { fn issue_228_allows_labels() { assert_lint_count( "python lsp (fork of pyright)", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 0, ) } @@ -209,7 +218,8 @@ mod tests { // Some words are marked as proper nouns in `dictionary.dict` but are lower camel case. assert_lint_count( "macOS 16 could be called something like Redwood or Shasta", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 0, ) } @@ -219,7 +229,7 @@ mod tests { // #[test] // fn uppercase_unamerican_at_start() { // assert_lint_count("un-American starts with a lowercase letter and contains an uppercase letter, but is not a proper noun or trademark.", - // SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + // SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), // 1, // ) // } @@ -234,7 +244,8 @@ mod tests { "continent use npm to share and borrow packages, and many organizations use npm to ", "manage private development as well." ), - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 0, ) } @@ -244,7 +255,8 @@ mod tests { // A very few words are not considered proper nouns but still start with a lowercase letter that shouldn't be uppercased at the start of a sentence. assert_lint_count( "mRNA is synthesized from the coding sequence of a gene during the transcriptional process.", - SentenceCapitalization::new(FstDictionary::curated(), Dialect::American), + "en", + SentenceCapitalization::new(FstDictionary::curated("en"), Dialect::American), 0, ) } diff --git a/harper-core/src/linting/somewhat_something.rs b/harper-core/src/linting/somewhat_something.rs index 6801961565..141e920255 100644 --- a/harper-core/src/linting/somewhat_something.rs +++ b/harper-core/src/linting/somewhat_something.rs @@ -56,6 +56,7 @@ mod tests { fn issue_414() { assert_suggestion_result( "This may be somewhat of a surprise.", + "en", SomewhatSomething::default(), "This may be something of a surprise.", ); diff --git a/harper-core/src/linting/spaces.rs b/harper-core/src/linting/spaces.rs index 28fc5803e2..f27396679d 100644 --- a/harper-core/src/linting/spaces.rs +++ b/harper-core/src/linting/spaces.rs @@ -76,13 +76,13 @@ mod tests { fn detects_space_before_period() { let source = "There is a space at the end of this sentence ."; - assert_lint_count(source, Spaces, 1) + assert_lint_count(source, "en", Spaces, 1) } #[test] fn allows_period_without_space() { let source = "There isn't a space at the end of this sentence."; - assert_lint_count(source, Spaces, 0) + assert_lint_count(source, "en", Spaces, 0) } } diff --git a/harper-core/src/linting/spell_check.rs b/harper-core/src/linting/spell_check.rs index 594c4d8220..e6c51a3ad2 100644 --- a/harper-core/src/linting/spell_check.rs +++ b/harper-core/src/linting/spell_check.rs @@ -140,7 +140,8 @@ mod tests { fn america_capitalized() { assert_suggestion_result( "The word america should be capitalized.", - SpellCheck::new(FstDictionary::curated(), Dialect::American), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::American), "The word America should be capitalized.", ); } @@ -149,7 +150,8 @@ mod tests { fn harper_automattic_capitalized() { assert_lint_count( "So should harper and automattic.", - SpellCheck::new(FstDictionary::curated(), Dialect::American), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::American), 2, ); } @@ -158,7 +160,8 @@ mod tests { fn american_color_in_british_dialect() { assert_lint_count( "Do you like the color?", - SpellCheck::new(FstDictionary::curated(), Dialect::British), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::British), 1, ); } @@ -167,7 +170,8 @@ mod tests { fn canadian_words_in_australian_dialect() { assert_lint_count( "Does your mom like yogourt?", - SpellCheck::new(FstDictionary::curated(), Dialect::Australian), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::Australian), 2, ); } @@ -176,7 +180,8 @@ mod tests { fn australian_words_in_canadian_dialect() { assert_lint_count( "We mine bauxite to make aluminium.", - SpellCheck::new(FstDictionary::curated(), Dialect::Canadian), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::Canadian), 1, ); } @@ -185,7 +190,8 @@ mod tests { fn mum_and_mummy_not_just_commonwealth() { assert_lint_count( "Mum's the word about that Egyptian mummy.", - SpellCheck::new(FstDictionary::curated(), Dialect::American), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::American), 0, ); } @@ -194,7 +200,8 @@ mod tests { fn australian_verandah() { assert_lint_count( "Our house has a verandah.", - SpellCheck::new(FstDictionary::curated(), Dialect::Australian), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::Australian), 0, ); } @@ -203,7 +210,8 @@ mod tests { fn australian_verandah_in_american_dialect() { assert_lint_count( "Our house has a verandah.", - SpellCheck::new(FstDictionary::curated(), Dialect::American), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::American), 1, ); } @@ -212,7 +220,8 @@ mod tests { fn austrlaian_verandah_in_british_dialect() { assert_lint_count( "Our house has a verandah.", - SpellCheck::new(FstDictionary::curated(), Dialect::British), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::British), 1, ); } @@ -221,7 +230,8 @@ mod tests { fn australian_verandah_in_canadian_dialect() { assert_lint_count( "Our house has a verandah.", - SpellCheck::new(FstDictionary::curated(), Dialect::Canadian), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::Canadian), 1, ); } @@ -230,7 +240,8 @@ mod tests { fn mixing_australian_and_canadian_dialects() { assert_lint_count( "In summer we sit on the verandah and eat yogourt.", - SpellCheck::new(FstDictionary::curated(), Dialect::Australian), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::Australian), 1, ); } @@ -239,7 +250,8 @@ mod tests { fn mixing_canadian_and_australian_dialects() { assert_lint_count( "In summer we sit on the verandah and eat yogourt.", - SpellCheck::new(FstDictionary::curated(), Dialect::Canadian), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::Canadian), 1, ); } @@ -248,7 +260,8 @@ mod tests { fn australian_and_canadian_spellings_that_are_not_american() { assert_lint_count( "In summer we sit on the verandah and eat yogourt.", - SpellCheck::new(FstDictionary::curated(), Dialect::American), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::American), 2, ); } @@ -257,7 +270,8 @@ mod tests { fn australian_and_canadian_spellings_that_are_not_british() { assert_lint_count( "In summer we sit on the verandah and eat yogourt.", - SpellCheck::new(FstDictionary::curated(), Dialect::British), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::British), 2, ); } @@ -266,7 +280,8 @@ mod tests { // fn australian_labour_vs_labor() { // assert_lint_count( // "In Australia we write 'labour' but the political party is the 'Labor Party'.", - // SpellCheck::new(FstDictionary::curated(), Dialect::Australian), + // "en", + // SpellCheck::new(FstDictionary::curated("en"), Dialect::Australian), // 0, // ) // } @@ -275,7 +290,8 @@ mod tests { fn australian_words_flagged_for_american_english() { assert_lint_count( "There's an esky full of beers in the back of the ute.", - SpellCheck::new(FstDictionary::curated(), Dialect::American), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::American), 2, ); } @@ -284,7 +300,8 @@ mod tests { fn american_words_not_flagged_for_australian_english() { assert_lint_count( "In general, utes have unibody construction while pickups have frames.", - SpellCheck::new(FstDictionary::curated(), Dialect::Australian), + "en", + SpellCheck::new(FstDictionary::curated("en"), Dialect::Australian), 0, ); } diff --git a/harper-core/src/linting/spelled_numbers.rs b/harper-core/src/linting/spelled_numbers.rs index 4a6b1a3d10..389719623f 100644 --- a/harper-core/src/linting/spelled_numbers.rs +++ b/harper-core/src/linting/spelled_numbers.rs @@ -125,12 +125,22 @@ mod tests { #[test] fn corrects_nine() { - assert_suggestion_result("There are 9 pigs.", SpelledNumbers, "There are nine pigs."); + assert_suggestion_result( + "There are 9 pigs.", + "en", + SpelledNumbers, + "There are nine pigs.", + ); } #[test] fn does_not_correct_ten() { - assert_suggestion_result("There are 10 pigs.", SpelledNumbers, "There are 10 pigs."); + assert_suggestion_result( + "There are 10 pigs.", + "en", + SpelledNumbers, + "There are 10 pigs.", + ); } /// Check that the algorithm won't stack overflow or return `None` for any numbers within the specified range. diff --git a/harper-core/src/linting/that_which.rs b/harper-core/src/linting/that_which.rs index cafd7fa4b8..db61166dec 100644 --- a/harper-core/src/linting/that_which.rs +++ b/harper-core/src/linting/that_which.rs @@ -71,6 +71,7 @@ mod tests { fn catches_lowercase() { assert_lint_count( "To reiterate, that that is cool is not uncool.", + "en", ThatWhich::default(), 1, ); @@ -78,13 +79,19 @@ mod tests { #[test] fn catches_different_cases() { - assert_lint_count("That that is cool is not uncool.", ThatWhich::default(), 1); + assert_lint_count( + "That that is cool is not uncool.", + "en", + ThatWhich::default(), + 1, + ); } #[test] fn likes_correction() { assert_lint_count( "To reiterate, that which is cool is not uncool.", + "en", ThatWhich::default(), 0, ); diff --git a/harper-core/src/linting/the_how_why.rs b/harper-core/src/linting/the_how_why.rs index dc558aa76d..55cb1b34e7 100644 --- a/harper-core/src/linting/the_how_why.rs +++ b/harper-core/src/linting/the_how_why.rs @@ -96,6 +96,7 @@ mod tests { fn basic_the_how() { assert_suggestion_result( "This is the how it all started.", + "en", TheHowWhy::default(), "This is how it all started.", ); @@ -105,6 +106,7 @@ mod tests { fn the_why() { assert_suggestion_result( "The important part is the why it matters.", + "en", TheHowWhy::default(), "The important part is why it matters.", ); @@ -114,6 +116,7 @@ mod tests { fn skip_how_to() { assert_lint_count( "I'd like to explain the how to install this properly.", + "en", TheHowWhy::default(), 0, ); @@ -123,6 +126,7 @@ mod tests { fn skip_whos_who() { assert_lint_count( "We covered the who's who of corporate leadership last time.", + "en", TheHowWhy::default(), 0, ); @@ -132,6 +136,7 @@ mod tests { fn the_who() { assert_suggestion_result( "We must identify the who is responsible.", + "en", TheHowWhy::default(), "We must identify who is responsible.", ); @@ -141,6 +146,7 @@ mod tests { fn the_when() { assert_suggestion_result( "He outlined the when the new phase will start.", + "en", TheHowWhy::default(), "He outlined when the new phase will start.", ); @@ -150,6 +156,7 @@ mod tests { fn the_what() { assert_suggestion_result( "The presentation clarifies the what we intend to build.", + "en", TheHowWhy::default(), "The presentation clarifies what we intend to build.", ); @@ -159,6 +166,7 @@ mod tests { fn no_false_positive() { assert_lint_count( "These tips examine the how to fix your code quickly, plus the what's next.", + "en", TheHowWhy::default(), 0, ); diff --git a/harper-core/src/linting/the_my.rs b/harper-core/src/linting/the_my.rs index 698dd453ab..f0ba01212a 100644 --- a/harper-core/src/linting/the_my.rs +++ b/harper-core/src/linting/the_my.rs @@ -90,44 +90,45 @@ mod tests { #[test] fn correct_the_my_atomic_lowercase() { - assert_suggestion_result("the my", TheMy::default(), "my"); + assert_suggestion_result("the my", "en", TheMy::default(), "my"); } #[test] fn correct_the_my_atomic_2nd_suggestion() { - assert_nth_suggestion_result("the my", TheMy::default(), "the", 1); + assert_nth_suggestion_result("the my", "en", TheMy::default(), "the", 1); } #[test] fn correct_the_my_atomic_uppercase() { - assert_suggestion_result("The my", TheMy::default(), "My"); + assert_suggestion_result("The my", "en", TheMy::default(), "My"); } #[test] fn correct_my_the_atomic_lowercase() { - assert_suggestion_result("my the", TheMy::default(), "my"); + assert_suggestion_result("my the", "en", TheMy::default(), "my"); } #[test] fn correct_my_the_atomic_2nd_suggestion() { - assert_nth_suggestion_result("my the", TheMy::default(), "the", 1); + assert_nth_suggestion_result("my the", "en", TheMy::default(), "the", 1); } #[test] fn correct_my_the_atomic_uppercase() { - assert_suggestion_result("My the", TheMy::default(), "My"); + assert_suggestion_result("My the", "en", TheMy::default(), "My"); } #[test] fn dont_correct_capitalized_possessive() { assert_lint_count("For some time the My Projects personal page was \"sluggish\" or took some time to generate the miniature depicting the project, now it seems completely stuck ... -", TheMy::default(), 0); +", "en", TheMy::default(), 0); } #[test] fn correct_the_my_github() { assert_suggestion_result( "When I try to configure the my react-native app to support koltin file, this library gives these errors", + "en", TheMy::default(), "When I try to configure my react-native app to support koltin file, this library gives these errors", ); @@ -137,6 +138,7 @@ mod tests { fn correct_the_our_github() { assert_suggestion_result( "Source codes of the our paper titled \"Multi-level Textual-Visual Alignment and Fusion Network for Multimodal Aspect-based Sentiment Analysis\"", + "en", TheMy::default(), "Source codes of our paper titled \"Multi-level Textual-Visual Alignment and Fusion Network for Multimodal Aspect-based Sentiment Analysis\"", ); @@ -146,6 +148,7 @@ mod tests { fn correct_the_their_github() { assert_suggestion_result( "the slider cannot render when i use again the their component on NextJS app", + "en", TheMy::default(), "the slider cannot render when i use again their component on NextJS app", ); @@ -155,6 +158,7 @@ mod tests { fn correct_your_the_github() { assert_suggestion_result( "This plugin allows you to view your the information about order and customer from your spree store on zendesk", + "en", TheMy::default(), "This plugin allows you to view your information about order and customer from your spree store on zendesk", ); @@ -164,6 +168,7 @@ mod tests { fn correct_my_the_github() { assert_suggestion_result( "Scripts used my the project to collect, process and store social media data from a number of sources", + "en", TheMy::default(), "Scripts used my project to collect, process and store social media data from a number of sources", ); @@ -173,6 +178,7 @@ mod tests { fn dont_correct_the_your_github() { assert_lint_count( "What exactly is the sort order of list names on the Your Stars page?", + "en", TheMy::default(), 0, ); @@ -182,6 +188,7 @@ mod tests { fn dont_correct_my_the_github() { assert_lint_count( "My The Frame TV is not pulling information properly", + "en", TheMy::default(), 0, ) @@ -191,6 +198,7 @@ mod tests { fn correct_our_the_github() { assert_suggestion_result( "Companion Repository to our the whitepaper \"Towards Reliable and Scalable Linux Kernel CVE Attribution in Automated Static Firmware Analyses\"", + "en", TheMy::default(), "Companion Repository to our whitepaper \"Towards Reliable and Scalable Linux Kernel CVE Attribution in Automated Static Firmware Analyses\"", ) @@ -200,6 +208,7 @@ mod tests { fn correct_their_the_github() { assert_suggestion_result( "Types exported by @_exported remember only their the original module", + "en", TheMy::default(), "Types exported by @_exported remember only their original module", ) @@ -209,6 +218,7 @@ mod tests { fn dont_correct_her_the_github() { assert_lint_count( "Create an admin role for boba-tan and give her the GoreMaster role only in !gore", + "en", TheMy::default(), 0, ) @@ -218,6 +228,7 @@ mod tests { fn correct_the_his_github() { assert_suggestion_result( "Allows the user to specify the his last name.", + "en", TheMy::default(), "Allows the user to specify his last name.", ) @@ -227,6 +238,7 @@ mod tests { fn correct_his_the_github() { assert_suggestion_result( "One interesting creation was his the Schelling segregation model", + "en", TheMy::default(), "One interesting creation was his Schelling segregation model", ) @@ -236,6 +248,7 @@ mod tests { fn correct_the_her_github() { assert_suggestion_result( "In memory of the occasion when our Queen Victoria graciously came to see our Island, and the her Royal Consort Albert landed at Ramsey", + "en", TheMy::default(), "In memory of the occasion when our Queen Victoria graciously came to see our Island, and her Royal Consort Albert landed at Ramsey", ) diff --git a/harper-core/src/linting/then_than.rs b/harper-core/src/linting/then_than.rs index 4bf9f4fb27..b651b39cf5 100644 --- a/harper-core/src/linting/then_than.rs +++ b/harper-core/src/linting/then_than.rs @@ -101,13 +101,14 @@ mod tests { #[test] fn allows_back_then() { - assert_lint_count("I was a gross kid back then.", ThenThan::default(), 0); + assert_lint_count("I was a gross kid back then.", "en", ThenThan::default(), 0); } #[test] fn catches_shorter_then() { assert_suggestion_result( "One was shorter then the other.", + "en", ThenThan::default(), "One was shorter than the other.", ); @@ -117,6 +118,7 @@ mod tests { fn catches_better_then() { assert_suggestion_result( "One was better then the other.", + "en", ThenThan::default(), "One was better than the other.", ); @@ -126,6 +128,7 @@ mod tests { fn catches_longer_then() { assert_suggestion_result( "One was longer then the other.", + "en", ThenThan::default(), "One was longer than the other.", ); @@ -135,6 +138,7 @@ mod tests { fn catches_less_then() { assert_suggestion_result( "I eat less then you.", + "en", ThenThan::default(), "I eat less than you.", ); @@ -144,6 +148,7 @@ mod tests { fn catches_more_then() { assert_suggestion_result( "I eat more then you.", + "en", ThenThan::default(), "I eat more than you.", ); @@ -153,6 +158,7 @@ mod tests { fn stronger_should_change() { assert_suggestion_result( "a chain is no stronger then its weakest link", + "en", ThenThan::default(), "a chain is no stronger than its weakest link", ); @@ -162,6 +168,7 @@ mod tests { fn half_a_loaf_should_change() { assert_suggestion_result( "half a loaf is better then no bread", + "en", ThenThan::default(), "half a loaf is better than no bread", ); @@ -169,13 +176,14 @@ mod tests { #[test] fn then_everyone_clapped_should_be_allowed() { - assert_lint_count("and then everyone clapped", ThenThan::default(), 0); + assert_lint_count("and then everyone clapped", "en", ThenThan::default(), 0); } #[test] fn crazier_than_rat_should_change() { assert_suggestion_result( "crazier then a shithouse rat", + "en", ThenThan::default(), "crazier than a shithouse rat", ); @@ -185,6 +193,7 @@ mod tests { fn poke_in_eye_should_change() { assert_suggestion_result( "better then a poke in the eye with a sharp stick", + "en", ThenThan::default(), "better than a poke in the eye with a sharp stick", ); @@ -194,6 +203,7 @@ mod tests { fn other_then_should_change() { assert_suggestion_result( "There was no one other then us at the campsite.", + "en", ThenThan::default(), "There was no one other than us at the campsite.", ); @@ -201,30 +211,33 @@ mod tests { #[test] fn allows_and_then() { - assert_lint_count("And then we left.", ThenThan::default(), 0); + assert_lint_count("And then we left.", "en", ThenThan::default(), 0); } #[test] fn allows_this_then() { - assert_lint_count("Do this then that.", ThenThan::default(), 0); + assert_lint_count("Do this then that.", "en", ThenThan::default(), 0); } #[test] fn allows_issue_720() { assert_lint_count( "And if just one of those is set incorrectly or it has the tiniest bit of dirt inside then that will wreak havoc with the engine's running ability.", + "en", ThenThan::default(), 0, ); - assert_lint_count("So let's check it out then.", ThenThan::default(), 0); + assert_lint_count("So let's check it out then.", "en", ThenThan::default(), 0); assert_lint_count( "And if just the tiniest bit of dirt gets inside then that will wreak havoc.", + "en", ThenThan::default(), 0, ); assert_lint_count( "He was always a top student in school but then his argument is that grades don't define intelligence.", + "en", ThenThan::default(), 0, ); @@ -234,6 +247,7 @@ mod tests { fn allows_issue_744() { assert_lint_count( "So then after talking about how he would, he didn't.", + "en", ThenThan::default(), 0, ); @@ -243,21 +257,25 @@ mod tests { fn issue_720_school_but_then_his() { assert_lint_count( "She loved the atmosphere of the school but then his argument is that it lacks proper resources for students.", + "en", ThenThan::default(), 0, ); assert_lint_count( "The teacher praised the efforts of the school but then his argument is that the curriculum needs to be updated.", + "en", ThenThan::default(), 0, ); assert_lint_count( "They were excited about the new program at school but then his argument is that it won't be effective without proper training.", + "en", ThenThan::default(), 0, ); assert_lint_count( "The community supported the school but then his argument is that funding is still a major issue.", + "en", ThenThan::default(), 0, ); @@ -267,26 +285,31 @@ mod tests { fn issue_720_so_then_these_resistors() { assert_lint_count( "So then these resistors are connected up in parallel to reduce the overall resistance.", + "en", ThenThan::default(), 0, ); assert_lint_count( "So then these resistors are connected up to ensure the current flows properly.", + "en", ThenThan::default(), 0, ); assert_lint_count( "So then these resistors are connected up to achieve the desired voltage drop.", + "en", ThenThan::default(), 0, ); assert_lint_count( "So then these resistors are connected up to demonstrate the principles of series and parallel circuits.", + "en", ThenThan::default(), 0, ); assert_lint_count( "So then these resistors are connected up to optimize the circuit's performance.", + "en", ThenThan::default(), 0, ); @@ -296,26 +319,31 @@ mod tests { fn issue_720_yes_so_then_sorry() { assert_lint_count( "Yes so then sorry you didn't receive the memo about the meeting changes.", + "en", ThenThan::default(), 0, ); assert_lint_count( "Yes so then sorry you had to wait so long for a response from our team.", + "en", ThenThan::default(), 0, ); assert_lint_count( "Yes so then sorry you felt left out during the discussion; we value your input.", + "en", ThenThan::default(), 0, ); assert_lint_count( "Yes so then sorry you missed the deadline; we can discuss an extension.", + "en", ThenThan::default(), 0, ); assert_lint_count( "Yes so then sorry you encountered issues with the software; let me help you troubleshoot.", + "en", ThenThan::default(), 0, ); @@ -325,6 +353,7 @@ mod tests { fn more_talented_then_her_issue_720() { assert_suggestion_result( "He was more talented then her at writing code.", + "en", ThenThan::default(), "He was more talented than her at writing code.", ); @@ -334,6 +363,7 @@ mod tests { fn simpler_then_hers_issue_720() { assert_suggestion_result( "The design was simpler then hers in layout and color scheme.", + "en", ThenThan::default(), "The design was simpler than hers in layout and color scheme.", ); @@ -343,6 +373,7 @@ mod tests { fn earlier_then_him_issue_720() { assert_suggestion_result( "We arrived earlier then him at the event.", + "en", ThenThan::default(), "We arrived earlier than him at the event.", ); @@ -352,6 +383,7 @@ mod tests { fn more_robust_then_his_issue_720() { assert_suggestion_result( "This approach is more robust then his for handling edge cases.", + "en", ThenThan::default(), "This approach is more robust than his for handling edge cases.", ); @@ -361,6 +393,7 @@ mod tests { fn patch_more_recently_then_last_week_issue_720() { assert_suggestion_result( "We submitted the patch more recently then last week, so they should have it already.", + "en", ThenThan::default(), "We submitted the patch more recently than last week, so they should have it already.", ); @@ -370,6 +403,7 @@ mod tests { fn allows_well_then() { assert_lint_count( "Well then we're just going to raise all of these taxes", + "en", ThenThan::default(), 0, ); @@ -379,6 +413,7 @@ mod tests { fn allows_nervous_then() { assert_lint_count( "I think both of us were getting nervous then because the system would have automatically aborted.", + "en", ThenThan::default(), 0, ); @@ -388,6 +423,7 @@ mod tests { fn flags_stupider_then_and_more_and_less_stupid_then() { assert_lint_count( "He was stupider then her but she was more stupid then some. Then again he was less stupid then some too.", + "en", ThenThan::default(), 3, ); @@ -397,6 +433,7 @@ mod tests { fn patch_worse_then() { assert_suggestion_result( "He was worse then her at writing code.", + "en", ThenThan::default(), "He was worse than her at writing code.", ); diff --git a/harper-core/src/linting/use_genitive.rs b/harper-core/src/linting/use_genitive.rs index 83be961610..39fa87182d 100644 --- a/harper-core/src/linting/use_genitive.rs +++ b/harper-core/src/linting/use_genitive.rs @@ -89,6 +89,7 @@ mod tests { fn catches_adjective_noun() { assert_suggestion_result( "What are there big problems?", + "en", UseGenitive::default(), "What are their big problems?", ) @@ -98,6 +99,7 @@ mod tests { fn catches_just_noun() { assert_suggestion_result( "What are there problems?", + "en", UseGenitive::default(), "What are their problems?", ) @@ -105,13 +107,14 @@ mod tests { #[test] fn allows_clause_termination() { - assert_lint_count("Look there!", UseGenitive::default(), 0) + assert_lint_count("Look there!", "en", UseGenitive::default(), 0) } #[test] fn allows_there_are() { assert_lint_count( "Since there are people here, we should be socially aware.", + "en", UseGenitive::default(), 0, ) @@ -121,6 +124,7 @@ mod tests { fn allows_there_at_beginning() { assert_lint_count( "There is a cute cat sitting on the chair at home.", + "en", UseGenitive::default(), 0, ) @@ -130,6 +134,7 @@ mod tests { fn catches_they_are() { assert_suggestion_result( "The students received they're test results today.", + "en", UseGenitive::default(), "The students received their test results today.", ) @@ -137,13 +142,19 @@ mod tests { #[test] fn allows_grantlemons_issue_267_cat() { - assert_lint_count("Were there cats at her house?", UseGenitive::default(), 0); + assert_lint_count( + "Were there cats at her house?", + "en", + UseGenitive::default(), + 0, + ); } #[test] fn allows_grantlemons_issue_267_apple() { assert_lint_count( "Were there any apples at the store?", + "en", UseGenitive::default(), 0, ); @@ -153,6 +164,7 @@ mod tests { fn allows_grantlemons_issue_267_fruit() { assert_lint_count( "Were there many kinds of fruit at the store?", + "en", UseGenitive::default(), 0, ); @@ -162,6 +174,7 @@ mod tests { fn allows_grantlemons_issue_267_people() { assert_lint_count( "Were there more than, or less than six people at the party?", + "en", UseGenitive::default(), 0, ); @@ -171,6 +184,7 @@ mod tests { fn allows_faster_at_running() { assert_lint_count( "Melissa was faster at running than her friend.", + "en", UseGenitive::default(), 0, ); diff --git a/harper-core/src/linting/was_aloud.rs b/harper-core/src/linting/was_aloud.rs index 4ff04fc1aa..6624b01823 100644 --- a/harper-core/src/linting/was_aloud.rs +++ b/harper-core/src/linting/was_aloud.rs @@ -55,6 +55,7 @@ mod tests { fn corrects_was_aloud() { assert_suggestion_result( "He was aloud to enter the room.", + "en", WasAloud::default(), "He was allowed to enter the room.", ); @@ -64,6 +65,7 @@ mod tests { fn corrects_were_aloud() { assert_suggestion_result( "They were aloud to participate.", + "en", WasAloud::default(), "They were allowed to participate.", ); @@ -73,6 +75,7 @@ mod tests { fn does_not_correct_proper_use_of_aloud() { assert_suggestion_result( "She read the passage aloud to the class.", + "en", WasAloud::default(), "She read the passage aloud to the class.", ); @@ -82,6 +85,7 @@ mod tests { fn does_not_flag_unrelated_text() { assert_suggestion_result( "The concert was loud and exciting.", + "en", WasAloud::default(), "The concert was loud and exciting.", ); @@ -91,6 +95,7 @@ mod tests { fn be_aloud() { assert_suggestion_result( "You may be aloud to enter the room.", + "en", WasAloud::default(), "You may be allowed to enter the room.", ); @@ -100,6 +105,7 @@ mod tests { fn been_aloud() { assert_suggestion_result( "If I had been aloud to enter I would've jumped at the chance.", + "en", WasAloud::default(), "If I had been allowed to enter I would've jumped at the chance.", ); diff --git a/harper-core/src/linting/whereas.rs b/harper-core/src/linting/whereas.rs index 8b37b39a45..6f41aa8caa 100644 --- a/harper-core/src/linting/whereas.rs +++ b/harper-core/src/linting/whereas.rs @@ -58,6 +58,7 @@ mod tests { fn where_as() { assert_suggestion_result( "Dogs love playing fetch, where as cats are more independent creatures.", + "en", Whereas::default(), "Dogs love playing fetch, whereas cats are more independent creatures.", ); diff --git a/harper-core/src/linting/widely_accepted.rs b/harper-core/src/linting/widely_accepted.rs index 0d7554107a..08b164ff5a 100644 --- a/harper-core/src/linting/widely_accepted.rs +++ b/harper-core/src/linting/widely_accepted.rs @@ -53,6 +53,7 @@ mod tests { fn wide_accepted_lowercase() { assert_suggestion_result( "It is wide accepted that exercise improves health.", + "en", WidelyAccepted::default(), "It is widely accepted that exercise improves health.", ); @@ -62,6 +63,7 @@ mod tests { fn wide_acceptable_mixed_case() { assert_suggestion_result( "Wide acceptable standards are used in the design.", + "en", WidelyAccepted::default(), "Widely acceptable standards are used in the design.", ); @@ -71,6 +73,7 @@ mod tests { fn widely_already_correct() { assert_lint_count( "It is widely accepted that sunlight is beneficial in moderation.", + "en", WidelyAccepted::default(), 0, ); @@ -80,6 +83,7 @@ mod tests { fn no_false_positive() { assert_lint_count( "The house had wide open windows during the renovation.", + "en", WidelyAccepted::default(), 0, ); @@ -89,6 +93,7 @@ mod tests { fn wide_accepted_in_long_text() { assert_suggestion_result( "This is an example paragraph, and it is wide accepted that these changes will improve performance. In fact, widely used frameworks have already adopted them.", + "en", WidelyAccepted::default(), "This is an example paragraph, and it is widely accepted that these changes will improve performance. In fact, widely used frameworks have already adopted them.", ); @@ -98,6 +103,7 @@ mod tests { fn wide_twice_in_one_sentence() { assert_suggestion_result( "It is wide accepted and wide used by many professionals.", + "en", WidelyAccepted::default(), "It is widely accepted and widely used by many professionals.", ); diff --git a/harper-core/src/linting/wordpress_dotcom.rs b/harper-core/src/linting/wordpress_dotcom.rs index e99005ee31..d406ebbecb 100644 --- a/harper-core/src/linting/wordpress_dotcom.rs +++ b/harper-core/src/linting/wordpress_dotcom.rs @@ -43,13 +43,14 @@ mod tests { #[test] fn simple() { - assert_suggestion_result("wordpress.com", WordPressDotcom, "WordPress.com"); + assert_suggestion_result("wordpress.com", "en", WordPressDotcom, "WordPress.com"); } #[test] fn sentence() { assert_suggestion_result( "wordpress.com is a great hosting provider", + "en", WordPressDotcom, "WordPress.com is a great hosting provider", ); diff --git a/harper-core/src/parsers/collapse_identifiers.rs b/harper-core/src/parsers/collapse_identifiers.rs index c13ee0fa9e..3a4f323e8e 100644 --- a/harper-core/src/parsers/collapse_identifiers.rs +++ b/harper-core/src/parsers/collapse_identifiers.rs @@ -81,7 +81,7 @@ mod tests { #[test] fn no_collapse() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let source = "This is a test."; let tokens = @@ -92,17 +92,17 @@ mod tests { #[test] fn one_collapse() { let source = "This is a separated_identifier, wow!"; - let curated_dictionary = FstDictionary::curated(); + let curated_dictionary = FstDictionary::curated("en"); let tokens = CollapseIdentifiers::new(Box::new(PlainEnglish), Box::new(curated_dictionary.clone())) .parse_str(source); assert_eq!(tokens.len(), 13); - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new("en"); dict.append_word_str("separated_identifier", WordMetadata::default()); - let mut merged_dict = MergedDictionary::new(); + let mut merged_dict = MergedDictionary::new("en"); merged_dict.add_dictionary(curated_dictionary); merged_dict.add_dictionary(Arc::new(dict)); @@ -115,7 +115,7 @@ mod tests { #[test] fn kebab_collapse() { let source = "This is a separated-identifier, wow!"; - let curated_dictionary = FstDictionary::curated(); + let curated_dictionary = FstDictionary::curated("en"); let tokens = CollapseIdentifiers::new(Box::new(PlainEnglish), Box::new(curated_dictionary.clone())) @@ -123,10 +123,10 @@ mod tests { assert_eq!(tokens.len(), 13); - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new("en"); dict.append_word_str("separated-identifier", WordMetadata::default()); - let mut merged_dict = MergedDictionary::new(); + let mut merged_dict = MergedDictionary::new("en"); merged_dict.add_dictionary(curated_dictionary); merged_dict.add_dictionary(Arc::new(dict)); @@ -140,17 +140,17 @@ mod tests { #[test] fn double_collapse() { let source = "This is a separated_identifier_token, wow!"; - let curated_dictionary = FstDictionary::curated(); + let curated_dictionary = FstDictionary::curated("en"); let tokens = CollapseIdentifiers::new(Box::new(PlainEnglish), Box::new(curated_dictionary.clone())) .parse_str(source); assert_eq!(tokens.len(), 15); - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new("en"); dict.append_word_str("separated_identifier_token", WordMetadata::default()); - let mut merged_dict = MergedDictionary::new(); + let mut merged_dict = MergedDictionary::new("en"); merged_dict.add_dictionary(curated_dictionary); merged_dict.add_dictionary(Arc::new(dict)); @@ -163,17 +163,17 @@ mod tests { #[test] fn two_collapses() { let source = "This is a separated_identifier, wow! separated_identifier"; - let curated_dictionary = FstDictionary::curated(); + let curated_dictionary = FstDictionary::curated("en"); let tokens = CollapseIdentifiers::new(Box::new(PlainEnglish), Box::new(curated_dictionary.clone())) .parse_str(source); assert_eq!(tokens.len(), 17); - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new("en"); dict.append_word_str("separated_identifier", WordMetadata::default()); - let mut merged_dict = MergedDictionary::new(); + let mut merged_dict = MergedDictionary::new("en"); merged_dict.add_dictionary(curated_dictionary); merged_dict.add_dictionary(Arc::new(dict)); @@ -186,18 +186,18 @@ mod tests { #[test] fn overlapping_identifiers() { let source = "This is a separated_identifier_token, wow!"; - let curated_dictionary = FstDictionary::curated(); + let curated_dictionary = FstDictionary::curated("en"); let tokens = CollapseIdentifiers::new(Box::new(PlainEnglish), Box::new(curated_dictionary.clone())) .parse_str(source); assert_eq!(tokens.len(), 15); - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new("en"); dict.append_word_str("separated_identifier", WordMetadata::default()); dict.append_word_str("identifier_token", WordMetadata::default()); - let mut merged_dict = MergedDictionary::new(); + let mut merged_dict = MergedDictionary::new("en"); merged_dict.add_dictionary(curated_dictionary); merged_dict.add_dictionary(Arc::new(dict)); @@ -210,18 +210,18 @@ mod tests { #[test] fn nested_identifiers() { let source = "This is a separated_identifier_token, wow!"; - let curated_dictionary = FstDictionary::curated(); + let curated_dictionary = FstDictionary::curated("en"); let tokens = CollapseIdentifiers::new(Box::new(PlainEnglish), Box::new(curated_dictionary.clone())) .parse_str(source); assert_eq!(tokens.len(), 15); - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new("en"); dict.append_word_str("separated_identifier_token", WordMetadata::default()); dict.append_word_str("separated_identifier", WordMetadata::default()); - let mut merged_dict = MergedDictionary::new(); + let mut merged_dict = MergedDictionary::new("en"); merged_dict.add_dictionary(curated_dictionary); merged_dict.add_dictionary(Arc::new(dict)); diff --git a/harper-core/src/parsers/isolate_english.rs b/harper-core/src/parsers/isolate_english.rs index 217449f7cd..97f5b14ea1 100644 --- a/harper-core/src/parsers/isolate_english.rs +++ b/harper-core/src/parsers/isolate_english.rs @@ -42,7 +42,7 @@ mod tests { /// Assert that the provided text contains _no_ chunks of valid English fn assert_no_english(text: &str) { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let document = Document::new( text, @@ -57,7 +57,7 @@ mod tests { /// Assert that, once stripped of non-English chunks, the resulting document looks like another /// piece of text. fn assert_stripped_english(source: &str, target: &str) { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let document = Document::new( source, diff --git a/harper-core/src/patterns/exact_phrase.rs b/harper-core/src/patterns/exact_phrase.rs index 9eb543cd2b..91ef704645 100644 --- a/harper-core/src/patterns/exact_phrase.rs +++ b/harper-core/src/patterns/exact_phrase.rs @@ -9,8 +9,8 @@ pub struct ExactPhrase { } impl ExactPhrase { - pub fn from_phrase(text: &str) -> Self { - let document = Document::new_markdown_default_curated(text); + pub fn from_phrase(text: &str, language: &str) -> Self { + let document = Document::new_markdown_default_curated(text, language); Self::from_document(&document) } diff --git a/harper-core/src/patterns/nominal_phrase.rs b/harper-core/src/patterns/nominal_phrase.rs index a655f5bef7..1bee471299 100644 --- a/harper-core/src/patterns/nominal_phrase.rs +++ b/harper-core/src/patterns/nominal_phrase.rs @@ -42,7 +42,7 @@ mod tests { #[test] fn simple_apple() { - let doc = Document::new_markdown_default_curated("A red apple"); + let doc = Document::new_markdown_default_curated("A red apple", "en"); let matches = NominalPhrase.find_all_matches_in_doc(&doc); assert_eq!(matches, vec![Span::new(0, 5)]) @@ -50,7 +50,7 @@ mod tests { #[test] fn complex_apple() { - let doc = Document::new_markdown_default_curated("A red apple with a long stem"); + let doc = Document::new_markdown_default_curated("A red apple with a long stem", "en"); let matches = NominalPhrase.find_all_matches_in_doc(&doc); assert_eq!(matches, vec![Span::new(0, 5), Span::new(8, 13)]) @@ -58,7 +58,7 @@ mod tests { #[test] fn list_fruit() { - let doc = Document::new_markdown_default_curated("An apple, a banana and a pear"); + let doc = Document::new_markdown_default_curated("An apple, a banana and a pear", "en"); let matches = NominalPhrase.find_all_matches_in_doc(&doc); assert_eq!( @@ -69,7 +69,7 @@ mod tests { #[test] fn simplest_banana() { - let doc = Document::new_markdown_default_curated("a banana"); + let doc = Document::new_markdown_default_curated("a banana", "en"); assert!( NominalPhrase .matches(doc.get_tokens(), doc.get_source()) @@ -81,6 +81,7 @@ mod tests { fn food() { let doc = Document::new_markdown_default_curated( "My favorite foods are pizza, sushi, tacos and burgers.", + "en", ); let matches = NominalPhrase.find_all_matches_in_doc(&doc); diff --git a/harper-core/src/patterns/sequence_pattern.rs b/harper-core/src/patterns/sequence_pattern.rs index bb08b7c1bb..bdb5905943 100644 --- a/harper-core/src/patterns/sequence_pattern.rs +++ b/harper-core/src/patterns/sequence_pattern.rs @@ -19,7 +19,7 @@ use crate::{Token, TokenKind}; /// use harper_core::patterns::{SequencePattern, DocPattern}; /// use harper_core::{Document, Span}; /// -/// let document = Document::new_markdown_default_curated("This is a test."); +/// let document = Document::new_markdown_default_curated("This is a test.", "en"); /// /// let pattern = SequencePattern::default().then_determiner().then_whitespace().then_nominal(); /// let matches = pattern.find_all_matches_in_doc(&document); diff --git a/harper-core/src/patterns/split_compound_word.rs b/harper-core/src/patterns/split_compound_word.rs index 836d788ec7..2c279f8c06 100644 --- a/harper-core/src/patterns/split_compound_word.rs +++ b/harper-core/src/patterns/split_compound_word.rs @@ -16,13 +16,16 @@ pub struct SplitCompoundWord { impl SplitCompoundWord { /// Create a new instance of the linter which will only look for compound words that fit the /// provided predicate. - pub fn new(predicate: impl Fn(&WordMetadata) -> bool + Send + Sync + 'static) -> Self { + pub fn new( + langiso639: &str, + predicate: impl Fn(&WordMetadata) -> bool + Send + Sync + 'static, + ) -> Self { Self { inner: SequencePattern::default() .then_any_word() .then_whitespace() .then_any_word(), - dict: FstDictionary::curated(), + dict: FstDictionary::curated(langiso639), predicate: Box::new(predicate), } } diff --git a/harper-core/src/patterns/word_set.rs b/harper-core/src/patterns/word_set.rs index cbb892004c..59f3d45ece 100644 --- a/harper-core/src/patterns/word_set.rs +++ b/harper-core/src/patterns/word_set.rs @@ -77,7 +77,8 @@ mod tests { fn fruit() { let set = WordSet::new(&["banana", "apple", "orange"]); - let doc = Document::new_markdown_default_curated("I ate a banana and an apple today."); + let doc = + Document::new_markdown_default_curated("I ate a banana and an apple today.", "en"); let matches = set.find_all_matches_in_doc(&doc); @@ -88,7 +89,8 @@ mod tests { fn fruit_whack_capitalization() { let set = WordSet::new(&["banana", "apple", "orange"]); - let doc = Document::new_markdown_default_curated("I Ate A bAnaNa And aN apPlE today."); + let doc = + Document::new_markdown_default_curated("I Ate A bAnaNa And aN apPlE today.", "en"); let matches = set.find_all_matches_in_doc(&doc); diff --git a/harper-core/src/spell/dictionary.rs b/harper-core/src/spell/dictionary.rs index d3cde48b65..7c61a8d105 100644 --- a/harper-core/src/spell/dictionary.rs +++ b/harper-core/src/spell/dictionary.rs @@ -9,6 +9,8 @@ use crate::WordMetadata; /// See also: [`super::FstDictionary`] and [`super::MutableDictionary`]. #[blanket(derive(Arc))] pub trait Dictionary: Send + Sync { + /// The language of the dictionary. + fn get_langiso639(&self) -> &str; /// Check if the dictionary contains any capitalization of a given word. fn contains_word(&self, word: &[char]) -> bool; /// Check if the dictionary contains any capitalization of a given word. diff --git a/harper-core/src/spell/fst_dictionary.rs b/harper-core/src/spell/fst_dictionary.rs index 947e39902a..78a7724b68 100644 --- a/harper-core/src/spell/fst_dictionary.rs +++ b/harper-core/src/spell/fst_dictionary.rs @@ -20,13 +20,16 @@ pub struct FstDictionary { word_map: FstMap>, /// Used for fuzzy-finding the index of words or metadata words: Vec<(CharString, WordMetadata)>, + /// The language of the dictionary + langiso639: String, } const EXPECTED_DISTANCE: u8 = 3; const TRANSPOSITION_COST_ONE: bool = false; lazy_static! { - static ref DICT: Arc = Arc::new((*MutableDictionary::curated()).clone().into()); + static ref DICT_EN: Arc = + Arc::new((*MutableDictionary::curated("en")).clone().into()); } thread_local! { @@ -49,13 +52,16 @@ impl PartialEq for FstDictionary { impl FstDictionary { /// Create a dictionary from the curated dictionary included /// in the Harper binary. - pub fn curated() -> Arc { - (*DICT).clone() + pub fn curated(langiso639: &str) -> Arc { + match langiso639 { + "en" => (*DICT_EN).clone(), + _ => Arc::new((*MutableDictionary::curated(langiso639)).clone().into()), + } } /// Construct a new [`FstDictionary`] using a word list as a source. /// This can be expensive, so only use this if fast fuzzy searches are worth it. - pub fn new(mut words: Vec<(CharString, WordMetadata)>) -> Self { + pub fn new(langiso639: &str, mut words: Vec<(CharString, WordMetadata)>) -> Self { words.sort_unstable_by(|(a, _), (b, _)| a.cmp(b)); words.dedup_by(|(a, _), (b, _)| a == b); @@ -67,7 +73,7 @@ impl FstDictionary { .expect("Insertion not in lexicographical order!"); } - let mut full_dict = MutableDictionary::new(); + let mut full_dict = MutableDictionary::new(langiso639); full_dict.extend_words(words.iter().cloned()); let fst_bytes = builder.into_inner().unwrap(); @@ -77,6 +83,7 @@ impl FstDictionary { full_dict: Arc::new(full_dict), word_map, words, + langiso639: langiso639.to_string(), } } } @@ -212,6 +219,10 @@ impl Dictionary for FstDictionary { fn get_word_from_id(&self, id: &WordId) -> Option<&[char]> { self.full_dict.get_word_from_id(id) } + + fn get_langiso639(&self) -> &str { + &self.langiso639 + } } #[cfg(test)] @@ -226,7 +237,7 @@ mod tests { #[test] fn fst_map_contains_all_in_full_dict() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); for word in dict.words_iter() { let misspelled_normalized = word.normalized(); @@ -245,7 +256,7 @@ mod tests { #[test] fn fst_contains_hello() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let word: Vec<_> = "hello".chars().collect(); let misspelled_normalized = word.normalized(); @@ -261,14 +272,14 @@ mod tests { #[test] fn on_is_not_nominal() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); assert!(!dict.get_word_metadata_str("on").unwrap().is_nominal()); } #[test] fn fuzzy_result_sorted_by_edit_distance() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let results = dict.fuzzy_match_str("hello", 3, 100); let is_sorted_by_dist = results @@ -282,14 +293,14 @@ mod tests { #[test] fn curated_contains_no_duplicates() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); assert!(dict.words.iter().map(|(word, _)| word).all_unique()); } #[test] fn contractions_not_derived() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let contractions = ["there's", "we're", "here's"]; @@ -306,7 +317,7 @@ mod tests { #[test] fn plural_llamas_derived_from_llama() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); assert_eq!( dict.get_word_metadata_str("llamas") @@ -319,7 +330,7 @@ mod tests { #[test] fn plural_cats_derived_from_cat() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); assert_eq!( dict.get_word_metadata_str("cats") @@ -332,7 +343,7 @@ mod tests { #[test] fn unhappy_derived_from_happy() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); assert_eq!( dict.get_word_metadata_str("unhappy") @@ -345,7 +356,7 @@ mod tests { #[test] fn quickly_derived_from_quick() { - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); assert_eq!( dict.get_word_metadata_str("quickly") diff --git a/harper-core/src/spell/merged_dictionary.rs b/harper-core/src/spell/merged_dictionary.rs index 5792db00a0..af5412dc0e 100644 --- a/harper-core/src/spell/merged_dictionary.rs +++ b/harper-core/src/spell/merged_dictionary.rs @@ -18,14 +18,16 @@ pub struct MergedDictionary { children: Vec>, hasher_builder: FixedState, child_hashes: Vec, + langiso639: String, } impl MergedDictionary { - pub fn new() -> Self { + pub fn new(langiso639: &str) -> Self { Self { children: Vec::new(), hasher_builder: FixedState::default(), child_hashes: Vec::new(), + langiso639: langiso639.to_string(), } } @@ -36,9 +38,10 @@ impl MergedDictionary { fn hash_dictionary(&self, dictionary: &Arc) -> u64 { // Hashing the curated dictionary isn't super helpful and takes a long time. + let langiso639 = dictionary.get_langiso639(); if Arc::ptr_eq( dictionary, - &(FstDictionary::curated() as Arc), + &(FstDictionary::curated(langiso639) as Arc), ) { return 1; } @@ -51,6 +54,10 @@ impl MergedDictionary { hasher.finish() } + + pub fn get_langiso639(&self) -> &str { + &self.langiso639 + } } impl PartialEq for MergedDictionary { @@ -59,12 +66,6 @@ impl PartialEq for MergedDictionary { } } -impl Default for MergedDictionary { - fn default() -> Self { - Self::new() - } -} - impl Dictionary for MergedDictionary { fn get_correct_capitalization_of(&self, word: &[char]) -> Option<&'_ [char]> { for child in &self.children { @@ -159,4 +160,8 @@ impl Dictionary for MergedDictionary { .iter() .find_map(|dict| dict.get_word_from_id(id)) } + + fn get_langiso639(&self) -> &str { + todo!() + } } diff --git a/harper-core/src/spell/mod.rs b/harper-core/src/spell/mod.rs index dd96db3108..7def803282 100644 --- a/harper-core/src/spell/mod.rs +++ b/harper-core/src/spell/mod.rs @@ -10,6 +10,7 @@ mod dictionary; mod fst_dictionary; mod merged_dictionary; mod mutable_dictionary; +mod mutable_dictionary_es; mod rune; mod word_id; mod word_map; @@ -126,7 +127,7 @@ mod tests { "punctation", RESULT_LIMIT, MAX_EDIT_DIST, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); assert!(results.iter().all_unique()) @@ -158,7 +159,7 @@ mod tests { "Semantical", RESULT_LIMIT, MAX_EDIT_DIST, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); dbg!(&results); @@ -177,7 +178,7 @@ mod tests { "hvllo", RESULT_LIMIT, MAX_EDIT_DIST, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); dbg!(&results); @@ -193,7 +194,7 @@ mod tests { misspelled_word, RESULT_LIMIT, MAX_EDIT_DIST, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); dbg!(&results); @@ -217,19 +218,19 @@ mod tests { "hello", RESULT_LIMIT, MAX_EDIT_DIST, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); let results2 = suggest_correct_spelling_str( "hello", RESULT_LIMIT, MAX_EDIT_DIST, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); let results3 = suggest_correct_spelling_str( "hello", RESULT_LIMIT, MAX_EDIT_DIST, - &FstDictionary::curated(), + &FstDictionary::curated("en"), ); assert_eq!(results1, results2); diff --git a/harper-core/src/spell/mutable_dictionary.rs b/harper-core/src/spell/mutable_dictionary.rs index bbdcf514bc..43b56b6da4 100644 --- a/harper-core/src/spell/mutable_dictionary.rs +++ b/harper-core/src/spell/mutable_dictionary.rs @@ -25,32 +25,73 @@ use super::dictionary::Dictionary; pub struct MutableDictionary { /// All English words word_map: WordMap, + langiso639: String, } /// The uncached function that is used to produce the original copy of the /// curated dictionary. -fn uncached_inner_new() -> Arc { - Arc::new( - MutableDictionary::from_rune_files( - include_str!("../../dictionary.dict"), - include_str!("../../affixes.json"), +fn uncached_inner_new(langiso639: &str) -> Arc { + if langiso639 == "en" { + Arc::new( + MutableDictionary::from_rune_files( + langiso639, + include_str!("../../dictionary.dict"), + include_str!("../../affixes.json"), + ) + .expect("Curated dictionary should be valid."), ) - .expect("Curated dictionary should be valid."), - ) + } else { + let mut dictpath = String::new(); + let mut affixpath = String::new(); + + if let Ok(cargo_manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") { + dictpath = format!("{}/dictionary-{}.dict", cargo_manifest_dir, langiso639); + affixpath = format!("{}/affixes-{}.json", cargo_manifest_dir, langiso639); + eprintln!("##✅## dictpath: '{}'", dictpath); + } else { + let current_exe = std::env::current_exe().unwrap(); + let rsrc_path = current_exe + .parent() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .display(); + dictpath = format!("{}/harper-core/dictionary-{}.dict", rsrc_path, langiso639); + affixpath = format!("{}/harper-core/affixes-{}.json", rsrc_path, langiso639); + eprintln!("##🚀## dictpath: '{}'", dictpath); + } + Arc::new( + MutableDictionary::from_rune_files( + langiso639, + &std::fs::read_to_string(dictpath) + .unwrap_or_else(|_| panic!("Missing dictionary for language {}", langiso639)), + &std::fs::read_to_string(affixpath) + .unwrap_or_else(|_| panic!("Missing affixes for language {}", langiso639)), + ) + .unwrap_or_else(|_| panic!("Failed to create dictionary for language {}", langiso639)), + ) + } } lazy_static! { - static ref DICT: Arc = uncached_inner_new(); + static ref DICT_EN: Arc = uncached_inner_new("en"); } impl MutableDictionary { - pub fn new() -> Self { + pub fn new(langiso639: &str) -> Self { Self { word_map: WordMap::default(), + langiso639: langiso639.to_string(), } } - pub fn from_rune_files(word_list: &str, attr_list: &str) -> Result { + pub fn from_rune_files( + langiso639: &str, + word_list: &str, + attr_list: &str, + ) -> Result { let word_list = parse_word_list(word_list)?; let attr_list = AttributeList::parse(attr_list)?; @@ -59,14 +100,20 @@ impl MutableDictionary { attr_list.expand_marked_words(word_list, &mut word_map); - Ok(Self { word_map }) + Ok(Self { + word_map, + langiso639: langiso639.to_string(), + }) } /// Create a dictionary from the curated dictionary included /// in the Harper binary. /// Consider using [`super::FstDictionary::curated()`] instead, as it is more performant for spellchecking. - pub fn curated() -> Arc { - (*DICT).clone() + pub fn curated(langiso639: &str) -> Arc { + match langiso639 { + "en" => (*DICT_EN).clone(), + _ => uncached_inner_new(langiso639), + } } /// Appends words to the dictionary. @@ -99,11 +146,9 @@ impl MutableDictionary { pub fn append_word_str(&mut self, word: &str, metadata: WordMetadata) { self.append_word(word.chars().collect::>(), metadata) } -} -impl Default for MutableDictionary { - fn default() -> Self { - Self::new() + pub fn get_langiso639(&self) -> &str { + &self.langiso639 } } @@ -233,6 +278,10 @@ impl Dictionary for MutableDictionary { fn get_word_from_id(&self, id: &WordId) -> Option<&[char]> { self.word_map.get(id).map(|w| w.canonical_spelling.as_ref()) } + + fn get_langiso639(&self) -> &str { + &self.langiso639 + } } impl From for FstDictionary { @@ -243,7 +292,7 @@ impl From for FstDictionary { .map(|entry| (entry.canonical_spelling, entry.metadata)) .collect(); - FstDictionary::new(words) + FstDictionary::new(&dict.langiso639, words) } } @@ -256,13 +305,13 @@ mod tests { #[test] fn curated_contains_no_duplicates() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(dict.words_iter().all_unique()); } #[test] fn curated_matches_capitalized() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(dict.contains_word_str("this")); assert!(dict.contains_word_str("This")); } @@ -272,40 +321,40 @@ mod tests { // TODO Harper previously wrongly classified it as a noun // #[test] // fn this_is_determiner() { - // let dict = MutableDictionary::curated(); + // let dict = MutableDictionary::curated("en"); // assert!(dict.get_word_metadata_str("this").unwrap().is_determiner()); // assert!(dict.get_word_metadata_str("This").unwrap().is_determiner()); // } #[test] fn than_is_conjunction() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(dict.get_word_metadata_str("than").unwrap().is_conjunction()); assert!(dict.get_word_metadata_str("Than").unwrap().is_conjunction()); } #[test] fn herself_is_pronoun() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(dict.get_word_metadata_str("herself").unwrap().is_pronoun()); assert!(dict.get_word_metadata_str("Herself").unwrap().is_pronoun()); } #[test] fn discussion_171() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(dict.contains_word_str("natively")); } #[test] fn im_is_common() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(dict.get_word_metadata_str("I'm").unwrap().common); } #[test] fn fuzzy_result_sorted_by_edit_distance() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); let results = dict.fuzzy_match_str("hello", 3, 100); let is_sorted_by_dist = results @@ -319,7 +368,7 @@ mod tests { #[test] fn there_is_not_a_pronoun() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(!dict.get_word_metadata_str("there").unwrap().is_nominal()); assert!(!dict.get_word_metadata_str("there").unwrap().is_pronoun()); @@ -327,17 +376,17 @@ mod tests { #[test] fn expanded_contains_giants() { - assert!(MutableDictionary::curated().contains_word_str("giants")); + assert!(MutableDictionary::curated("en").contains_word_str("giants")); } #[test] fn expanded_contains_deallocate() { - assert!(MutableDictionary::curated().contains_word_str("deallocate")); + assert!(MutableDictionary::curated("en").contains_word_str("deallocate")); } #[test] fn curated_contains_repo() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); assert!(dict.contains_word_str("repo")); assert!(dict.contains_word_str("repos")); @@ -347,7 +396,7 @@ mod tests { #[test] fn curated_contains_possessive_abandonment() { assert!( - MutableDictionary::curated() + MutableDictionary::curated("en") .get_word_metadata_str("abandonment's") .unwrap() .is_possessive_noun() @@ -356,7 +405,7 @@ mod tests { #[test] fn has_is_not_a_nominal() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); let has = dict.get_word_metadata_str("has"); assert!(has.is_some()); @@ -366,7 +415,7 @@ mod tests { #[test] fn is_is_linking_verb() { - let dict = MutableDictionary::curated(); + let dict = MutableDictionary::curated("en"); let is = dict.get_word_metadata_str("is"); @@ -377,10 +426,21 @@ mod tests { #[test] fn are_merged_attrs_same_as_spread_attrs() { let curated_attr_list = include_str!("../../affixes.json"); - - let merged = MutableDictionary::from_rune_files("1\nblork/DGS", curated_attr_list).unwrap(); - let spread = - MutableDictionary::from_rune_files("2\nblork/DG\nblork/S", curated_attr_list).unwrap(); + eprintln!("##🧪## are_merged_attrs_same_as_spread_attrs()"); + let merged = MutableDictionary::from_rune_files( + // "fake_language_code_amasasa_m", + "en", + "1\nblork/DGS", + curated_attr_list, + ) + .unwrap(); + let spread = MutableDictionary::from_rune_files( + // "fake_language_code_amasasa_s", + "en", + "2\nblork/DG\nblork/S", + curated_attr_list, + ) + .unwrap(); assert_eq!( merged.word_map.into_iter().collect::>(), diff --git a/harper-core/src/spell/mutable_dictionary_es.rs b/harper-core/src/spell/mutable_dictionary_es.rs new file mode 100644 index 0000000000..e92ef12a53 --- /dev/null +++ b/harper-core/src/spell/mutable_dictionary_es.rs @@ -0,0 +1,11 @@ +#[cfg(test)] +mod tests { + use crate::{Dictionary, MutableDictionary}; + + #[test] + fn curated_matches_capitalized_es() { + let dict = MutableDictionary::curated("es"); + assert!(dict.contains_word_str("este")); + assert!(dict.contains_word_str("Este")); + } +} \ No newline at end of file diff --git a/harper-core/src/title_case.rs b/harper-core/src/title_case.rs index b4f623fc72..8912f1a8ac 100644 --- a/harper-core/src/title_case.rs +++ b/harper-core/src/title_case.rs @@ -118,7 +118,11 @@ mod tests { #[test] fn normal() { assert_eq!( - make_title_case_str("this is a test", &PlainEnglish, &FstDictionary::curated()), + make_title_case_str( + "this is a test", + &PlainEnglish, + &FstDictionary::curated("en") + ), "This Is a Test" ) } @@ -129,7 +133,7 @@ mod tests { make_title_case_str( "the first and last words should be capitalized, even if it is \"the\"", &PlainEnglish, - &FstDictionary::curated() + &FstDictionary::curated("en") ), "The First and Last Words Should Be Capitalized, Even If It Is \"The\"" ) @@ -139,7 +143,7 @@ mod tests { #[test] fn about_uppercase_with_numbers() { assert_eq!( - make_title_case_str("0 about 0", &PlainEnglish, &FstDictionary::curated()), + make_title_case_str("0 about 0", &PlainEnglish, &FstDictionary::curated("en")), "0 About 0" ) } @@ -147,7 +151,7 @@ mod tests { #[test] fn pipe_does_not_cause_crash() { assert_eq!( - make_title_case_str("|", &Markdown::default(), &FstDictionary::curated()), + make_title_case_str("|", &Markdown::default(), &FstDictionary::curated("en")), "|" ) } @@ -155,7 +159,7 @@ mod tests { #[test] fn a_paragraph_does_not_cause_crash() { assert_eq!( - make_title_case_str("A\n", &Markdown::default(), &FstDictionary::curated()), + make_title_case_str("A\n", &Markdown::default(), &FstDictionary::curated("en")), "A" ) } @@ -163,7 +167,7 @@ mod tests { #[test] fn tab_a_becomes_upcase() { assert_eq!( - make_title_case_str("\ta", &PlainEnglish, &FstDictionary::curated()), + make_title_case_str("\ta", &PlainEnglish, &FstDictionary::curated("en")), "\tA" ) } @@ -171,7 +175,7 @@ mod tests { #[test] fn fixes_video_press() { assert_eq!( - make_title_case_str("videopress", &PlainEnglish, &FstDictionary::curated()), + make_title_case_str("videopress", &PlainEnglish, &FstDictionary::curated("en")), "VideoPress" ) } @@ -190,7 +194,7 @@ mod tests { let title_case: Vec<_> = make_title_case_str( &format!("{prefix} a {postfix}"), &Markdown::default(), - &FstDictionary::curated(), + &FstDictionary::curated("en"), ) .chars() .collect(); @@ -212,7 +216,7 @@ mod tests { let title_case: Vec<_> = make_title_case_str( &format!("{prefix} about {postfix}"), &Markdown::default(), - &FstDictionary::curated(), + &FstDictionary::curated("en"), ) .chars() .collect(); @@ -223,7 +227,7 @@ mod tests { #[quickcheck] fn first_word_is_upcase(text: String) -> TestResult { let title_case: Vec<_> = - make_title_case_str(&text, &PlainEnglish, &FstDictionary::curated()) + make_title_case_str(&text, &PlainEnglish, &FstDictionary::curated("en")) .chars() .collect(); @@ -241,7 +245,11 @@ mod tests { #[test] fn united_states() { assert_eq!( - make_title_case_str("united states", &PlainEnglish, &FstDictionary::curated()), + make_title_case_str( + "united states", + &PlainEnglish, + &FstDictionary::curated("en") + ), "United States" ) } diff --git a/harper-core/tests/run_tests.rs b/harper-core/tests/run_tests.rs index 5a37291539..b4b4a3a806 100644 --- a/harper-core/tests/run_tests.rs +++ b/harper-core/tests/run_tests.rs @@ -15,7 +15,7 @@ macro_rules! create_test { ) ); - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let document = Document::new_markdown_default(&source, &dict); let mut linter = LintGroup::new_curated(dict, $dialect); diff --git a/harper-html/tests/run_tests.rs b/harper-html/tests/run_tests.rs index 3e3e36520c..cf49a8caa9 100644 --- a/harper-html/tests/run_tests.rs +++ b/harper-html/tests/run_tests.rs @@ -15,7 +15,7 @@ macro_rules! create_test { ) ); - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let document = Document::new_markdown_default(&source, &dict); let mut linter = LintGroup::new_curated(dict, Dialect::American); diff --git a/harper-literate-haskell/tests/run_tests.rs b/harper-literate-haskell/tests/run_tests.rs index 6f0b706437..23d769094c 100644 --- a/harper-literate-haskell/tests/run_tests.rs +++ b/harper-literate-haskell/tests/run_tests.rs @@ -17,8 +17,8 @@ macro_rules! create_test { ) ); - let dict = FstDictionary::curated(); - let document = Document::new_curated(&source, &LiterateHaskellParser::new_markdown(MarkdownOptions::default())); + let dict = FstDictionary::curated("en"); + let document = Document::new_curated(&source, &LiterateHaskellParser::new_markdown(MarkdownOptions::default()), "en"); let mut linter = LintGroup::new_curated(dict, Dialect::American); let lints = linter.lint(&document); diff --git a/harper-ls/src/backend.rs b/harper-ls/src/backend.rs index 400adfa3e6..f63d3b801e 100644 --- a/harper-ls/src/backend.rs +++ b/harper-ls/src/backend.rs @@ -56,10 +56,18 @@ impl Backend { } /// Load a specific file's dictionary - async fn load_file_dictionary(&self, url: &Url) -> anyhow::Result { + async fn load_file_dictionary( + &self, + url: &Url, + langiso639: &str, + ) -> anyhow::Result { // VS Code's unsaved documents have "untitled" scheme + eprintln!( + "##📁## load_file_dictionary() :: scheme: '{}'", + url.scheme() + ); if url.scheme() == "untitled" { - return Ok(MutableDictionary::new()); + return Ok(MutableDictionary::new(langiso639)); } let path = self @@ -67,10 +75,11 @@ impl Backend { .await .context("Unable to get the file path.")?; - load_dict(path) + eprintln!("##🗂️## load_file_directory() / load_dict()"); + load_dict(path, langiso639) .await .map_err(|err| info!("{err}")) - .or(Ok(MutableDictionary::new())) + .or(Ok(MutableDictionary::new(langiso639))) } /// Compute the location of the file's specific dictionary @@ -94,10 +103,11 @@ impl Backend { async fn load_user_dictionary(&self) -> MutableDictionary { let config = self.config.read().await; - load_dict(&config.user_dict_path) + eprintln!("##👤## load_user_dictionary() / load_dict()"); + load_dict(&config.user_dict_path, &config.langiso639) .await .map_err(|err| info!("{err}")) - .unwrap_or(MutableDictionary::new()) + .unwrap_or(MutableDictionary::new(&config.langiso639)) } async fn save_user_dictionary(&self, dict: impl Dictionary) -> Result<()> { @@ -129,17 +139,26 @@ impl Backend { } async fn generate_global_dictionary(&self) -> Result { - let mut dict = MergedDictionary::new(); - dict.add_dictionary(FstDictionary::curated()); + eprintln!("##🧜‍♀️## generate_global_dictionary() / MergedDictionary::new()"); + // let mut dict = MergedDictionary::new("fake_language_code_ggdm"); + let mut dict = MergedDictionary::new("en"); + eprintln!("##🥌## generate_global_dictionary() / FstDictionary::curated()"); + // dict.add_dictionary(FstDictionary::curated("fake_language_code_ggdc")); // TODO + // dict.add_dictionary(FstDictionary::curated("es")); // TODO + dict.add_dictionary(FstDictionary::curated("en")); // TODO let user_dict = self.load_user_dictionary().await; dict.add_dictionary(Arc::new(user_dict)); Ok(dict) } - async fn generate_file_dictionary(&self, url: &Url) -> Result { + async fn generate_file_dictionary( + &self, + url: &Url, + langiso639: &str, + ) -> Result { let (global_dictionary, file_dictionary) = tokio::join!( self.generate_global_dictionary(), - self.load_file_dictionary(url) + self.load_file_dictionary(url, langiso639) ); let mut global_dictionary = @@ -171,18 +190,19 @@ impl Backend { self.pull_config().await; // Copy necessary configuration to avoid holding lock. - let (lint_config, markdown_options, isolate_english, dialect) = { + let (lint_config, markdown_options, isolate_english, dialect, langiso639) = { let config = self.config.read().await; ( config.lint_config.clone(), config.markdown_options, config.isolate_english, config.dialect, + config.langiso639.clone(), ) }; let dict = Arc::new( - self.generate_file_dictionary(url) + self.generate_file_dictionary(url, &langiso639) .await .context("Unable to generate the file dictionary.")?, ); @@ -195,21 +215,21 @@ impl Backend { DocumentState { linter: LintGroup::new_curated(dict.clone(), dialect) .with_lint_config(lint_config.clone()), - language_id: language_id.map(|v| v.to_string()), - dict: dict.clone(), + code_language_id: language_id.map(|v| v.to_string()), + dict: Some(dict.clone()), url: url.clone(), ..Default::default() } }); - if doc_state.dict != dict { - doc_state.dict = dict.clone(); + if doc_state.dict.as_ref() != Some(&dict) { + doc_state.dict = Some(dict.clone()); info!("Constructing new linter because of modified dictionary."); doc_state.linter = LintGroup::new_curated(dict.clone(), dialect).with_lint_config(lint_config.clone()); } - let Some(language_id) = &doc_state.language_id else { + let Some(language_id) = &doc_state.code_language_id else { doc_lock.remove(url); return Ok(()); }; @@ -221,24 +241,27 @@ impl Backend { url: &'a Url, doc_state: &'a mut DocumentState, lint_config: &LintGroupConfig, + // TODO: langiso639 ? dialect: Dialect, ) -> Result> { - if doc_state.ident_dict != new_dict { + if doc_state.ident_dict.as_ref() != Some(&new_dict) { info!("Constructing new linter because of modified ident dictionary."); - doc_state.ident_dict = new_dict.clone(); + doc_state.ident_dict = Some(new_dict.clone()); + + let langiso639 = new_dict.get_langiso639(); - let mut merged = backend.generate_file_dictionary(url).await?; + let mut merged = backend.generate_file_dictionary(url, langiso639).await?; merged.add_dictionary(new_dict); let merged = Arc::new(merged); doc_state.linter = LintGroup::new_curated(merged.clone(), dialect) .with_lint_config(lint_config.clone()); - doc_state.dict = merged.clone(); + doc_state.dict = Some(merged.clone()); } Ok(Box::new(CollapseIdentifiers::new( Box::new(parser), - Box::new(doc_state.dict.clone()), + Box::new(doc_state.dict.clone().unwrap()), ))) } @@ -302,11 +325,16 @@ impl Backend { doc_lock.remove(url); } Some(mut parser) => { + // TODO: currently english-specific if isolate_english { - parser = Box::new(IsolateEnglish::new(parser, doc_state.dict.clone())); + // TODO: currently english-specific + parser = Box::new(IsolateEnglish::new( + parser, + doc_state.dict.as_ref().unwrap().clone(), + )); } - doc_state.document = Document::new(text, &parser, &doc_state.dict); + doc_state.document = Document::new(text, &parser, doc_state.dict.as_ref().unwrap()); } } @@ -577,8 +605,11 @@ impl LanguageServer for Backend { let file_url = second.parse().unwrap(); + let config = self.config.read().await; + let langiso639 = config.langiso639.clone(); + let mut dict = match self - .load_file_dictionary(&file_url) + .load_file_dictionary(&file_url, &langiso639) .await .map_err(|err| error!("{err}")) { @@ -657,7 +688,7 @@ impl LanguageServer for Backend { for doc in doc_lock.values_mut() { info!("Constructing new LintGroup for updated configuration."); - doc.linter = LintGroup::new_curated(doc.dict.clone(), config_lock.dialect) + doc.linter = LintGroup::new_curated(doc.dict.clone().unwrap(), config_lock.dialect) .with_lint_config(config_lock.lint_config.clone()); } diff --git a/harper-ls/src/config.rs b/harper-ls/src/config.rs index 4ebd2d104b..6a01048696 100644 --- a/harper-ls/src/config.rs +++ b/harper-ls/src/config.rs @@ -71,6 +71,7 @@ pub struct Config { pub code_action_config: CodeActionConfig, pub isolate_english: bool, pub markdown_options: MarkdownOptions, + pub langiso639: String, pub dialect: Dialect, } @@ -163,6 +164,7 @@ impl Default for Config { code_action_config: CodeActionConfig::default(), isolate_english: false, markdown_options: MarkdownOptions::default(), + langiso639: "en".to_string(), dialect: Dialect::American, } } diff --git a/harper-ls/src/dictionary_io.rs b/harper-ls/src/dictionary_io.rs index dfbb5908a4..79b74a4daa 100644 --- a/harper-ls/src/dictionary_io.rs +++ b/harper-ls/src/dictionary_io.rs @@ -38,22 +38,25 @@ async fn write_word_list(dict: impl Dictionary, mut w: impl AsyncWrite + Unpin) } /// Load a dictionary from a file on disk. -pub async fn load_dict(path: impl AsRef) -> Result { +pub async fn load_dict(path: impl AsRef, langiso639: &str) -> Result { let file = File::open(path.as_ref()).await?; let read = BufReader::new(file); - dict_from_word_list(read).await + dict_from_word_list(read, langiso639).await } /// Load a dictionary from a list of words. /// It could definitely be optimized to use less memory. /// Right now it isn't an issue. -async fn dict_from_word_list(mut r: impl AsyncRead + Unpin) -> Result { +async fn dict_from_word_list( + mut r: impl AsyncRead + Unpin, + langiso639: &str, +) -> Result { let mut str = String::new(); r.read_to_string(&mut str).await?; - let mut dict = MutableDictionary::new(); + let mut dict = MutableDictionary::new(langiso639); dict.extend_words( str.lines() .map(|l| (l.chars().collect::>(), WordMetadata::default())), diff --git a/harper-ls/src/document_state.rs b/harper-ls/src/document_state.rs index 7dfa113a39..17826b65f9 100644 --- a/harper-ls/src/document_state.rs +++ b/harper-ls/src/document_state.rs @@ -8,10 +8,10 @@ use tower_lsp::lsp_types::{CodeActionOrCommand, Command, Diagnostic, Range, Url} pub struct DocumentState { pub document: Document, - pub ident_dict: Lrc, - pub dict: Lrc, + pub ident_dict: Option>, + pub dict: Option>, pub linter: LintGroup, - pub language_id: Option, + pub code_language_id: Option, pub ignored_lints: IgnoredLints, pub url: Url, } @@ -90,7 +90,7 @@ impl Default for DocumentState { ident_dict: Default::default(), dict: Default::default(), linter: Default::default(), - language_id: Default::default(), + code_language_id: Default::default(), ignored_lints: Default::default(), url: Url::parse("https://example.net").unwrap(), } diff --git a/harper-tree-sitter/src/lib.rs b/harper-tree-sitter/src/lib.rs index 8e3516970d..e2854b4528 100644 --- a/harper-tree-sitter/src/lib.rs +++ b/harper-tree-sitter/src/lib.rs @@ -26,7 +26,11 @@ impl TreeSitterMasker { parser.parse(text, None) } - pub fn create_ident_dict(&self, source: &[char]) -> Option { + pub fn create_ident_dict( + &self, + langiso639: &str, + source: &[char], + ) -> Option { let text: String = source.iter().collect(); // Byte-indexed @@ -52,7 +56,7 @@ impl TreeSitterMasker { .map(|ident| (ident, WordMetadata::default())) .collect(); - let mut dictionary = MutableDictionary::new(); + let mut dictionary = MutableDictionary::new(langiso639); dictionary.extend_words(idents); Some(dictionary) diff --git a/harper-typst/tests/run_tests.rs b/harper-typst/tests/run_tests.rs index b89edd8a56..6b624f015b 100644 --- a/harper-typst/tests/run_tests.rs +++ b/harper-typst/tests/run_tests.rs @@ -16,7 +16,7 @@ macro_rules! create_test { ) ); - let dict = FstDictionary::curated(); + let dict = FstDictionary::curated("en"); let document = Document::new(&source, &Typst, &dict); let mut linter = LintGroup::new_curated(dict, Dialect::American); diff --git a/harper-typst/tests/tests.rs b/harper-typst/tests/tests.rs index 762142dec9..adb03dc925 100644 --- a/harper-typst/tests/tests.rs +++ b/harper-typst/tests/tests.rs @@ -8,7 +8,7 @@ use harper_typst::Typst; fn number() { let source = "12 is larger than 11, but much less than 11!"; - let document = Document::new_curated(source, &Typst); + let document = Document::new_curated(source, &Typst, "en"); let token_kinds = document.tokens().map(|t| t.kind.clone()).collect_vec(); dbg!(&token_kinds); @@ -56,7 +56,7 @@ fn number() { fn math_unlintable() { let source = "$12 > 11$, $12 << 11!$"; - let document = Document::new_curated(source, &Typst); + let document = Document::new_curated(source, &Typst, "en"); let token_kinds = document.tokens().map(|t| t.kind.clone()).collect_vec(); dbg!(&token_kinds); @@ -78,7 +78,7 @@ fn dict_parsing() { born: 2019, )"#; - let document = Document::new_curated(source, &Typst); + let document = Document::new_curated(source, &Typst, "en"); let token_kinds = document.tokens().map(|t| t.kind.clone()).collect_vec(); dbg!(&token_kinds); @@ -102,7 +102,7 @@ fn dict_parsing() { fn str_parsing() { let source = r#"#let ident = "This is a string""#; - let document = Document::new_curated(source, &Typst); + let document = Document::new_curated(source, &Typst, "en"); let token_kinds = document.tokens().map(|t| t.kind.clone()).collect_vec(); dbg!(&token_kinds); @@ -125,7 +125,7 @@ fn str_parsing() { fn non_adjacent_spaces_not_condensed() { let source = r#"#authors_slice.join(", ", last: ", and ") bob"#; - let document = Document::new_curated(source, &Typst); + let document = Document::new_curated(source, &Typst, "en"); let token_kinds = document.tokens().map(|t| t.kind.clone()).collect_vec(); dbg!(&token_kinds); @@ -151,7 +151,7 @@ fn header_parsing() { let source = "= Header Paragraph"; - let document = Document::new_curated(source, &Typst); + let document = Document::new_curated(source, &Typst, "en"); let token_kinds = document.tokens().map(|t| t.kind.clone()).collect_vec(); dbg!(&token_kinds); @@ -176,7 +176,7 @@ fn parbreak() { Paragraph"; - let document = Document::new_curated(source, &Typst); + let document = Document::new_curated(source, &Typst, "en"); let token_kinds = document.tokens().map(|t| t.kind.clone()).collect_vec(); dbg!(&token_kinds); @@ -196,7 +196,7 @@ fn label_ref_unlintable() {