mirror of
https://github.com/crate-ci/typos.git
synced 2024-11-22 17:11:07 -05:00
Merge pull request #854 from epage/word
feat(config): Allow ignoring words by regex
This commit is contained in:
commit
f8405997c6
8 changed files with 58 additions and 6 deletions
|
@ -425,6 +425,8 @@ pub struct DictConfig {
|
||||||
#[serde(with = "serde_regex")]
|
#[serde(with = "serde_regex")]
|
||||||
pub extend_ignore_identifiers_re: Vec<regex::Regex>,
|
pub extend_ignore_identifiers_re: Vec<regex::Regex>,
|
||||||
pub extend_identifiers: HashMap<kstring::KString, kstring::KString>,
|
pub extend_identifiers: HashMap<kstring::KString, kstring::KString>,
|
||||||
|
#[serde(with = "serde_regex")]
|
||||||
|
pub extend_ignore_words_re: Vec<regex::Regex>,
|
||||||
pub extend_words: HashMap<kstring::KString, kstring::KString>,
|
pub extend_words: HashMap<kstring::KString, kstring::KString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,6 +437,7 @@ impl DictConfig {
|
||||||
locale: Some(empty.locale()),
|
locale: Some(empty.locale()),
|
||||||
extend_ignore_identifiers_re: Default::default(),
|
extend_ignore_identifiers_re: Default::default(),
|
||||||
extend_identifiers: Default::default(),
|
extend_identifiers: Default::default(),
|
||||||
|
extend_ignore_words_re: Default::default(),
|
||||||
extend_words: Default::default(),
|
extend_words: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,6 +454,8 @@ impl DictConfig {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, value)| (key.clone(), value.clone())),
|
.map(|(key, value)| (key.clone(), value.clone())),
|
||||||
);
|
);
|
||||||
|
self.extend_ignore_words_re
|
||||||
|
.extend(source.extend_ignore_words_re.iter().cloned());
|
||||||
self.extend_words.extend(
|
self.extend_words.extend(
|
||||||
source
|
source
|
||||||
.extend_words
|
.extend_words
|
||||||
|
@ -475,6 +480,10 @@ impl DictConfig {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extend_ignore_words_re(&self) -> Box<dyn Iterator<Item = ®ex::Regex> + '_> {
|
||||||
|
Box::new(self.extend_ignore_words_re.iter())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn extend_words(&self) -> Box<dyn Iterator<Item = (&str, &str)> + '_> {
|
pub fn extend_words(&self) -> Box<dyn Iterator<Item = (&str, &str)> + '_> {
|
||||||
Box::new(
|
Box::new(
|
||||||
self.extend_words
|
self.extend_words
|
||||||
|
@ -503,6 +512,11 @@ impl PartialEq for DictConfig {
|
||||||
.map(|r| r.as_str())
|
.map(|r| r.as_str())
|
||||||
.eq(rhs.extend_ignore_identifiers_re.iter().map(|r| r.as_str()))
|
.eq(rhs.extend_ignore_identifiers_re.iter().map(|r| r.as_str()))
|
||||||
&& self.extend_identifiers == rhs.extend_identifiers
|
&& self.extend_identifiers == rhs.extend_identifiers
|
||||||
|
&& self
|
||||||
|
.extend_ignore_words_re
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.as_str())
|
||||||
|
.eq(rhs.extend_ignore_words_re.iter().map(|r| r.as_str()))
|
||||||
&& self.extend_words == rhs.extend_words
|
&& self.extend_words == rhs.extend_words
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,7 @@ fn case_correct(correction: &mut Cow<'_, str>, case: Case) {
|
||||||
pub struct Override<'i, 'w, D> {
|
pub struct Override<'i, 'w, D> {
|
||||||
ignored_identifiers: Vec<regex::Regex>,
|
ignored_identifiers: Vec<regex::Regex>,
|
||||||
identifiers: HashMap<&'i str, Status<'i>, ahash::RandomState>,
|
identifiers: HashMap<&'i str, Status<'i>, ahash::RandomState>,
|
||||||
|
ignored_words: Vec<regex::Regex>,
|
||||||
words: HashMap<unicase::UniCase<&'w str>, Status<'w>, ahash::RandomState>,
|
words: HashMap<unicase::UniCase<&'w str>, Status<'w>, ahash::RandomState>,
|
||||||
inner: D,
|
inner: D,
|
||||||
}
|
}
|
||||||
|
@ -225,6 +226,7 @@ impl<'i, 'w, D: typos::Dictionary> Override<'i, 'w, D> {
|
||||||
Self {
|
Self {
|
||||||
ignored_identifiers: Default::default(),
|
ignored_identifiers: Default::default(),
|
||||||
identifiers: Default::default(),
|
identifiers: Default::default(),
|
||||||
|
ignored_words: Default::default(),
|
||||||
words: Default::default(),
|
words: Default::default(),
|
||||||
inner,
|
inner,
|
||||||
}
|
}
|
||||||
|
@ -238,6 +240,10 @@ impl<'i, 'w, D: typos::Dictionary> Override<'i, 'w, D> {
|
||||||
self.identifiers = Self::interpret(identifiers).collect();
|
self.identifiers = Self::interpret(identifiers).collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ignored_words<'r>(&mut self, ignored: impl Iterator<Item = &'r regex::Regex>) {
|
||||||
|
self.ignored_words.extend(ignored.cloned());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn words<I: Iterator<Item = (&'w str, &'w str)>>(&mut self, words: I) {
|
pub fn words<I: Iterator<Item = (&'w str, &'w str)>>(&mut self, words: I) {
|
||||||
self.words = Self::interpret(words)
|
self.words = Self::interpret(words)
|
||||||
.map(|(k, v)| (UniCase::new(k), v))
|
.map(|(k, v)| (UniCase::new(k), v))
|
||||||
|
@ -283,15 +289,22 @@ impl<'i, 'w, D: typos::Dictionary> typos::Dictionary for Override<'i, 'w, D> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ignored in &self.ignored_words {
|
||||||
|
if ignored.is_match(word.token()) {
|
||||||
|
return Some(Status::Valid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Skip hashing if we can
|
// Skip hashing if we can
|
||||||
let custom = if !self.words.is_empty() {
|
if !self.words.is_empty() {
|
||||||
let w = UniCase::new(word.token());
|
let w = UniCase::new(word.token());
|
||||||
// HACK: couldn't figure out the lifetime issue with replacing `cloned` with `borrow`
|
// HACK: couldn't figure out the lifetime issue with replacing `cloned` with `borrow`
|
||||||
self.words.get(&w).cloned()
|
if let Some(status) = self.words.get(&w).cloned() {
|
||||||
} else {
|
return Some(status);
|
||||||
None
|
}
|
||||||
};
|
}
|
||||||
custom.or_else(|| self.inner.correct_word(word))
|
|
||||||
|
self.inner.correct_word(word)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,6 +255,7 @@ impl<'s> ConfigEngine<'s> {
|
||||||
.extend_identifiers()
|
.extend_identifiers()
|
||||||
.map(|(k, v)| (self.storage.get(k), self.storage.get(v))),
|
.map(|(k, v)| (self.storage.get(k), self.storage.get(v))),
|
||||||
);
|
);
|
||||||
|
dict.ignored_words(dict_config.extend_ignore_words_re());
|
||||||
dict.words(
|
dict.words(
|
||||||
dict_config
|
dict_config
|
||||||
.extend_words()
|
.extend_words()
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
[default.extend-words]
|
||||||
|
hello = "goodbye"
|
||||||
|
|
||||||
|
[type.fail]
|
||||||
|
extend-glob = ["*.fail"]
|
||||||
|
|
||||||
|
[type.ignore]
|
||||||
|
extend-glob = ["*.ignore"]
|
||||||
|
extend-ignore-words-re = ["he.*"]
|
|
@ -0,0 +1 @@
|
||||||
|
hello
|
|
@ -0,0 +1 @@
|
||||||
|
hello
|
12
crates/typos-cli/tests/cmd/extend-ignore-words-re.toml
Normal file
12
crates/typos-cli/tests/cmd/extend-ignore-words-re.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
bin.name = "typos"
|
||||||
|
status.code = 2
|
||||||
|
stdin = ""
|
||||||
|
stdout = """
|
||||||
|
error: `hello` should be `goodbye`
|
||||||
|
--> ./file.fail:1:1
|
||||||
|
|
|
||||||
|
1 | hello
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
"""
|
||||||
|
stderr = ""
|
|
@ -34,6 +34,7 @@ Configuration is read from the following (in precedence order)
|
||||||
| default.extend-identifiers | \- | table of strings | Corrections for [identifiers](./design.md#identifiers-and-words). When the correction is blank, the identifier is never valid. When the correction is the key, the identifier is always valid. |
|
| default.extend-identifiers | \- | table of strings | Corrections for [identifiers](./design.md#identifiers-and-words). When the correction is blank, the identifier is never valid. When the correction is the key, the identifier is always valid. |
|
||||||
| default.extend-ignore-identifiers-re | \- | list of [regexes](https://docs.rs/regex/latest/regex/index.html#syntax) | Pattern-match always-valid identifiers |
|
| default.extend-ignore-identifiers-re | \- | list of [regexes](https://docs.rs/regex/latest/regex/index.html#syntax) | Pattern-match always-valid identifiers |
|
||||||
| default.extend-words | \- | table of strings | Corrections for [words](./design.md#identifiers-and-words). When the correction is blank, the word is never valid. When the correction is the key, the word is always valid. |
|
| default.extend-words | \- | table of strings | Corrections for [words](./design.md#identifiers-and-words). When the correction is blank, the word is never valid. When the correction is the key, the word is always valid. |
|
||||||
|
| default.extend-ignore-words-re | \- | list of [regexes](https://docs.rs/regex/latest/regex/index.html#syntax) | Pattern-match always-valid words. Note: you must handle case insensitivity yourself |
|
||||||
| type.\<name>.\<field> | \<varied> | \<varied> | See `default.` for child keys. Run with `--type-list` to see available `<name>`s |
|
| type.\<name>.\<field> | \<varied> | \<varied> | See `default.` for child keys. Run with `--type-list` to see available `<name>`s |
|
||||||
| type.\<name>.extend-glob | \- | list of strings | File globs for matching `<name>` |
|
| type.\<name>.extend-glob | \- | list of strings | File globs for matching `<name>` |
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue