mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-14 22:35:11 +00:00
Handle right parens in join comma builder (#5711)
This commit is contained in:
parent
f0aa6bd4d3
commit
653429bef9
11 changed files with 159 additions and 136 deletions
|
@ -5,10 +5,12 @@ use crate::expression::parentheses::{
|
|||
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
|
||||
Parenthesize,
|
||||
};
|
||||
use crate::trivia::{SimpleTokenizer, TokenKind};
|
||||
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
||||
use ruff_formatter::prelude::{format_with, group, text};
|
||||
use ruff_formatter::{write, Buffer, FormatResult};
|
||||
use rustpython_parser::ast::ExprCall;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use rustpython_parser::ast::{Expr, ExprCall, Ranged};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatExprCall;
|
||||
|
@ -43,15 +45,25 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
|
|||
);
|
||||
}
|
||||
|
||||
let all_args = format_with(|f| {
|
||||
f.join_comma_separated()
|
||||
.entries(
|
||||
// We have the parentheses from the call so the arguments never need any
|
||||
args.iter()
|
||||
.map(|arg| (arg, arg.format().with_options(Parenthesize::Never))),
|
||||
)
|
||||
.nodes(keywords.iter())
|
||||
.finish()
|
||||
let all_args = format_with(|f: &mut PyFormatter| {
|
||||
let source = f.context().source();
|
||||
let mut joiner = f.join_comma_separated(item.end());
|
||||
match args.as_slice() {
|
||||
[argument] if keywords.is_empty() => {
|
||||
let parentheses =
|
||||
if is_single_argument_parenthesized(argument, item.end(), source) {
|
||||
Parenthesize::Always
|
||||
} else {
|
||||
Parenthesize::Never
|
||||
};
|
||||
joiner.entry(argument, &argument.format().with_options(parentheses));
|
||||
}
|
||||
arguments => {
|
||||
joiner.nodes(arguments).nodes(keywords.iter());
|
||||
}
|
||||
}
|
||||
|
||||
joiner.finish()
|
||||
});
|
||||
|
||||
write!(
|
||||
|
@ -97,3 +109,28 @@ impl NeedsParentheses for ExprCall {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_single_argument_parenthesized(argument: &Expr, call_end: TextSize, source: &str) -> bool {
|
||||
let mut has_seen_r_paren = false;
|
||||
|
||||
for token in
|
||||
SimpleTokenizer::new(source, TextRange::new(argument.end(), call_end)).skip_trivia()
|
||||
{
|
||||
match token.kind() {
|
||||
TokenKind::RParen => {
|
||||
if has_seen_r_paren {
|
||||
return true;
|
||||
}
|
||||
has_seen_r_paren = true;
|
||||
}
|
||||
// Skip over any trailing comma
|
||||
TokenKind::Comma => continue,
|
||||
_ => {
|
||||
// Passed the arguments
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ impl FormatNodeRule<ExprDict> for FormatExprDict {
|
|||
}
|
||||
|
||||
let format_pairs = format_with(|f| {
|
||||
let mut joiner = f.join_comma_separated();
|
||||
let mut joiner = f.join_comma_separated(item.end());
|
||||
|
||||
for (key, value) in keys.iter().zip(values) {
|
||||
let key_value_pair = KeyValuePair { key, value };
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::expression::parentheses::{
|
|||
use crate::prelude::*;
|
||||
use crate::FormatNodeRule;
|
||||
use ruff_formatter::{format_args, write};
|
||||
use rustpython_parser::ast::ExprList;
|
||||
use rustpython_parser::ast::{ExprList, Ranged};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatExprList;
|
||||
|
@ -53,7 +53,11 @@ impl FormatNodeRule<ExprList> for FormatExprList {
|
|||
"A non-empty expression list has dangling comments"
|
||||
);
|
||||
|
||||
let items = format_with(|f| f.join_comma_separated().nodes(elts.iter()).finish());
|
||||
let items = format_with(|f| {
|
||||
f.join_comma_separated(item.end())
|
||||
.nodes(elts.iter())
|
||||
.finish()
|
||||
});
|
||||
|
||||
parenthesized("[", &items, "]").fmt(f)
|
||||
}
|
||||
|
|
|
@ -108,14 +108,14 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
|||
//
|
||||
// Unlike other expression parentheses, tuple parentheses are part of the range of the
|
||||
// tuple itself.
|
||||
elts if is_parenthesized(*range, elts, f.context().source())
|
||||
_ if is_parenthesized(*range, elts, f.context().source())
|
||||
&& self.parentheses != TupleParentheses::StripInsideForLoop =>
|
||||
{
|
||||
parenthesized("(", &ExprSequence::new(elts), ")").fmt(f)
|
||||
parenthesized("(", &ExprSequence::new(item), ")").fmt(f)
|
||||
}
|
||||
elts => match self.parentheses {
|
||||
TupleParentheses::Subscript => group(&ExprSequence::new(elts)).fmt(f),
|
||||
_ => parenthesize_if_expands(&ExprSequence::new(elts)).fmt(f),
|
||||
_ => match self.parentheses {
|
||||
TupleParentheses::Subscript => group(&ExprSequence::new(item)).fmt(f),
|
||||
_ => parenthesize_if_expands(&ExprSequence::new(item)).fmt(f),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -128,18 +128,20 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
|||
|
||||
#[derive(Debug)]
|
||||
struct ExprSequence<'a> {
|
||||
elts: &'a [Expr],
|
||||
tuple: &'a ExprTuple,
|
||||
}
|
||||
|
||||
impl<'a> ExprSequence<'a> {
|
||||
const fn new(elts: &'a [Expr]) -> Self {
|
||||
Self { elts }
|
||||
const fn new(expr: &'a ExprTuple) -> Self {
|
||||
Self { tuple: expr }
|
||||
}
|
||||
}
|
||||
|
||||
impl Format<PyFormatContext<'_>> for ExprSequence<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||
f.join_comma_separated().nodes(self.elts.iter()).finish()
|
||||
f.join_comma_separated(self.tuple.end())
|
||||
.nodes(&self.tuple.elts)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue