1
1
//! Checks that a list of items is in alphabetical order
2
2
//!
3
- //! To use, use the following annotation in the code:
3
+ //! Use the following marker in the code:
4
4
//! ```rust
5
5
//! // tidy-alphabetical-start
6
6
//! fn aaa() {}
10
10
//! ```
11
11
//!
12
12
//! The following lines are ignored:
13
+ //! - Empty lines
13
14
//! - Lines that are indented with more or less spaces than the first line
14
- //! - Lines starting with `//`, `#[`, `)`, `]`, `}` if the comment has the same indentation as
15
- //! the first line
15
+ //! - Lines starting with `//`, `#` (except those starting with `#!`), `)`, `]`, `}` if the comment
16
+ //! has the same indentation as the first line
17
+ //! - Lines starting with a closing delimiter (`)`, `[`, `}`) are ignored.
16
18
//!
17
- //! If a line ends with an opening bracket, the line is ignored and the next line will have
18
- //! its extra indentation ignored .
19
+ //! If a line ends with an opening delimiter, we effectively join the following line to it before
20
+ //! checking it. E.g. `foo(\nbar)` is treated like `foo(bar)` .
19
21
20
- use std:: { fmt:: Display , path:: Path } ;
22
+ use std:: fmt:: Display ;
23
+ use std:: path:: Path ;
21
24
22
25
use crate :: walk:: { filter_dirs, walk} ;
23
26
27
+ #[ cfg( test) ]
28
+ mod tests;
29
+
24
30
fn indentation ( line : & str ) -> usize {
25
31
line. find ( |c| c != ' ' ) . unwrap_or ( 0 )
26
32
}
@@ -29,28 +35,36 @@ fn is_close_bracket(c: char) -> bool {
29
35
matches ! ( c, ')' | ']' | '}' )
30
36
}
31
37
32
- // Don't let tidy check this here :D
33
- const START_COMMENT : & str = concat ! ( "tidy-alphabetical" , "-start" ) ;
34
- const END_COMMENT : & str = "tidy-alphabetical-end" ;
38
+ const START_MARKER : & str = "tidy-alphabetical-start" ;
39
+ const END_MARKER : & str = "tidy-alphabetical-end" ;
35
40
36
41
fn check_section < ' a > (
37
42
file : impl Display ,
38
43
lines : impl Iterator < Item = ( usize , & ' a str ) > ,
44
+ err : & mut dyn FnMut ( & str ) -> std:: io:: Result < ( ) > ,
39
45
bad : & mut bool ,
40
46
) {
41
- let content_lines = lines. take_while ( |( _, line) | !line. contains ( END_COMMENT ) ) ;
42
-
43
47
let mut prev_line = String :: new ( ) ;
44
48
let mut first_indent = None ;
45
49
let mut in_split_line = None ;
46
50
47
- for ( line_idx, line) in content_lines {
48
- if line. contains ( START_COMMENT ) {
49
- tidy_error ! (
51
+ for ( idx, line) in lines {
52
+ if line. is_empty ( ) {
53
+ continue ;
54
+ }
55
+
56
+ if line. contains ( START_MARKER ) {
57
+ tidy_error_ext ! (
58
+ err,
50
59
bad,
51
- "{file}:{} found `{START_COMMENT}` expecting `{END_COMMENT}`" ,
52
- line_idx
53
- )
60
+ "{file}:{} found `{START_MARKER}` expecting `{END_MARKER}`" ,
61
+ idx + 1
62
+ ) ;
63
+ return ;
64
+ }
65
+
66
+ if line. contains ( END_MARKER ) {
67
+ return ;
54
68
}
55
69
56
70
let indent = first_indent. unwrap_or_else ( || {
@@ -60,6 +74,7 @@ fn check_section<'a>(
60
74
} ) ;
61
75
62
76
let line = if let Some ( prev_split_line) = in_split_line {
77
+ // Join the split lines.
63
78
in_split_line = None ;
64
79
format ! ( "{prev_split_line}{}" , line. trim_start( ) )
65
80
} else {
@@ -73,7 +88,7 @@ fn check_section<'a>(
73
88
let trimmed_line = line. trim_start_matches ( ' ' ) ;
74
89
75
90
if trimmed_line. starts_with ( "//" )
76
- || trimmed_line. starts_with ( "#[" )
91
+ || ( trimmed_line. starts_with ( "#" ) && !trimmed_line . starts_with ( "#!" ) )
77
92
|| trimmed_line. starts_with ( is_close_bracket)
78
93
{
79
94
continue ;
@@ -87,25 +102,44 @@ fn check_section<'a>(
87
102
let prev_line_trimmed_lowercase = prev_line. trim_start_matches ( ' ' ) . to_lowercase ( ) ;
88
103
89
104
if trimmed_line. to_lowercase ( ) < prev_line_trimmed_lowercase {
90
- tidy_error ! ( bad, "{file}:{}: line not in alphabetical order" , line_idx + 1 , ) ;
105
+ tidy_error_ext ! ( err , bad, "{file}:{}: line not in alphabetical order" , idx + 1 ) ;
91
106
}
92
107
93
108
prev_line = line;
94
109
}
110
+
111
+ tidy_error_ext ! ( err, bad, "{file}: reached end of file expecting `{END_MARKER}`" )
95
112
}
96
113
97
- pub fn check ( path : & Path , bad : & mut bool ) {
98
- walk ( path, |path, _is_dir| filter_dirs ( path) , & mut |entry, contents| {
99
- let file = & entry. path ( ) . display ( ) ;
114
+ fn check_lines < ' a > (
115
+ file : & impl Display ,
116
+ mut lines : impl Iterator < Item = ( usize , & ' a str ) > ,
117
+ err : & mut dyn FnMut ( & str ) -> std:: io:: Result < ( ) > ,
118
+ bad : & mut bool ,
119
+ ) {
120
+ while let Some ( ( idx, line) ) = lines. next ( ) {
121
+ if line. contains ( END_MARKER ) {
122
+ tidy_error_ext ! (
123
+ err,
124
+ bad,
125
+ "{file}:{} found `{END_MARKER}` expecting `{START_MARKER}`" ,
126
+ idx + 1
127
+ )
128
+ }
100
129
101
- let mut lines = contents. lines ( ) . enumerate ( ) . peekable ( ) ;
102
- while let Some ( ( _, line) ) = lines. next ( ) {
103
- if line. contains ( START_COMMENT ) {
104
- check_section ( file, & mut lines, bad) ;
105
- if lines. peek ( ) . is_none ( ) {
106
- tidy_error ! ( bad, "{file}: reached end of file expecting `{END_COMMENT}`" )
107
- }
108
- }
130
+ if line. contains ( START_MARKER ) {
131
+ check_section ( file, & mut lines, err, bad) ;
109
132
}
133
+ }
134
+ }
135
+
136
+ pub fn check ( path : & Path , bad : & mut bool ) {
137
+ let skip =
138
+ |path : & _ , _is_dir| filter_dirs ( path) || path. ends_with ( "tidy/src/alphabetical/tests.rs" ) ;
139
+
140
+ walk ( path, skip, & mut |entry, contents| {
141
+ let file = & entry. path ( ) . display ( ) ;
142
+ let lines = contents. lines ( ) . enumerate ( ) ;
143
+ check_lines ( file, lines, & mut crate :: tidy_error, bad)
110
144
} ) ;
111
145
}
0 commit comments