english_lint/
lib.rs

1//! Find common stylistic problems in english texts. Works well for technical or
2//! scientific documents. Based on [write-good][npm-write-good] and
3//! [this article][matt].
4//!
5//! [npm-write-good]: https://github.com/btford/write-good
6//! [matt]: http://matt.might.net/articles/shell-scripts-for-passive-voice-weasel-words-duplicates/
7#![deny(missing_docs, dead_code)]
8
9extern crate aho_corasick;
10extern crate regex;
11#[macro_use] extern crate lazy_static;
12
13mod range_map;
14
15mod data;
16mod hint;
17mod matcher;
18mod pattern_groups;
19
20use aho_corasick::AcAutomaton;
21
22pub use hint::Hint;
23
24/// Lint a string of english text
25///
26/// Given some english text, this function will try to give suggestions on how
27/// to improve the language.
28///
29/// # Examples
30///
31/// ```
32/// extern crate english_lint;
33///
34/// let text: &str = "This chapter consists of relatively independent tutorials";
35/// let suggestions: Vec<english_lint::Hint> = english_lint::lint(text);
36///
37/// assert_eq!(suggestions, vec![
38///     english_lint::Hint { group: Some("adverbs"),
39///                          value: "relatively".to_owned(),
40///                          line: Some(1), start: 25, end: 35 },
41/// ]);
42/// ```
43pub fn lint(input: &str) -> Vec<Hint> {
44    let mut pattern_groups = pattern_groups::PatternGroups::with_capacity(32_000);
45    pattern_groups.push(data::ADVERBS, "adverbs");
46    pattern_groups.push(data::WEAKENS, "weakens");
47    pattern_groups.push(data::CLICHES, "cliches");
48    pattern_groups.push(data::WORDY, "wordy");
49    pattern_groups.push(data::WEASELS, "weasels");
50
51    let automaton = AcAutomaton::new(pattern_groups.patterns.clone());
52
53    input
54        .lines().enumerate()
55        .flat_map(|(index, line)| {
56            let line_number = index + 1;
57
58            let irregulars = data::PASSIVE.find_iter(line)
59                .map(move |(start, end)| Hint {
60                    group: Some("passive"),
61                    value: line[start..end].to_owned(),
62                    line: Some(line_number.clone()),
63                    start: start,
64                    end: end,
65                 });
66
67            matcher::matcher(&automaton, &pattern_groups, line)
68                .into_iter()
69                .map(move |hint| Hint { line: Some(line_number.clone()), ..hint.clone()})
70                .chain(irregulars)
71        })
72        .collect()
73}