diff --git a/Cargo.lock b/Cargo.lock index 9170df7..456b7d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,7 +235,7 @@ dependencies = [ "regex", "serde", "serde_json", - "spellbook", + "spellbook 0.2.0 (git+https://github.com/helix-editor/spellbook.git#b6c31ea)", "streaming-iterator", "tempfile", "tokio", @@ -268,7 +268,7 @@ dependencies = [ "regex", "serde", "serde_json", - "spellbook", + "spellbook 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "streaming-iterator", "tempfile", "tokio", @@ -1110,6 +1110,15 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "spellbook" +version = "0.2.0" +source = "git+https://github.com/helix-editor/spellbook.git#b6c31ea#b6c31ea767443437e44ddd3786318202d8a157ec" +dependencies = [ + "ahash", + "hashbrown 0.15.2", +] + [[package]] name = "spin" version = "0.9.8" diff --git a/codebook/Cargo.toml b/codebook/Cargo.toml index 385210d..06eeb17 100644 --- a/codebook/Cargo.toml +++ b/codebook/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] lazy_static = "1.5.0" regex = "1.11.1" -spellbook = "0.2.0" +spellbook = { git = "https://github.com/helix-editor/spellbook.git#b6c31ea" } tree-sitter = "<0.25.0" tree-sitter-css = "<0.25.0" tree-sitter-rust = "<0.25.0" diff --git a/codebook/src/dictionary.rs b/codebook/src/dictionary.rs index 9325bb0..00c5840 100644 --- a/codebook/src/dictionary.rs +++ b/codebook/src/dictionary.rs @@ -34,6 +34,13 @@ pub struct TextRange { pub end_line: u32, } +enum WordCase { + AllCaps, + AllLower, + TitleCase, + Unknown, +} + #[derive(Debug)] pub struct CodeDictionary { custom_dictionary: Arc>>, @@ -74,7 +81,26 @@ impl CodeDictionary { if self.config.is_allowed_word(&lower_word) { return true; } - self.dictionary.check(word) + if self.dictionary.check(word) { + return true; + } + if self + .dictionary + .checker() + .check_lower_as_title(true) + .check(word) + { + return true; + } + if self + .dictionary + .checker() + .check_lower_as_upper(true) + .check(word) + { + return true; + } + false } pub fn add_to_dictionary(&self, strings: &str) { @@ -99,6 +125,24 @@ impl CodeDictionary { self.dictionary.suggest(word, &mut suggestions); suggestions.truncate(5); if !suggestions.is_empty() { + let word_case = self.get_word_case(&word); + // mutate suggestions in place to match case + + for suggestion in &mut suggestions { + match word_case { + WordCase::AllCaps => { + suggestion.make_ascii_uppercase(); + } + WordCase::AllLower => { + suggestion.make_ascii_lowercase(); + } + WordCase::TitleCase => { + // Leave it alone if it's a title case + } + WordCase::Unknown => {} + } + } + self.suggestion_cache .write() .unwrap() @@ -107,6 +151,19 @@ impl CodeDictionary { suggestions } + fn get_word_case(&self, word: &str) -> WordCase { + if word.chars().all(char::is_uppercase) { + return WordCase::AllCaps; + } + if word.chars().all(char::is_lowercase) { + return WordCase::AllLower; + } + if word.chars().next().unwrap().is_uppercase() { + return WordCase::TitleCase; + } + WordCase::Unknown + } + pub fn spell_check( &self, text: &str, @@ -328,7 +385,6 @@ mod dictionary_tests { #[test] fn test_spell_checking() { let processor = get_dict(); - let text = "HelloWorld calc_wrld"; let misspelled = processor.spell_check_type(text, LanguageType::Text); println!("{:?}", misspelled); @@ -413,8 +469,15 @@ mod dictionary_tests { let suggestions = dict.suggest("wrld"); println!("{:?}", suggestions); assert!(suggestions.contains(&"world".to_string())); + } + + #[test] + fn test_ignore_case() { + let dict = get_dict(); + let check = dict.check("alice"); + assert!(check); let suggestions = dict.suggest("alice"); println!("{:?}", suggestions); - assert!(suggestions.contains(&"Alice".to_string())); + assert!(suggestions.contains(&"alice".to_string())); } } diff --git a/codebook/src/queries.rs b/codebook/src/queries.rs index d511462..10a24ea 100644 --- a/codebook/src/queries.rs +++ b/codebook/src/queries.rs @@ -130,6 +130,10 @@ pub static LANGUAGE_SETTINGS: &[LanguageSetting] = &[ (argument_list (interpreted_string_literal) @string) (function_declaration (identifier) @identifier) (raw_string_literal) @raw_string + (expression_list + (interpreted_string_literal) @string + ) + (var_spec (identifier) @identifier) "#, extensions: &["go"], }, diff --git a/codebook/tests/test_go.rs b/codebook/tests/test_go.rs index ecf52ee..fa25ef4 100644 --- a/codebook/tests/test_go.rs +++ b/codebook/tests/test_go.rs @@ -7,9 +7,14 @@ mod utils; #[test] fn test_go_location() { + utils::init_logging(); let sample_text = r#" + import ( + "fmt" + ) func mispeledFuncion() string { - return "" + var alicz = "Alizzz" + return alicz }"#; let expected = vec![ SpellCheckResult::new( @@ -17,8 +22,8 @@ fn test_go_location() { vec![TextRange { start_char: 9, end_char: 17, - start_line: 1, - end_line: 1, + start_line: 4, + end_line: 4, }], ), SpellCheckResult::new( @@ -26,19 +31,41 @@ fn test_go_location() { vec![TextRange { start_char: 17, end_char: 24, - start_line: 1, - end_line: 1, + start_line: 4, + end_line: 4, + }], + ), + SpellCheckResult::new( + "Alizzz".to_string(), + vec![TextRange { + start_char: 21, + end_char: 27, + start_line: 5, + end_line: 5, + }], + ), + SpellCheckResult::new( + "alicz".to_string(), + vec![TextRange { + start_char: 12, + end_char: 17, + start_line: 5, + end_line: 5, }], ), ]; + let not_expected = ["fmt"]; let processor = utils::get_processor(); let misspelled = processor - .spell_check(sample_text, Some(LanguageType::Text), None) + .spell_check(sample_text, Some(LanguageType::Go), None) .to_vec(); println!("Misspelled words: {misspelled:?}"); for e in &expected { - let miss = misspelled.iter().find(|r| r.word == e.word).unwrap(); println!("Expecting: {e:?}"); + let miss = misspelled.iter().find(|r| r.word == e.word).unwrap(); assert_eq!(miss.locations, e.locations); } + for result in misspelled { + assert!(!not_expected.contains(&result.word.as_str())); + } } diff --git a/examples/example.go b/examples/example.go index 5b337d5..1d1155e 100644 --- a/examples/example.go +++ b/examples/example.go @@ -7,8 +7,10 @@ import ( func main() { // I'm bad at speling alice fmt.Println("Hello, Wolrd!") - var alice = "Alice" - fmt.Println("Hello, " + alice) + var alicz = "Alicz" + fmt.Println("Hello, " + alicz) + var rsvp = "RSVP" + fmt.Println("Hello, " + rsvp) } func mispeledFuncion() string {