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_idx in sentence.iter_space_indices() {
14 if space_idx == 0 {
15 continue;
16 }
17
18 let space = &sentence[space_idx];
19
20 let TokenKind::Space(count) = space.kind else {
21 panic!("The space iterator should only return spaces.")
22 };
23
24 if count > 1 {
25 output.push(Lint {
26 span: space.span,
27 lint_kind: LintKind::Formatting,
28 suggestions: vec![Suggestion::ReplaceWith(vec![' '])],
29 message: format!(
30 "There are {count} spaces where there should be only one."
31 ),
32 priority: 15,
33 })
34 }
35 }
36
37 if matches!(
38 sentence,
39 [
40 ..,
41 Token {
42 kind: TokenKind::Word(_),
43 ..
44 },
45 Token {
46 kind: TokenKind::Space(_),
47 ..
48 },
49 Token {
50 kind: TokenKind::Punctuation(_),
51 ..
52 }
53 ]
54 ) {
55 output.push(Lint {
56 span: sentence[sentence.len() - 2..sentence.len() - 1]
57 .span()
58 .unwrap(),
59 lint_kind: LintKind::Formatting,
60 suggestions: vec![Suggestion::Remove],
61 message: "Unnecessary space at the end of the sentence.".to_string(),
62 priority: 63,
63 })
64 }
65 }
66
67 output
68 }
69
70 fn description(&self) -> &'static str {
71 "Words should be separated by at most one space."
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::Spaces;
78 use crate::linting::tests::{assert_lint_count, assert_no_lints};
79
80 #[test]
81 fn detects_space_before_period() {
82 let source = "There is a space at the end of this sentence .";
83
84 assert_lint_count(source, Spaces, 1)
85 }
86
87 #[test]
88 fn allows_period_without_space() {
89 let source = "There isn't a space at the end of this sentence.";
90
91 assert_lint_count(source, Spaces, 0)
92 }
93
94 #[test]
95 fn ignores_french_spacing() {
96 assert_no_lints(
97 "This is a short sentence. This is another short sentence.",
98 Spaces,
99 );
100 }
101}