11use std:: io:: { self , BufWriter , Write } ;
22
33use anyhow:: Result ;
4- use serde:: Serialize ;
4+ use serde:: ser:: SerializeSeq ;
5+ use serde:: { Serialize , Serializer } ;
6+ use strum:: IntoEnumIterator ;
57
68use ruff:: registry:: { Linter , Rule , RuleNamespace } ;
79use ruff_diagnostics:: AutofixKind ;
@@ -11,72 +13,106 @@ use crate::args::HelpFormat;
1113#[ derive( Serialize ) ]
1214struct Explanation < ' a > {
1315 name : & ' a str ,
14- code : & ' a str ,
16+ code : String ,
1517 linter : & ' a str ,
1618 summary : & ' a str ,
1719 message_formats : & ' a [ & ' a str ] ,
18- autofix : & ' a str ,
20+ autofix : String ,
1921 explanation : Option < & ' a str > ,
22+ nursery : bool ,
2023}
2124
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+ }
2742
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' ) ;
3348
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' ) ;
3753
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+ }
4460
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
4864still under development. As such, it must be enabled by explicitly selecting
4965{}."# ,
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+ }
5571
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) ) ?;
6590 }
6691 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) ) ?;
7693 }
7794 } ;
95+ Ok ( ( ) )
96+ }
7897
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+ }
81117 Ok ( ( ) )
82118}
0 commit comments