use crate::{
CharStringExt, Lint, Token, TokenKind,
expr::{Expr, SequenceExpr},
linting::{ExprLinter, LintKind, Suggestion, expr_linter::Chunk},
};
pub struct NakedEye {
expr: SequenceExpr,
}
impl Default for NakedEye {
fn default() -> Self {
Self {
expr: SequenceExpr::optional(
SequenceExpr::word_set(&[
"hide", "hides", "hid", "hidden", "hiding", "keep", "keeps", "kept", "keeping",
])
.t_ws()
.then_optional(
SequenceExpr::optional(
SequenceExpr::default()
.then_kind_any(&[
TokenKind::is_determiner,
TokenKind::is_adjective,
TokenKind::is_oov,
])
.t_ws(),
)
.then_noun()
.t_ws(),
),
)
.then_preposition()
.t_ws()
.t_aco("the")
.t_ws()
.t_aco("naked")
.t_ws()
.t_set(&["eye", "eyes"]),
}
}
}
impl ExprLinter for NakedEye {
type Unit = Chunk;
fn match_to_lint(&self, toks: &[Token], src: &[char]) -> Option<Lint> {
let (verb, _adj, _noun, prep, _idiom) = match toks.len() {
7 => (None, None, None, &toks[0], &toks[2..]),
9 => (Some(&toks[0]), None, None, &toks[2], &toks[4..]),
11 => (Some(&toks[0]), None, Some(&toks[2]), &toks[4], &toks[6..]),
13 => (
Some(&toks[0]),
Some(&toks[2]),
Some(&toks[4]),
&toks[6],
&toks[8..],
),
_ => return None,
};
let prep = prep.span;
let prepch = prep.get_content(src);
match (
verb.is_some(),
prepch.eq_ch(&['f', 'r', 'o', 'm']),
prepch.eq_any_ignore_ascii_case_str(&["to", "with", "by"]),
) {
(_, _, true) => return None, (true, true, _) => return None, (_, false, _) => return None, (_, true, _) => (), };
let suggestions = ["to", "with", "by"]
.into_iter()
.map(|p| Suggestion::replace_with_match_case_str(p, prep.get_content(src)))
.collect();
Some(Lint {
span: prep,
lint_kind: LintKind::Miscellaneous,
suggestions,
message: "This idiom usually requires a different preposition.".to_string(),
..Default::default()
})
}
fn expr(&self) -> &dyn Expr {
&self.expr
}
fn description(&self) -> &str {
"Corrects the wrong preposition used instead of `to`, `with`, or `by` the naked eye."
}
}
#[cfg(test)]
mod tests {
use crate::linting::tests::{assert_no_lints, assert_suggestion_result};
use super::NakedEye;
#[test]
#[ignore = "Underscores are not parts of words"]
fn dont_flag_hiding_adj_noun_from() {
assert_no_lints(
"Once the opt-in is complete, the obtained lock() and unlock() utilities enable hiding __experimental APIs from the naked eye:",
NakedEye::default(),
);
}
#[test]
fn dont_flag_easily_hide_noun_from() {
assert_no_lints(
"But there is something we forgot about, something that allows one to easily hide things from the naked eye ... macros!",
NakedEye::default(),
);
}
#[test]
fn dont_flag_well_hidden_from() {
assert_no_lints(
"We successfully tampered with the release, well hidden from the naked eye.",
NakedEye::default(),
);
}
#[test]
fn but_from_the_naked_eye() {
assert_suggestion_result(
"As you can see from the pic the pedestrian is being detected but from the naked eye it can't be seen due to the slope.",
NakedEye::default(),
"As you can see from the pic the pedestrian is being detected but to the naked eye it can't be seen due to the slope.",
);
}
#[test]
fn even_from_the_naked_eye() {
assert_suggestion_result(
"the Photoshop one when even from the naked eye you can tell that if you were to zoom into",
NakedEye::default(),
"the Photoshop one when even with the naked eye you can tell that if you were to zoom into",
);
}
#[test]
fn looks_legit_to_the_naked_eye() {
assert_suggestion_result(
"In fact, it looks like legit 1080p from the naked eye I guess... ðŸ˜",
NakedEye::default(),
"In fact, it looks like legit 1080p to the naked eye I guess... ðŸ˜",
);
}
#[test]
fn observed_from_the_naked_eye() {
assert_suggestion_result(
"... when observed from the naked eye for the bone micro-architecture of the osteoporotic and healthy cases ...",
NakedEye::default(),
"... when observed with the naked eye for the bone micro-architecture of the osteoporotic and healthy cases ...",
);
}
#[test]
fn being_private_hidden_from() {
assert_no_lints(
"... which makes the entire concept of it being private hidden from the naked eye.",
NakedEye::default(),
);
}
#[test]
fn dont_flag_keep_det_noun_from() {
assert_no_lints(
"... but how can I keep this key from the naked eyes?",
NakedEye::default(),
);
}
#[test]
fn just_from_the_naked_eye() {
assert_suggestion_result(
"What I want is, just from the naked eye, I think there are only 5 colors on this picture",
NakedEye::default(),
"What I want is, just with the naked eye, I think there are only 5 colors on this picture",
);
}
#[test]
fn invisibility_from_the_naked_eye() {
assert_suggestion_result(
"Considering the real security implications of true invisibility from the naked eye",
NakedEye::default(),
"Considering the real security implications of true invisibility to the naked eye",
);
}
}