Compare commits

...

1 Commits

Author SHA1 Message Date
konstin
0f2979ed66 Formatter: Show preceding, following and enclosing of comments
**Summary** I used to always add `dbg!` for preceding, following and enclosing. With this change `--print-comments` can do this instead.
```python
import re  # import

def to_camel_case(node: str) -> str:
    """Converts PascalCase to camel_case"""
    return re.sub("([A-Z])", r"_\1", node).lower().lstrip("_")

# a
if True:
    pass  # b
else:
    print()
```
Debug output:
```
11..19 Some((StmtImport, 0..9)) Some((StmtFunctionDef, 22..165)) (ModModule, 0..213) "# import"
168..171 Some((StmtFunctionDef, 22..165)) Some((StmtIf, 172..212)) (ModModule, 0..213) "# a"
191..194 Some((StmtPass, 185..189)) Some((ElifElseClause, 195..212)) (StmtIf, 172..212) "# b"
```

**Test Plan** n/a
2023-08-23 12:55:24 +02:00
3 changed files with 106 additions and 38 deletions

View File

@@ -8,8 +8,10 @@ use ruff_python_parser::lexer::lex;
use ruff_python_parser::{parse_tokens, Mode}; use ruff_python_parser::{parse_tokens, Mode};
use ruff_formatter::SourceCode; use ruff_formatter::SourceCode;
use ruff_python_ast::Ranged;
use ruff_python_index::CommentRangesBuilder; use ruff_python_index::CommentRangesBuilder;
use crate::comments::Comments;
use crate::{format_node, PyFormatOptions}; use crate::{format_node, PyFormatOptions};
#[derive(ValueEnum, Clone, Debug)] #[derive(ValueEnum, Clone, Debug)]
@@ -68,6 +70,29 @@ pub fn format_and_debug_print(input: &str, cli: &Cli) -> Result<String> {
println!("{}", formatted.document().display(SourceCode::new(input))); println!("{}", formatted.document().display(SourceCode::new(input)));
} }
if cli.print_comments { if cli.print_comments {
// Print preceding, following and enclosing nodes
let decorated_comments = Comments::collect_decorated_comments(
&python_ast,
SourceCode::new(input),
&comment_ranges,
);
for comment in decorated_comments {
println!(
"{:?} {:?} {:?} {:?} {:?}",
comment.slice().range(),
comment
.preceding_node()
.map(|node| (node.kind(), node.range())),
comment
.following_node()
.map(|node| (node.kind(), node.range())),
(
comment.enclosing_node().kind(),
comment.enclosing_node().range()
),
comment.slice().text(SourceCode::new(input)),
);
}
println!( println!(
"{:#?}", "{:#?}",
formatted.context().comments().debug(SourceCode::new(input)) formatted.context().comments().debug(SourceCode::new(input))

View File

@@ -105,7 +105,9 @@ use ruff_python_index::CommentRanges;
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;
use crate::comments::visitor::CommentsVisitor; use crate::comments::visitor::{
CommentsBuilder, CommentsVisitor, DecoratedComment, DecoratedCommentsCollector,
};
mod debug; mod debug;
mod format; mod format;
@@ -262,12 +264,25 @@ impl<'a> Comments<'a> {
let map = if comment_ranges.is_empty() { let map = if comment_ranges.is_empty() {
CommentsMap::new() CommentsMap::new()
} else { } else {
CommentsVisitor::new(source_code, comment_ranges).visit(root) let mut builder = CommentsBuilder::default();
CommentsVisitor::new(source_code, comment_ranges, &mut builder).visit(root);
builder.finish()
}; };
Self::new(map) Self::new(map)
} }
/// Extracts the comments from the AST.
pub(crate) fn collect_decorated_comments(
root: &'a Mod,
source_code: SourceCode<'a>,
comment_ranges: &'a CommentRanges,
) -> Vec<DecoratedComment<'a>> {
let mut builder = DecoratedCommentsCollector::default();
CommentsVisitor::new(source_code, comment_ranges, &mut builder).visit(root);
builder.finish()
}
#[inline] #[inline]
pub(crate) fn has_comments<T>(&self, node: T) -> bool pub(crate) fn has_comments<T>(&self, node: T) -> bool
where where

View File

@@ -22,19 +22,29 @@ use crate::comments::placement::place_comment;
use crate::comments::{CommentLinePosition, CommentsMap, SourceComment}; use crate::comments::{CommentLinePosition, CommentsMap, SourceComment};
/// Visitor extracting the comments from an AST. /// Visitor extracting the comments from an AST.
#[derive(Debug, Clone)] #[derive(Debug)]
pub(crate) struct CommentsVisitor<'a> { pub(super) struct CommentsVisitor<'a, 'b, Collector>
builder: CommentsBuilder<'a>, where
Collector: CommentsCollector<'a>,
{
collector: &'b mut Collector,
source_code: SourceCode<'a>, source_code: SourceCode<'a>,
parents: Vec<AnyNodeRef<'a>>, parents: Vec<AnyNodeRef<'a>>,
preceding_node: Option<AnyNodeRef<'a>>, preceding_node: Option<AnyNodeRef<'a>>,
comment_ranges: Peekable<std::slice::Iter<'a, TextRange>>, comment_ranges: Peekable<std::slice::Iter<'a, TextRange>>,
} }
impl<'a> CommentsVisitor<'a> { impl<'a, 'b, Collector> CommentsVisitor<'a, 'b, Collector>
pub(crate) fn new(source_code: SourceCode<'a>, comment_ranges: &'a CommentRanges) -> Self { where
Collector: CommentsCollector<'a>,
{
pub(super) fn new(
source_code: SourceCode<'a>,
comment_ranges: &'a CommentRanges,
collector: &'b mut Collector,
) -> Self {
Self { Self {
builder: CommentsBuilder::default(), collector,
source_code, source_code,
parents: Vec::new(), parents: Vec::new(),
preceding_node: None, preceding_node: None,
@@ -42,10 +52,8 @@ impl<'a> CommentsVisitor<'a> {
} }
} }
pub(super) fn visit(mut self, root: &'a Mod) -> CommentsMap<'a> { pub(super) fn visit(mut self, root: &'a Mod) {
self.visit_mod(root); self.visit_mod(root);
self.finish()
} }
fn start_node<N>(&mut self, node: N) -> TraversalSignal fn start_node<N>(&mut self, node: N) -> TraversalSignal
@@ -78,10 +86,8 @@ impl<'a> CommentsVisitor<'a> {
slice: self.source_code.slice(*comment_range), slice: self.source_code.slice(*comment_range),
}; };
self.builder.add_comment(place_comment( self.collector
comment, .add_comment(comment, &Locator::new(self.source_code.as_str()));
&Locator::new(self.source_code.as_str()),
));
self.comment_ranges.next(); self.comment_ranges.next();
} }
@@ -137,23 +143,20 @@ impl<'a> CommentsVisitor<'a> {
slice: self.source_code.slice(*comment_range), slice: self.source_code.slice(*comment_range),
}; };
self.builder.add_comment(place_comment( self.collector
comment, .add_comment(comment, &Locator::new(self.source_code.as_str()));
&Locator::new(self.source_code.as_str()),
));
self.comment_ranges.next(); self.comment_ranges.next();
} }
self.preceding_node = Some(node); self.preceding_node = Some(node);
} }
fn finish(self) -> CommentsMap<'a> {
self.builder.finish()
}
} }
impl<'ast> PreorderVisitor<'ast> for CommentsVisitor<'ast> { impl<'ast, 'b, Collector> PreorderVisitor<'ast> for CommentsVisitor<'ast, 'b, Collector>
where
Collector: CommentsCollector<'ast>,
{
fn visit_mod(&mut self, module: &'ast Mod) { fn visit_mod(&mut self, module: &'ast Mod) {
if self.start_node(module).is_traverse() { if self.start_node(module).is_traverse() {
walk_module(self, module); walk_module(self, module);
@@ -336,7 +339,7 @@ fn text_position(comment_range: TextRange, source_code: SourceCode) -> CommentLi
/// ///
/// Used by [`CommentStyle::place_comment`] to determine if this should become a [leading](self#leading-comments), [dangling](self#dangling-comments), or [trailing](self#trailing-comments) comment. /// Used by [`CommentStyle::place_comment`] to determine if this should become a [leading](self#leading-comments), [dangling](self#dangling-comments), or [trailing](self#trailing-comments) comment.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(super) struct DecoratedComment<'a> { pub(crate) struct DecoratedComment<'a> {
enclosing: AnyNodeRef<'a>, enclosing: AnyNodeRef<'a>,
preceding: Option<AnyNodeRef<'a>>, preceding: Option<AnyNodeRef<'a>>,
following: Option<AnyNodeRef<'a>>, following: Option<AnyNodeRef<'a>>,
@@ -362,17 +365,17 @@ impl<'a> DecoratedComment<'a> {
/// ///
/// The enclosing node is the list expression and not the name `b` because /// The enclosing node is the list expression and not the name `b` because
/// `a` and `b` are children of the list expression and `comment` is between the two nodes. /// `a` and `b` are children of the list expression and `comment` is between the two nodes.
pub(super) fn enclosing_node(&self) -> AnyNodeRef<'a> { pub(crate) fn enclosing_node(&self) -> AnyNodeRef<'a> {
self.enclosing self.enclosing
} }
/// Returns the parent of the enclosing node, if any /// Returns the parent of the enclosing node, if any
pub(super) fn enclosing_parent(&self) -> Option<AnyNodeRef<'a>> { pub(crate) fn enclosing_parent(&self) -> Option<AnyNodeRef<'a>> {
self.parent self.parent
} }
/// Returns the slice into the source code. /// Returns the slice into the source code.
pub(super) fn slice(&self) -> &SourceCodeSlice { pub(crate) fn slice(&self) -> &SourceCodeSlice {
&self.slice &self.slice
} }
@@ -416,7 +419,7 @@ impl<'a> DecoratedComment<'a> {
/// ///
/// Returns `Some(a)` because `a` is the preceding node of `comment`. The presence of the `,` token /// Returns `Some(a)` because `a` is the preceding node of `comment`. The presence of the `,` token
/// doesn't change that. /// doesn't change that.
pub(super) fn preceding_node(&self) -> Option<AnyNodeRef<'a>> { pub(crate) fn preceding_node(&self) -> Option<AnyNodeRef<'a>> {
self.preceding self.preceding
} }
@@ -474,12 +477,12 @@ impl<'a> DecoratedComment<'a> {
/// ///
/// Returns `None` because `comment` is enclosed inside the parenthesized expression and it has no children /// Returns `None` because `comment` is enclosed inside the parenthesized expression and it has no children
/// following `# comment`. /// following `# comment`.
pub(super) fn following_node(&self) -> Option<AnyNodeRef<'a>> { pub(crate) fn following_node(&self) -> Option<AnyNodeRef<'a>> {
self.following self.following
} }
/// The position of the comment in the text. /// The position of the comment in the text.
pub(super) fn line_position(&self) -> CommentLinePosition { pub(crate) fn line_position(&self) -> CommentLinePosition {
self.line_position self.line_position
} }
} }
@@ -683,13 +686,18 @@ impl TraversalSignal {
} }
} }
pub(super) trait CommentsCollector<'a>: Default {
fn add_comment(&mut self, placement: DecoratedComment<'a>, locator: &Locator);
}
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct CommentsBuilder<'a> { pub(super) struct CommentsBuilder<'a> {
comments: CommentsMap<'a>, comments: CommentsMap<'a>,
} }
impl<'a> CommentsBuilder<'a> { impl<'a> CommentsCollector<'a> for CommentsBuilder<'a> {
fn add_comment(&mut self, placement: CommentPlacement<'a>) { fn add_comment(&mut self, placement: DecoratedComment<'a>, locator: &Locator) {
let placement = place_comment(placement, locator);
match placement { match placement {
CommentPlacement::Leading { node, comment } => { CommentPlacement::Leading { node, comment } => {
self.push_leading_comment(node, comment); self.push_leading_comment(node, comment);
@@ -748,11 +756,9 @@ impl<'a> CommentsBuilder<'a> {
} }
} }
} }
}
fn finish(self) -> CommentsMap<'a> { impl<'a> CommentsBuilder<'a> {
self.comments
}
fn push_leading_comment(&mut self, node: AnyNodeRef<'a>, comment: impl Into<SourceComment>) { fn push_leading_comment(&mut self, node: AnyNodeRef<'a>, comment: impl Into<SourceComment>) {
self.comments self.comments
.push_leading(NodeRefEqualityKey::from_ref(node), comment.into()); .push_leading(NodeRefEqualityKey::from_ref(node), comment.into());
@@ -767,4 +773,26 @@ impl<'a> CommentsBuilder<'a> {
self.comments self.comments
.push_trailing(NodeRefEqualityKey::from_ref(node), comment.into()); .push_trailing(NodeRefEqualityKey::from_ref(node), comment.into());
} }
pub(super) fn finish(self) -> CommentsMap<'a> {
self.comments
}
}
/// Used for the debug output, collects preceding, following and enclosing
#[derive(Default)]
pub(super) struct DecoratedCommentsCollector<'a> {
comments: Vec<DecoratedComment<'a>>,
}
impl<'a> CommentsCollector<'a> for DecoratedCommentsCollector<'a> {
fn add_comment(&mut self, placement: DecoratedComment<'a>, _locator: &Locator) {
self.comments.push(placement);
}
}
impl<'a> DecoratedCommentsCollector<'a> {
pub(super) fn finish(self) -> Vec<DecoratedComment<'a>> {
self.comments
}
} }