mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 21:43:52 +00:00
parent
9e2fd0c620
commit
1979103ec0
11 changed files with 583 additions and 123 deletions
|
@ -29,6 +29,7 @@ pub(super) fn place_comment<'a>(
|
|||
handle_trailing_body_comment,
|
||||
handle_trailing_end_of_line_body_comment,
|
||||
handle_trailing_end_of_line_condition_comment,
|
||||
handle_trailing_end_of_line_except_comment,
|
||||
handle_module_level_own_line_comment_before_class_or_function_comment,
|
||||
handle_arguments_separator_comment,
|
||||
handle_trailing_binary_expression_left_or_operator_comment,
|
||||
|
@ -158,44 +159,52 @@ fn handle_in_between_except_handlers_or_except_handler_and_else_or_finally_comme
|
|||
comment: DecoratedComment<'a>,
|
||||
locator: &Locator,
|
||||
) -> CommentPlacement<'a> {
|
||||
if comment.line_position().is_end_of_line() || comment.following_node().is_none() {
|
||||
if comment.line_position().is_end_of_line() {
|
||||
return CommentPlacement::Default(comment);
|
||||
}
|
||||
|
||||
if let Some(AnyNodeRef::ExceptHandlerExceptHandler(except_handler)) = comment.preceding_node() {
|
||||
// it now depends on the indentation level of the comment if it is a leading comment for e.g.
|
||||
// the following `elif` or indeed a trailing comment of the previous body's last statement.
|
||||
let comment_indentation =
|
||||
whitespace::indentation_at_offset(locator, comment.slice().range().start())
|
||||
.map(str::len)
|
||||
.unwrap_or_default();
|
||||
let (Some(AnyNodeRef::ExceptHandlerExceptHandler(preceding_except_handler)), Some(following)) = (comment.preceding_node(), comment.following_node()) else {
|
||||
return CommentPlacement::Default(comment);
|
||||
};
|
||||
|
||||
if let Some(except_indentation) =
|
||||
whitespace::indentation(locator, except_handler).map(str::len)
|
||||
// it now depends on the indentation level of the comment if it is a leading comment for e.g.
|
||||
// the following `finally` or indeed a trailing comment of the previous body's last statement.
|
||||
let comment_indentation =
|
||||
whitespace::indentation_at_offset(locator, comment.slice().range().start())
|
||||
.map(str::len)
|
||||
.unwrap_or_default();
|
||||
|
||||
let Some(except_indentation) =
|
||||
whitespace::indentation(locator, preceding_except_handler).map(str::len) else
|
||||
{
|
||||
return if comment_indentation <= except_indentation {
|
||||
// It has equal, or less indent than the `except` handler. It must be a comment
|
||||
// of the following `finally` or `else` block
|
||||
//
|
||||
// ```python
|
||||
// try:
|
||||
// pass
|
||||
// except Exception:
|
||||
// print("noop")
|
||||
// # leading
|
||||
// finally:
|
||||
// pass
|
||||
// ```
|
||||
// Attach it to the `try` statement.
|
||||
CommentPlacement::dangling(comment.enclosing_node(), comment)
|
||||
} else {
|
||||
// Delegate to `handle_trailing_body_comment`
|
||||
CommentPlacement::Default(comment)
|
||||
};
|
||||
}
|
||||
return CommentPlacement::Default(comment);
|
||||
};
|
||||
|
||||
if comment_indentation > except_indentation {
|
||||
// Delegate to `handle_trailing_body_comment`
|
||||
return CommentPlacement::Default(comment);
|
||||
}
|
||||
|
||||
CommentPlacement::Default(comment)
|
||||
// It has equal, or less indent than the `except` handler. It must be a comment of a subsequent
|
||||
// except handler or of the following `finally` or `else` block
|
||||
//
|
||||
// ```python
|
||||
// try:
|
||||
// pass
|
||||
// except Exception:
|
||||
// print("noop")
|
||||
// # leading
|
||||
// finally:
|
||||
// pass
|
||||
// ```
|
||||
|
||||
if following.is_except_handler() {
|
||||
// Attach it to the following except handler (which has a node) as leading
|
||||
CommentPlacement::leading(following, comment)
|
||||
} else {
|
||||
// No following except handler; attach it to the `try` statement.as dangling
|
||||
CommentPlacement::dangling(comment.enclosing_node(), comment)
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles own line comments between the last statement and the first statement of two bodies.
|
||||
|
@ -668,6 +677,40 @@ fn handle_trailing_end_of_line_condition_comment<'a>(
|
|||
CommentPlacement::Default(comment)
|
||||
}
|
||||
|
||||
/// Handles end of line comments after the `:` of an except clause
|
||||
///
|
||||
/// ```python
|
||||
/// try:
|
||||
/// ...
|
||||
/// except: # comment
|
||||
/// pass
|
||||
/// ```
|
||||
///
|
||||
/// It attaches the comment as dangling comment to the enclosing except handler.
|
||||
fn handle_trailing_end_of_line_except_comment<'a>(
|
||||
comment: DecoratedComment<'a>,
|
||||
_locator: &Locator,
|
||||
) -> CommentPlacement<'a> {
|
||||
let AnyNodeRef::ExceptHandlerExceptHandler(handler) = comment.enclosing_node() else {
|
||||
return CommentPlacement::Default(comment);
|
||||
};
|
||||
|
||||
// Must be an end of line comment
|
||||
if comment.line_position().is_own_line() {
|
||||
return CommentPlacement::Default(comment);
|
||||
}
|
||||
|
||||
let Some(first_body_statement) = handler.body.first() else {
|
||||
return CommentPlacement::Default(comment);
|
||||
};
|
||||
|
||||
if comment.slice().start() < first_body_statement.range().start() {
|
||||
CommentPlacement::dangling(comment.enclosing_node(), comment)
|
||||
} else {
|
||||
CommentPlacement::Default(comment)
|
||||
}
|
||||
}
|
||||
|
||||
/// Attaches comments for the positional only arguments separator `/` or the keywords only arguments
|
||||
/// separator `*` as dangling comments to the enclosing [`Arguments`] node.
|
||||
///
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
|
||||
use crate::comments::trailing_comments;
|
||||
use crate::expression::parentheses::Parenthesize;
|
||||
use crate::prelude::*;
|
||||
use crate::{FormatNodeRule, PyFormatter};
|
||||
use ruff_formatter::{write, Buffer, FormatResult};
|
||||
use ruff_python_ast::node::AstNode;
|
||||
use rustpython_parser::ast::ExceptHandlerExceptHandler;
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -11,6 +15,43 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
|
|||
item: &ExceptHandlerExceptHandler,
|
||||
f: &mut PyFormatter,
|
||||
) -> FormatResult<()> {
|
||||
write!(f, [not_yet_implemented(item)])
|
||||
let ExceptHandlerExceptHandler {
|
||||
range: _,
|
||||
type_,
|
||||
name,
|
||||
body,
|
||||
} = item;
|
||||
|
||||
let comments_info = f.context().comments().clone();
|
||||
let dangling_comments = comments_info.dangling_comments(item.as_any_node_ref());
|
||||
|
||||
write!(f, [text("except")])?;
|
||||
|
||||
if let Some(type_) = type_ {
|
||||
write!(
|
||||
f,
|
||||
[space(), type_.format().with_options(Parenthesize::IfBreaks)]
|
||||
)?;
|
||||
if let Some(name) = name {
|
||||
write!(f, [space(), text("as"), space(), name.format()])?;
|
||||
}
|
||||
}
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
text(":"),
|
||||
trailing_comments(dangling_comments),
|
||||
block_indent(&body.format())
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_dangling_comments(
|
||||
&self,
|
||||
_node: &ExceptHandlerExceptHandler,
|
||||
_f: &mut PyFormatter,
|
||||
) -> FormatResult<()> {
|
||||
// dangling comments are formatted as part of fmt_fields
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,112 @@
|
|||
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
|
||||
use crate::comments;
|
||||
use crate::comments::leading_alternate_branch_comments;
|
||||
use crate::comments::SourceComment;
|
||||
use crate::prelude::*;
|
||||
use crate::statement::FormatRefWithRule;
|
||||
use crate::statement::Stmt;
|
||||
use crate::{FormatNodeRule, PyFormatter};
|
||||
use ruff_formatter::{write, Buffer, FormatResult};
|
||||
use rustpython_parser::ast::StmtTry;
|
||||
use ruff_python_ast::node::AstNode;
|
||||
use rustpython_parser::ast::{ExceptHandler, Ranged, StmtTry, Suite};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FormatStmtTry;
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct FormatExceptHandler;
|
||||
|
||||
impl FormatRule<ExceptHandler, PyFormatContext<'_>> for FormatExceptHandler {
|
||||
fn fmt(
|
||||
&self,
|
||||
item: &ExceptHandler,
|
||||
f: &mut Formatter<PyFormatContext<'_>>,
|
||||
) -> FormatResult<()> {
|
||||
match item {
|
||||
ExceptHandler::ExceptHandler(x) => x.format().fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> AsFormat<PyFormatContext<'ast>> for ExceptHandler {
|
||||
type Format<'a> = FormatRefWithRule<
|
||||
'a,
|
||||
ExceptHandler,
|
||||
FormatExceptHandler,
|
||||
PyFormatContext<'ast>,
|
||||
> where Self: 'a;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
FormatRefWithRule::new(self, FormatExceptHandler::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatNodeRule<StmtTry> for FormatStmtTry {
|
||||
fn fmt_fields(&self, item: &StmtTry, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
write!(f, [not_yet_implemented(item)])
|
||||
let StmtTry {
|
||||
range: _,
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
finalbody,
|
||||
} = item;
|
||||
|
||||
let comments_info = f.context().comments().clone();
|
||||
let mut dangling_comments = comments_info.dangling_comments(item.as_any_node_ref());
|
||||
|
||||
write!(f, [text("try:"), block_indent(&body.format())])?;
|
||||
|
||||
let mut previous_node = body.last();
|
||||
|
||||
for handler in handlers {
|
||||
let handler_comments = comments_info.leading_comments(handler);
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
leading_alternate_branch_comments(handler_comments, previous_node),
|
||||
&handler.format()
|
||||
]
|
||||
)?;
|
||||
previous_node = match handler {
|
||||
ExceptHandler::ExceptHandler(handler) => handler.body.last(),
|
||||
};
|
||||
}
|
||||
|
||||
(previous_node, dangling_comments) =
|
||||
format_case("else", orelse, previous_node, dangling_comments, f)?;
|
||||
|
||||
format_case("finally", finalbody, previous_node, dangling_comments, f)?;
|
||||
|
||||
write!(f, [comments::dangling_comments(dangling_comments)])
|
||||
}
|
||||
|
||||
fn fmt_dangling_comments(&self, _node: &StmtTry, _f: &mut PyFormatter) -> FormatResult<()> {
|
||||
// TODO(konstin): Needs node formatting or this leads to unstable formatting
|
||||
// dangling comments are formatted as part of fmt_fields
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn format_case<'a>(
|
||||
name: &'static str,
|
||||
body: &Suite,
|
||||
previous_node: Option<&Stmt>,
|
||||
dangling_comments: &'a [SourceComment],
|
||||
f: &mut PyFormatter,
|
||||
) -> FormatResult<(Option<&'a Stmt>, &'a [SourceComment])> {
|
||||
Ok(if let Some(last) = body.last() {
|
||||
let case_comments_start =
|
||||
dangling_comments.partition_point(|comment| comment.slice().end() <= last.end());
|
||||
let (case_comments, rest) = dangling_comments.split_at(case_comments_start);
|
||||
write!(
|
||||
f,
|
||||
[leading_alternate_branch_comments(
|
||||
case_comments,
|
||||
previous_node
|
||||
)]
|
||||
)?;
|
||||
|
||||
write!(f, [text(name), text(":"), block_indent(&body.format())])?;
|
||||
(None, rest)
|
||||
} else {
|
||||
(None, dangling_comments)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue