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( comments_map.push_leading(
continue_statement.as_ref().into(), continue_statement.as_ref().into(),
SourceComment { SourceComment::new(
slice: source_code.slice(TextRange::at(TextSize::new(0), TextSize::new(17))), source_code.slice(TextRange::at(TextSize::new(0), TextSize::new(17))),
#[cfg(debug_assertions)] CommentTextPosition::OwnLine,
formatted: std::cell::Cell::new(false), ),
position: CommentTextPosition::OwnLine,
},
); );
comments_map.push_trailing( comments_map.push_trailing(
continue_statement.as_ref().into(), continue_statement.as_ref().into(),
SourceComment { SourceComment::new(
slice: source_code.slice(TextRange::at(TextSize::new(28), TextSize::new(10))), source_code.slice(TextRange::at(TextSize::new(28), TextSize::new(10))),
#[cfg(debug_assertions)] CommentTextPosition::EndOfLine,
formatted: std::cell::Cell::new(false), ),
position: CommentTextPosition::EndOfLine,
},
); );
comments_map.push_leading( comments_map.push_leading(
break_statement.as_ref().into(), break_statement.as_ref().into(),
SourceComment { SourceComment::new(
slice: source_code.slice(TextRange::at(TextSize::new(39), TextSize::new(15))), source_code.slice(TextRange::at(TextSize::new(39), TextSize::new(15))),
#[cfg(debug_assertions)] CommentTextPosition::OwnLine,
formatted: std::cell::Cell::new(false), ),
position: CommentTextPosition::OwnLine,
},
); );
let comments = Comments::new(comments_map); let comments = Comments::new(comments_map);

View file

@ -36,7 +36,10 @@ impl Format<PyFormatContext<'_>> for FormatLeadingComments<'_> {
FormatLeadingComments::Comments(comments) => comments, 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 slice = comment.slice();
let lines_after_comment = lines_after(slice.end(), f.context().contents()); 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; 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(); let slice = trailing.slice();
has_trailing_own_line_comment |= trailing.position().is_own_line(); has_trailing_own_line_comment |= trailing.position().is_own_line();
@ -198,7 +204,10 @@ impl Format<PyFormatContext<'_>> for FormatDanglingComments<'_> {
}; };
let mut first = true; 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() { if first && comment.position().is_end_of_line() {
write!(f, [space(), space()])?; 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, //! 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::debug::{DebugComment, DebugComments};
use crate::comments::map::MultiMap; use crate::comments::map::MultiMap;
use crate::comments::node_key::NodeRefEqualityKey; use crate::comments::node_key::NodeRefEqualityKey;
@ -109,40 +98,60 @@ pub(crate) use format::{
use ruff_formatter::{SourceCode, SourceCodeSlice}; use ruff_formatter::{SourceCode, SourceCodeSlice};
use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::source_code::CommentRanges; 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. /// A comment in the source document.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct SourceComment { pub(crate) struct SourceComment {
/// The location of the comment in the source document. /// The location of the comment in the source document.
slice: SourceCodeSlice, slice: SourceCodeSlice,
/// Whether the comment has been formatted or not. /// Whether the comment has been formatted or not.
#[cfg(debug_assertions)] formatted: Cell<bool>,
formatted: std::cell::Cell<bool>,
position: CommentTextPosition, position: CommentTextPosition,
} }
impl SourceComment { 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. /// Returns the location of the comment in the original source code.
/// Allows retrieving the text of the comment. /// Allows retrieving the text of the comment.
pub(crate) fn slice(&self) -> &SourceCodeSlice { pub(crate) const fn slice(&self) -> &SourceCodeSlice {
&self.slice &self.slice
} }
pub(crate) fn position(&self) -> CommentTextPosition { pub(crate) const fn position(&self) -> CommentTextPosition {
self.position self.position
} }
#[cfg(not(debug_assertions))]
#[inline(always)]
pub(crate) fn mark_formatted(&self) {}
/// Marks the comment as formatted /// Marks the comment as formatted
#[cfg(debug_assertions)]
pub(crate) fn mark_formatted(&self) { pub(crate) fn mark_formatted(&self) {
self.formatted.set(true); 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 { impl SourceComment {

View file

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

View file

@ -1,25 +1,11 @@
use crate::comments::leading_node_comments;
use crate::prelude::*; use crate::prelude::*;
use crate::FormatNodeRule; use crate::FormatNodeRule;
use ruff_formatter::{write, FormatRuleWithOptions}; use ruff_formatter::write;
use ruff_text_size::{TextLen, TextRange}; use ruff_text_size::{TextLen, TextRange};
use rustpython_parser::ast::Arg; use rustpython_parser::ast::Arg;
#[derive(Default)] #[derive(Default)]
pub struct FormatArg { 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,
}
impl FormatNodeRule<Arg> for FormatArg { impl FormatNodeRule<Arg> for FormatArg {
fn fmt_fields(&self, item: &Arg, f: &mut PyFormatter) -> FormatResult<()> { fn fmt_fields(&self, item: &Arg, f: &mut PyFormatter) -> FormatResult<()> {
@ -46,21 +32,4 @@ impl FormatNodeRule<Arg> for FormatArg {
Ok(()) 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::comments::{dangling_node_comments, leading_node_comments};
use crate::context::NodeLevel; use crate::context::NodeLevel;
use crate::other::arg::ArgumentKind;
use crate::prelude::*; use crate::prelude::*;
use crate::trivia::{first_non_trivia_token, SimpleTokenizer, Token, TokenKind}; use crate::trivia::{first_non_trivia_token, SimpleTokenizer, Token, TokenKind};
use crate::FormatNodeRule; use crate::FormatNodeRule;
@ -63,7 +62,7 @@ impl FormatNodeRule<Arguments> for FormatArguments {
joiner.entry(&format_args![ joiner.entry(&format_args![
leading_node_comments(vararg.as_ref()), leading_node_comments(vararg.as_ref()),
text("*"), text("*"),
vararg.format().with_options(ArgumentKind::Varg) vararg.format()
]); ]);
last_node = Some(vararg.as_any_node_ref()); last_node = Some(vararg.as_any_node_ref());
} }
@ -90,7 +89,7 @@ impl FormatNodeRule<Arguments> for FormatArguments {
joiner.entry(&format_args![ joiner.entry(&format_args![
leading_node_comments(kwarg.as_ref()), leading_node_comments(kwarg.as_ref()),
text("**"), text("**"),
kwarg.format().with_options(ArgumentKind::Kwarg) kwarg.format()
]); ]);
last_node = Some(kwarg.as_any_node_ref()); last_node = Some(kwarg.as_any_node_ref());
} }