mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:15:12 +00:00
parent
a95deec00f
commit
424b720c19
62 changed files with 1799 additions and 3890 deletions
|
@ -1,15 +1,14 @@
|
|||
use ruff_python_ast::{AnyNodeRef, ExprFString, StringLike};
|
||||
use ruff_text_size::TextSlice;
|
||||
|
||||
use crate::expression::parentheses::{
|
||||
in_parentheses_only_group, NeedsParentheses, OptionalParentheses,
|
||||
};
|
||||
use crate::other::f_string::{FStringLayout, FormatFString};
|
||||
use crate::other::f_string::FStringLayout;
|
||||
use crate::prelude::*;
|
||||
use crate::string::implicit::{
|
||||
FormatImplicitConcatenatedString, FormatImplicitConcatenatedStringFlat,
|
||||
};
|
||||
use crate::string::{Quoting, StringLikeExtensions};
|
||||
use crate::string::StringLikeExtensions;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatExprFString;
|
||||
|
@ -23,7 +22,7 @@ impl FormatNodeRule<ExprFString> for FormatExprFString {
|
|||
// [`ruff_python_ast::FStringValue::single`] constructor.
|
||||
let f_string = f_string_part.as_f_string().unwrap();
|
||||
|
||||
FormatFString::new(f_string, f_string_quoting(item, f.context().source())).fmt(f)
|
||||
f_string.format().fmt(f)
|
||||
} else {
|
||||
// Always join fstrings that aren't parenthesized and thus, are always on a single line.
|
||||
if !f.context().node_level().is_parenthesized() {
|
||||
|
@ -58,28 +57,3 @@ impl NeedsParentheses for ExprFString {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn f_string_quoting(f_string: &ExprFString, source: &str) -> Quoting {
|
||||
let unprefixed = source
|
||||
.slice(f_string)
|
||||
.trim_start_matches(|c| c != '"' && c != '\'');
|
||||
let triple_quoted = unprefixed.starts_with(r#"""""#) || unprefixed.starts_with(r"'''");
|
||||
|
||||
if f_string
|
||||
.value
|
||||
.elements()
|
||||
.filter_map(|element| element.as_expression())
|
||||
.any(|expression| {
|
||||
let string_content = source.slice(expression);
|
||||
if triple_quoted {
|
||||
string_content.contains(r#"""""#) || string_content.contains("'''")
|
||||
} else {
|
||||
string_content.contains(['"', '\''])
|
||||
}
|
||||
})
|
||||
{
|
||||
Quoting::Preserve
|
||||
} else {
|
||||
Quoting::CanChange
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use crate::expression::parentheses::{
|
|||
};
|
||||
use crate::expression::CallChainLayout;
|
||||
use crate::prelude::*;
|
||||
use crate::preview::is_empty_parameters_no_unnecessary_parentheses_around_return_value_enabled;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatExprSubscript {
|
||||
|
@ -108,13 +107,14 @@ impl NeedsParentheses for ExprSubscript {
|
|||
if function.returns.as_deref().is_some_and(|returns| {
|
||||
AnyNodeRef::ptr_eq(returns.into(), self.into())
|
||||
}) {
|
||||
if is_empty_parameters_no_unnecessary_parentheses_around_return_value_enabled(context) &&
|
||||
function.parameters.is_empty() && !context.comments().has(&*function.parameters) {
|
||||
if function.parameters.is_empty()
|
||||
&& !context.comments().has(&*function.parameters)
|
||||
{
|
||||
// Apply the `optional_parentheses` layout when the subscript
|
||||
// is in a return type position of a function without parameters.
|
||||
// This ensures the subscript is parenthesized if it has a very
|
||||
// long name that goes over the line length limit.
|
||||
return OptionalParentheses::Multiline
|
||||
return OptionalParentheses::Multiline;
|
||||
}
|
||||
|
||||
// Don't use the best fitting layout for return type annotation because it results in the
|
||||
|
|
|
@ -19,10 +19,7 @@ use crate::expression::parentheses::{
|
|||
OptionalParentheses, Parentheses, Parenthesize,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use crate::preview::{
|
||||
is_empty_parameters_no_unnecessary_parentheses_around_return_value_enabled,
|
||||
is_f_string_formatting_enabled, is_hug_parens_with_braces_and_square_brackets_enabled,
|
||||
};
|
||||
use crate::preview::is_hug_parens_with_braces_and_square_brackets_enabled;
|
||||
|
||||
mod binary_like;
|
||||
pub(crate) mod expr_attribute;
|
||||
|
@ -388,18 +385,12 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
|
|||
// is parenthesized. Unless, it's the `Parenthesize::IfBreaksParenthesizedNested` layout
|
||||
// where parenthesizing nested `maybe_parenthesized_expression` is explicitly desired.
|
||||
_ if f.context().node_level().is_parenthesized() => {
|
||||
if !is_empty_parameters_no_unnecessary_parentheses_around_return_value_enabled(
|
||||
f.context(),
|
||||
) {
|
||||
OptionalParentheses::Never
|
||||
} else if matches!(parenthesize, Parenthesize::IfBreaksParenthesizedNested) {
|
||||
return parenthesize_if_expands(
|
||||
&expression.format().with_options(Parentheses::Never),
|
||||
)
|
||||
.with_indent(!is_expression_huggable(expression, f.context()))
|
||||
.fmt(f);
|
||||
return if matches!(parenthesize, Parenthesize::IfBreaksParenthesizedNested) {
|
||||
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never))
|
||||
.with_indent(!is_expression_huggable(expression, f.context()))
|
||||
.fmt(f)
|
||||
} else {
|
||||
return expression.format().with_options(Parentheses::Never).fmt(f);
|
||||
expression.format().with_options(Parentheses::Never).fmt(f)
|
||||
}
|
||||
}
|
||||
needs_parentheses => needs_parentheses,
|
||||
|
@ -409,13 +400,12 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
|
|||
|
||||
match needs_parentheses {
|
||||
OptionalParentheses::Multiline => match parenthesize {
|
||||
Parenthesize::IfBreaksParenthesized | Parenthesize::IfBreaksParenthesizedNested if !is_empty_parameters_no_unnecessary_parentheses_around_return_value_enabled(f.context()) => {
|
||||
parenthesize_if_expands(&unparenthesized).fmt(f)
|
||||
}
|
||||
|
||||
Parenthesize::IfRequired => unparenthesized.fmt(f),
|
||||
|
||||
Parenthesize::Optional | Parenthesize::IfBreaks | Parenthesize::IfBreaksParenthesized | Parenthesize::IfBreaksParenthesizedNested => {
|
||||
Parenthesize::Optional
|
||||
| Parenthesize::IfBreaks
|
||||
| Parenthesize::IfBreaksParenthesized
|
||||
| Parenthesize::IfBreaksParenthesizedNested => {
|
||||
if can_omit_optional_parentheses(expression, f.context()) {
|
||||
optional_parentheses(&unparenthesized).fmt(f)
|
||||
} else {
|
||||
|
@ -424,9 +414,6 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
|
|||
}
|
||||
},
|
||||
OptionalParentheses::BestFit => match parenthesize {
|
||||
Parenthesize::IfBreaksParenthesized | Parenthesize::IfBreaksParenthesizedNested if !is_empty_parameters_no_unnecessary_parentheses_around_return_value_enabled(f.context()) =>
|
||||
parenthesize_if_expands(&unparenthesized).fmt(f),
|
||||
|
||||
Parenthesize::IfBreaksParenthesized | Parenthesize::IfBreaksParenthesizedNested => {
|
||||
// Can-omit layout is relevant for `"abcd".call`. We don't want to add unnecessary
|
||||
// parentheses in this case.
|
||||
|
@ -454,15 +441,11 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
|
|||
}
|
||||
},
|
||||
OptionalParentheses::Never => match parenthesize {
|
||||
Parenthesize::IfBreaksParenthesized | Parenthesize::IfBreaksParenthesizedNested if !is_empty_parameters_no_unnecessary_parentheses_around_return_value_enabled(f.context()) => {
|
||||
parenthesize_if_expands(&unparenthesized)
|
||||
.with_indent(!is_expression_huggable(expression, f.context()))
|
||||
.fmt(f)
|
||||
}
|
||||
|
||||
Parenthesize::Optional | Parenthesize::IfBreaks | Parenthesize::IfRequired | Parenthesize::IfBreaksParenthesized | Parenthesize::IfBreaksParenthesizedNested => {
|
||||
unparenthesized.fmt(f)
|
||||
}
|
||||
Parenthesize::Optional
|
||||
| Parenthesize::IfBreaks
|
||||
| Parenthesize::IfRequired
|
||||
| Parenthesize::IfBreaksParenthesized
|
||||
| Parenthesize::IfBreaksParenthesizedNested => unparenthesized.fmt(f),
|
||||
},
|
||||
|
||||
OptionalParentheses::Always => {
|
||||
|
@ -766,32 +749,6 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
|
|||
return;
|
||||
}
|
||||
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. })
|
||||
if value.is_implicit_concatenated() =>
|
||||
{
|
||||
if !is_f_string_formatting_enabled(self.context) {
|
||||
self.update_max_precedence(OperatorPrecedence::String);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. })
|
||||
if value.is_implicit_concatenated() =>
|
||||
{
|
||||
if !is_f_string_formatting_enabled(self.context) {
|
||||
self.update_max_precedence(OperatorPrecedence::String);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
Expr::FString(ast::ExprFString { value, .. }) if value.is_implicit_concatenated() => {
|
||||
if !is_f_string_formatting_enabled(self.context) {
|
||||
self.update_max_precedence(OperatorPrecedence::String);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Non terminal nodes that don't have a termination token.
|
||||
Expr::Named(_) | Expr::Generator(_) | Expr::Tuple(_) => {}
|
||||
|
||||
|
@ -1193,8 +1150,6 @@ enum OperatorPrecedence {
|
|||
BitwiseXor,
|
||||
BitwiseOr,
|
||||
Comparator,
|
||||
// Implicit string concatenation
|
||||
String,
|
||||
BooleanOperation,
|
||||
Conditional,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue