Files
ruff/crates/ruff_python_formatter/src/expression/expr_dict.rs
Charlie Marsh c7703e205d Move empty_parenthesized into the parentheses.rs (#6403)
## Summary

This PR moves `empty_parenthesized` such that it's peer to
`parenthesized`, and changes the API to better match that of
`parenthesized` (takes `&str` rather than `StaticText`, has a
`with_dangling_comments` method, etc.).

It may be intentionally _not_ part of `parentheses.rs`, but to me
they're so similar that it makes more sense for them to be in the same
module, with the same API, etc.
2023-08-08 19:17:17 +00:00

107 lines
2.9 KiB
Rust

use ruff_formatter::{format_args, write};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::Ranged;
use ruff_python_ast::{Expr, ExprDict};
use ruff_text_size::TextRange;
use crate::comments::leading_comments;
use crate::expression::parentheses::{
empty_parenthesized, parenthesized, NeedsParentheses, OptionalParentheses,
};
use crate::prelude::*;
use crate::FormatNodeRule;
#[derive(Default)]
pub struct FormatExprDict;
struct KeyValuePair<'a> {
key: &'a Option<Expr>,
value: &'a Expr,
}
impl Ranged for KeyValuePair<'_> {
fn range(&self) -> TextRange {
if let Some(key) = self.key {
TextRange::new(key.start(), self.value.end())
} else {
self.value.range()
}
}
}
impl Format<PyFormatContext<'_>> for KeyValuePair<'_> {
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
if let Some(key) = self.key {
write!(
f,
[group(&format_args![
key.format(),
text(":"),
space(),
self.value.format()
])]
)
} else {
let comments = f.context().comments().clone();
let leading_value_comments = comments.leading_comments(self.value);
write!(
f,
[
// make sure the leading comments are hoisted past the `**`
leading_comments(leading_value_comments),
group(&format_args![text("**"), self.value.format()])
]
)
}
}
}
impl FormatNodeRule<ExprDict> for FormatExprDict {
fn fmt_fields(&self, item: &ExprDict, f: &mut PyFormatter) -> FormatResult<()> {
let ExprDict {
range: _,
keys,
values,
} = item;
debug_assert_eq!(keys.len(), values.len());
let comments = f.context().comments().clone();
let dangling = comments.dangling_comments(item);
if values.is_empty() {
return empty_parenthesized("{", dangling, "}").fmt(f);
}
let format_pairs = format_with(|f| {
let mut joiner = f.join_comma_separated(item.end());
for (key, value) in keys.iter().zip(values) {
let key_value_pair = KeyValuePair { key, value };
joiner.entry(&key_value_pair, &key_value_pair);
}
joiner.finish()
});
parenthesized("{", &format_pairs, "}")
.with_dangling_comments(dangling)
.fmt(f)
}
fn fmt_dangling_comments(&self, _node: &ExprDict, _f: &mut PyFormatter) -> FormatResult<()> {
// Handled by `fmt_fields`
Ok(())
}
}
impl NeedsParentheses for ExprDict {
fn needs_parentheses(
&self,
_parent: AnyNodeRef,
_context: &PyFormatContext,
) -> OptionalParentheses {
OptionalParentheses::Never
}
}