1
1
use std:: io:: { self , BufWriter , Write } ;
2
2
3
3
use anyhow:: Result ;
4
- use serde:: Serialize ;
4
+ use serde:: ser:: SerializeSeq ;
5
+ use serde:: { Serialize , Serializer } ;
6
+ use strum:: IntoEnumIterator ;
5
7
6
8
use ruff:: registry:: { Linter , Rule , RuleNamespace } ;
7
9
use ruff_diagnostics:: AutofixKind ;
@@ -11,72 +13,106 @@ use crate::args::HelpFormat;
11
13
#[ derive( Serialize ) ]
12
14
struct Explanation < ' a > {
13
15
name : & ' a str ,
14
- code : & ' a str ,
16
+ code : String ,
15
17
linter : & ' a str ,
16
18
summary : & ' a str ,
17
19
message_formats : & ' a [ & ' a str ] ,
18
- autofix : & ' a str ,
20
+ autofix : String ,
19
21
explanation : Option < & ' a str > ,
22
+ nursery : bool ,
20
23
}
21
24
22
- /// Explain a `Rule` to the user.
23
- pub ( crate ) fn rule ( rule : Rule , format : HelpFormat ) -> Result < ( ) > {
24
- let ( linter, _) = Linter :: parse_code ( & rule. noqa_code ( ) . to_string ( ) ) . unwrap ( ) ;
25
- let mut stdout = BufWriter :: new ( io:: stdout ( ) . lock ( ) ) ;
26
- let mut output = String :: new ( ) ;
25
+ impl < ' a > Explanation < ' a > {
26
+ fn from_rule ( rule : & ' a Rule ) -> Self {
27
+ let code = rule. noqa_code ( ) . to_string ( ) ;
28
+ let ( linter, _) = Linter :: parse_code ( & code) . unwrap ( ) ;
29
+ let autofix = rule. autofixable ( ) . to_string ( ) ;
30
+ Self {
31
+ name : rule. as_ref ( ) ,
32
+ code,
33
+ linter : linter. name ( ) ,
34
+ summary : rule. message_formats ( ) [ 0 ] ,
35
+ message_formats : rule. message_formats ( ) ,
36
+ autofix,
37
+ explanation : rule. explanation ( ) ,
38
+ nursery : rule. is_nursery ( ) ,
39
+ }
40
+ }
41
+ }
27
42
28
- match format {
29
- HelpFormat :: Text => {
30
- output. push_str ( & format ! ( "# {} ({})" , rule. as_ref( ) , rule. noqa_code( ) ) ) ;
31
- output. push ( '\n' ) ;
32
- output. push ( '\n' ) ;
43
+ fn format_rule_text ( rule : Rule ) -> String {
44
+ let mut output = String :: new ( ) ;
45
+ output. push_str ( & format ! ( "# {} ({})" , rule. as_ref( ) , rule. noqa_code( ) ) ) ;
46
+ output. push ( '\n' ) ;
47
+ output. push ( '\n' ) ;
33
48
34
- output. push_str ( & format ! ( "Derived from the **{}** linter." , linter. name( ) ) ) ;
35
- output. push ( '\n' ) ;
36
- output. push ( '\n' ) ;
49
+ let ( linter, _) = Linter :: parse_code ( & rule. noqa_code ( ) . to_string ( ) ) . unwrap ( ) ;
50
+ output. push_str ( & format ! ( "Derived from the **{}** linter." , linter. name( ) ) ) ;
51
+ output. push ( '\n' ) ;
52
+ output. push ( '\n' ) ;
37
53
38
- let autofix = rule. autofixable ( ) ;
39
- if matches ! ( autofix, AutofixKind :: Always | AutofixKind :: Sometimes ) {
40
- output. push_str ( & autofix. to_string ( ) ) ;
41
- output. push ( '\n' ) ;
42
- output. push ( '\n' ) ;
43
- }
54
+ let autofix = rule. autofixable ( ) ;
55
+ if matches ! ( autofix, AutofixKind :: Always | AutofixKind :: Sometimes ) {
56
+ output. push_str ( & autofix. to_string ( ) ) ;
57
+ output. push ( '\n' ) ;
58
+ output. push ( '\n' ) ;
59
+ }
44
60
45
- if rule. is_nursery ( ) {
46
- output. push_str ( & format ! (
47
- r#"This rule is part of the **nursery**, a collection of newer lints that are
61
+ if rule. is_nursery ( ) {
62
+ output. push_str ( & format ! (
63
+ r#"This rule is part of the **nursery**, a collection of newer lints that are
48
64
still under development. As such, it must be enabled by explicitly selecting
49
65
{}."# ,
50
- rule. noqa_code( )
51
- ) ) ;
52
- output. push ( '\n' ) ;
53
- output. push ( '\n' ) ;
54
- }
66
+ rule. noqa_code( )
67
+ ) ) ;
68
+ output. push ( '\n' ) ;
69
+ output. push ( '\n' ) ;
70
+ }
55
71
56
- if let Some ( explanation) = rule. explanation ( ) {
57
- output. push_str ( explanation. trim ( ) ) ;
58
- } else {
59
- output. push_str ( "Message formats:" ) ;
60
- for format in rule. message_formats ( ) {
61
- output. push ( '\n' ) ;
62
- output. push_str ( & format ! ( "* {format}" ) ) ;
63
- }
64
- }
72
+ if let Some ( explanation) = rule. explanation ( ) {
73
+ output. push_str ( explanation. trim ( ) ) ;
74
+ } else {
75
+ output. push_str ( "Message formats:" ) ;
76
+ for format in rule. message_formats ( ) {
77
+ output. push ( '\n' ) ;
78
+ output. push_str ( & format ! ( "* {format}" ) ) ;
79
+ }
80
+ }
81
+ output
82
+ }
83
+
84
+ /// Explain a `Rule` to the user.
85
+ pub ( crate ) fn rule ( rule : Rule , format : HelpFormat ) -> Result < ( ) > {
86
+ let mut stdout = BufWriter :: new ( io:: stdout ( ) . lock ( ) ) ;
87
+ match format {
88
+ HelpFormat :: Text => {
89
+ writeln ! ( stdout, "{}" , format_rule_text( rule) ) ?;
65
90
}
66
91
HelpFormat :: Json => {
67
- output. push_str ( & serde_json:: to_string_pretty ( & Explanation {
68
- name : rule. as_ref ( ) ,
69
- code : & rule. noqa_code ( ) . to_string ( ) ,
70
- linter : linter. name ( ) ,
71
- summary : rule. message_formats ( ) [ 0 ] ,
72
- message_formats : rule. message_formats ( ) ,
73
- autofix : & rule. autofixable ( ) . to_string ( ) ,
74
- explanation : rule. explanation ( ) ,
75
- } ) ?) ;
92
+ serde_json:: to_writer_pretty ( stdout, & Explanation :: from_rule ( & rule) ) ?;
76
93
}
77
94
} ;
95
+ Ok ( ( ) )
96
+ }
78
97
79
- writeln ! ( stdout, "{output}" ) ?;
80
-
98
+ /// Explain all rules to the user.
99
+ pub ( crate ) fn rules ( format : HelpFormat ) -> Result < ( ) > {
100
+ let mut stdout = BufWriter :: new ( io:: stdout ( ) . lock ( ) ) ;
101
+ match format {
102
+ HelpFormat :: Text => {
103
+ for rule in Rule :: iter ( ) {
104
+ writeln ! ( stdout, "{}" , format_rule_text( rule) ) ?;
105
+ writeln ! ( stdout) ?;
106
+ }
107
+ }
108
+ HelpFormat :: Json => {
109
+ let mut serializer = serde_json:: Serializer :: pretty ( stdout) ;
110
+ let mut seq = serializer. serialize_seq ( None ) ?;
111
+ for rule in Rule :: iter ( ) {
112
+ seq. serialize_element ( & Explanation :: from_rule ( & rule) ) ?;
113
+ }
114
+ seq. end ( ) ?;
115
+ }
116
+ }
81
117
Ok ( ( ) )
82
118
}
0 commit comments