1
- use crate :: expression:: parentheses:: {
2
- default_expression_needs_parentheses, NeedsParentheses , Parentheses , Parenthesize ,
3
- } ;
4
- use crate :: expression:: string:: { FormatString , StringLayout } ;
1
+ use ruff_text_size:: { TextLen , TextRange } ;
2
+ use rustpython_parser:: ast:: { Constant , ExprConstant , Ranged } ;
3
+
4
+ use ruff_formatter:: write;
5
+ use ruff_python_ast:: node:: AnyNodeRef ;
6
+ use ruff_python_ast:: str:: is_implicit_concatenation;
7
+
8
+ use crate :: expression:: parentheses:: { NeedsParentheses , OptionalParentheses } ;
9
+ use crate :: expression:: string:: { FormatString , StringPrefix , StringQuotes } ;
5
10
use crate :: prelude:: * ;
6
11
use crate :: { not_yet_implemented_custom_text, verbatim_text, FormatNodeRule } ;
7
- use ruff_formatter:: { write, FormatRuleWithOptions } ;
8
- use rustpython_parser:: ast:: { Constant , ExprConstant } ;
9
12
10
13
#[ derive( Default ) ]
11
- pub struct FormatExprConstant {
12
- string_layout : StringLayout ,
13
- }
14
-
15
- impl FormatRuleWithOptions < ExprConstant , PyFormatContext < ' _ > > for FormatExprConstant {
16
- type Options = StringLayout ;
17
-
18
- fn with_options ( mut self , options : Self :: Options ) -> Self {
19
- self . string_layout = options;
20
- self
21
- }
22
- }
14
+ pub struct FormatExprConstant ;
23
15
24
16
impl FormatNodeRule < ExprConstant > for FormatExprConstant {
25
17
fn fmt_fields ( & self , item : & ExprConstant , f : & mut PyFormatter ) -> FormatResult < ( ) > {
@@ -39,7 +31,7 @@ impl FormatNodeRule<ExprConstant> for FormatExprConstant {
39
31
Constant :: Int ( _) | Constant :: Float ( _) | Constant :: Complex { .. } => {
40
32
write ! ( f, [ verbatim_text( item) ] )
41
33
}
42
- Constant :: Str ( _) => FormatString :: new ( item, self . string_layout ) . fmt ( f) ,
34
+ Constant :: Str ( _) => FormatString :: new ( item) . fmt ( f) ,
43
35
Constant :: Bytes ( _) => {
44
36
not_yet_implemented_custom_text ( r#"b"NOT_YET_IMPLEMENTED_BYTE_STRING""# ) . fmt ( f)
45
37
}
@@ -61,20 +53,32 @@ impl FormatNodeRule<ExprConstant> for FormatExprConstant {
61
53
impl NeedsParentheses for ExprConstant {
62
54
fn needs_parentheses (
63
55
& self ,
64
- parenthesize : Parenthesize ,
56
+ _parent : AnyNodeRef ,
65
57
context : & PyFormatContext ,
66
- ) -> Parentheses {
67
- match default_expression_needs_parentheses ( self . into ( ) , parenthesize, context) {
68
- Parentheses :: Optional if self . value . is_str ( ) && parenthesize. is_if_breaks ( ) => {
69
- // Custom handling that only adds parentheses for implicit concatenated strings.
70
- if parenthesize. is_if_breaks ( ) {
71
- Parentheses :: Custom
72
- } else {
73
- Parentheses :: Optional
74
- }
58
+ ) -> OptionalParentheses {
59
+ if self . value . is_str ( ) {
60
+ let contents = context. locator ( ) . slice ( self . range ( ) ) ;
61
+ // Don't wrap triple quoted strings
62
+ if is_multiline_string ( self , context. source ( ) ) || !is_implicit_concatenation ( contents) {
63
+ OptionalParentheses :: Never
64
+ } else {
65
+ OptionalParentheses :: Multiline
75
66
}
76
- Parentheses :: Optional => Parentheses :: Never ,
77
- parentheses => parentheses ,
67
+ } else {
68
+ OptionalParentheses :: Never
78
69
}
79
70
}
80
71
}
72
+
73
+ pub ( super ) fn is_multiline_string ( constant : & ExprConstant , source : & str ) -> bool {
74
+ if constant. value . is_str ( ) {
75
+ let contents = & source[ constant. range ( ) ] ;
76
+ let prefix = StringPrefix :: parse ( contents) ;
77
+ let quotes =
78
+ StringQuotes :: parse ( & contents[ TextRange :: new ( prefix. text_len ( ) , contents. text_len ( ) ) ] ) ;
79
+
80
+ quotes. map_or ( false , StringQuotes :: is_triple) && contents. contains ( [ '\n' , '\r' ] )
81
+ } else {
82
+ false
83
+ }
84
+ }
0 commit comments