harper_core/linting/
spaces.rs1use super::{Lint, LintKind, Linter, Suggestion};
2use crate::TokenStringExt;
3use crate::{Document, Token, TokenKind};
4
5#[derive(Debug, Default)]
6pub struct Spaces;
7
8impl Linter for Spaces {
9 fn lint(&mut self, document: &Document) -> Vec<Lint> {
10 let mut output = Vec::new();
11
12 for sentence in document.iter_sentences() {
13 for space in sentence.iter_spaces() {
14 let TokenKind::Space(count) = space.kind else {
15 panic!("The space iterator should only return spaces.")
16 };
17
18 if count > 1 {
19 output.push(Lint {
20 span: space.span,
21 lint_kind: LintKind::Formatting,
22 suggestions: vec![Suggestion::ReplaceWith(vec![' '])],
23 message: format!(
24 "There are {count} spaces where there should be only one."
25 ),
26 priority: 15,
27 })
28 }
29 }
30
31 if matches!(
32 sentence,
33 [
34 ..,
35 Token {
36 kind: TokenKind::Word(_),
37 ..
38 },
39 Token {
40 kind: TokenKind::Space(_),
41 ..
42 },
43 Token {
44 kind: TokenKind::Punctuation(_),
45 ..
46 }
47 ]
48 ) {
49 output.push(Lint {
50 span: sentence[sentence.len() - 2..sentence.len() - 1]
51 .span()
52 .unwrap(),
53 lint_kind: LintKind::Formatting,
54 suggestions: vec![Suggestion::Remove],
55 message: "Unnecessary space at the end of the sentence.".to_string(),
56 priority: 63,
57 })
58 }
59 }
60
61 output
62 }
63
64 fn description(&self) -> &'static str {
65 "Words should be separated by at most one space."
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::Spaces;
72 use crate::linting::tests::assert_lint_count;
73
74 #[test]
75 fn detects_space_before_period() {
76 let source = "There is a space at the end of this sentence .";
77
78 assert_lint_count(source, Spaces, 1)
79 }
80
81 #[test]
82 fn allows_period_without_space() {
83 let source = "There isn't a space at the end of this sentence.";
84
85 assert_lint_count(source, Spaces, 0)
86 }
87}