Track formatted comments (#4979)

This commit is contained in:
Micha Reiser 2023-06-09 11:09:45 +02:00 committed by GitHub
parent 646ab64850
commit 68d52da43b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 85 deletions

View file

@ -206,32 +206,26 @@ break;
comments_map.push_leading(
continue_statement.as_ref().into(),
SourceComment {
slice: source_code.slice(TextRange::at(TextSize::new(0), TextSize::new(17))),
#[cfg(debug_assertions)]
formatted: std::cell::Cell::new(false),
position: CommentTextPosition::OwnLine,
},
SourceComment::new(
source_code.slice(TextRange::at(TextSize::new(0), TextSize::new(17))),
CommentTextPosition::OwnLine,
),
);
comments_map.push_trailing(
continue_statement.as_ref().into(),
SourceComment {
slice: source_code.slice(TextRange::at(TextSize::new(28), TextSize::new(10))),
#[cfg(debug_assertions)]
formatted: std::cell::Cell::new(false),
position: CommentTextPosition::EndOfLine,
},
SourceComment::new(
source_code.slice(TextRange::at(TextSize::new(28), TextSize::new(10))),
CommentTextPosition::EndOfLine,
),
);
comments_map.push_leading(
break_statement.as_ref().into(),
SourceComment {
slice: source_code.slice(TextRange::at(TextSize::new(39), TextSize::new(15))),
#[cfg(debug_assertions)]
formatted: std::cell::Cell::new(false),
position: CommentTextPosition::OwnLine,
},
SourceComment::new(
source_code.slice(TextRange::at(TextSize::new(39), TextSize::new(15))),
CommentTextPosition::OwnLine,
),
);
let comments = Comments::new(comments_map);

View file

@ -36,7 +36,10 @@ impl Format<PyFormatContext<'_>> for FormatLeadingComments<'_> {
FormatLeadingComments::Comments(comments) => comments,
};
for comment in leading_comments {
for comment in leading_comments
.iter()
.filter(|comment| comment.is_unformatted())
{
let slice = comment.slice();
let lines_after_comment = lines_after(slice.end(), f.context().contents());
@ -127,7 +130,10 @@ impl Format<PyFormatContext<'_>> for FormatTrailingComments<'_> {
let mut has_trailing_own_line_comment = false;
for trailing in trailing_comments {
for trailing in trailing_comments
.iter()
.filter(|comment| comment.is_unformatted())
{
let slice = trailing.slice();
has_trailing_own_line_comment |= trailing.position().is_own_line();
@ -198,7 +204,10 @@ impl Format<PyFormatContext<'_>> for FormatDanglingComments<'_> {
};
let mut first = true;
for comment in dangling_comments {
for comment in dangling_comments
.iter()
.filter(|comment| comment.is_unformatted())
{
if first && comment.position().is_end_of_line() {
write!(f, [space(), space()])?;
}

View file

@ -87,17 +87,6 @@
//!
//! It is possible to add an additional optional label to [`SourceComment`] If ever the need arises to distinguish two *dangling comments* in the formatting logic,
use rustpython_parser::ast::Mod;
use std::fmt::Debug;
use std::rc::Rc;
mod debug;
mod format;
mod map;
mod node_key;
mod placement;
mod visitor;
use crate::comments::debug::{DebugComment, DebugComments};
use crate::comments::map::MultiMap;
use crate::comments::node_key::NodeRefEqualityKey;
@ -109,40 +98,60 @@ pub(crate) use format::{
use ruff_formatter::{SourceCode, SourceCodeSlice};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::source_code::CommentRanges;
use rustpython_parser::ast::Mod;
use std::cell::Cell;
use std::fmt::Debug;
use std::rc::Rc;
mod debug;
mod format;
mod map;
mod node_key;
mod placement;
mod visitor;
/// A comment in the source document.
#[derive(Debug, Clone)]
pub(crate) struct SourceComment {
/// The location of the comment in the source document.
slice: SourceCodeSlice,
/// Whether the comment has been formatted or not.
#[cfg(debug_assertions)]
formatted: std::cell::Cell<bool>,
formatted: Cell<bool>,
position: CommentTextPosition,
}
impl SourceComment {
fn new(slice: SourceCodeSlice, position: CommentTextPosition) -> Self {
Self {
slice,
position,
formatted: Cell::new(false),
}
}
/// Returns the location of the comment in the original source code.
/// Allows retrieving the text of the comment.
pub(crate) fn slice(&self) -> &SourceCodeSlice {
pub(crate) const fn slice(&self) -> &SourceCodeSlice {
&self.slice
}
pub(crate) fn position(&self) -> CommentTextPosition {
pub(crate) const fn position(&self) -> CommentTextPosition {
self.position
}
#[cfg(not(debug_assertions))]
#[inline(always)]
pub(crate) fn mark_formatted(&self) {}
/// Marks the comment as formatted
#[cfg(debug_assertions)]
pub(crate) fn mark_formatted(&self) {
self.formatted.set(true);
}
/// If the comment has already been formatted
pub(crate) fn is_formatted(&self) -> bool {
self.formatted.get()
}
pub(crate) fn is_unformatted(&self) -> bool {
!self.is_formatted()
}
}
impl SourceComment {

View file

@ -420,12 +420,7 @@ impl<'a> DecoratedComment<'a> {
impl From<DecoratedComment<'_>> for SourceComment {
fn from(decorated: DecoratedComment) -> Self {
Self {
slice: decorated.slice,
position: decorated.text_position,
#[cfg(debug_assertions)]
formatted: std::cell::Cell::new(false),
}
Self::new(decorated.slice, decorated.text_position)
}
}

View file

@ -1,25 +1,11 @@
use crate::comments::leading_node_comments;
use crate::prelude::*;
use crate::FormatNodeRule;
use ruff_formatter::{write, FormatRuleWithOptions};
use ruff_formatter::write;
use ruff_text_size::{TextLen, TextRange};
use rustpython_parser::ast::Arg;
#[derive(Default)]
pub struct FormatArg {
kind: ArgumentKind,
}
#[derive(Copy, Clone, Debug, Default)]
pub enum ArgumentKind {
/// Positional only, regular argument, or a keyword only argument.
#[default]
Normal,
/// A `*args` arguments
Varg,
/// A `**kwargs` argument
Kwarg,
}
pub struct FormatArg;
impl FormatNodeRule<Arg> for FormatArg {
fn fmt_fields(&self, item: &Arg, f: &mut PyFormatter) -> FormatResult<()> {
@ -46,21 +32,4 @@ impl FormatNodeRule<Arg> for FormatArg {
Ok(())
}
fn fmt_leading_comments(&self, node: &Arg, f: &mut PyFormatter) -> FormatResult<()> {
match self.kind {
ArgumentKind::Normal => leading_node_comments(node).fmt(f),
// Formatted as part of the `Arguments` to avoid emitting leading comments between the `*` and the argument.
ArgumentKind::Kwarg | ArgumentKind::Varg => Ok(()),
}
}
}
impl FormatRuleWithOptions<Arg, PyFormatContext<'_>> for FormatArg {
type Options = ArgumentKind;
fn with_options(mut self, options: Self::Options) -> Self {
self.kind = options;
self
}
}

View file

@ -1,6 +1,5 @@
use crate::comments::{dangling_node_comments, leading_node_comments};
use crate::context::NodeLevel;
use crate::other::arg::ArgumentKind;
use crate::prelude::*;
use crate::trivia::{first_non_trivia_token, SimpleTokenizer, Token, TokenKind};
use crate::FormatNodeRule;
@ -63,7 +62,7 @@ impl FormatNodeRule<Arguments> for FormatArguments {
joiner.entry(&format_args![
leading_node_comments(vararg.as_ref()),
text("*"),
vararg.format().with_options(ArgumentKind::Varg)
vararg.format()
]);
last_node = Some(vararg.as_any_node_ref());
}
@ -90,7 +89,7 @@ impl FormatNodeRule<Arguments> for FormatArguments {
joiner.entry(&format_args![
leading_node_comments(kwarg.as_ref()),
text("**"),
kwarg.format().with_options(ArgumentKind::Kwarg)
kwarg.format()
]);
last_node = Some(kwarg.as_any_node_ref());
}