mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 21:43:52 +00:00

## Summary Previously, `DecoratedComment` used `text_position()` and `SourceComment` used `position()`. This PR unifies this to `line_position` everywhere. ## Test Plan This is a rename refactoring.
235 lines
6.7 KiB
Rust
235 lines
6.7 KiB
Rust
use crate::comments::node_key::NodeRefEqualityKey;
|
|
use crate::comments::{CommentsMap, SourceComment};
|
|
use itertools::Itertools;
|
|
use ruff_formatter::SourceCode;
|
|
use ruff_python_ast::prelude::*;
|
|
use std::fmt::{Debug, Formatter, Write};
|
|
|
|
/// Prints a debug representation of [`SourceComment`] that includes the comment's text
|
|
pub(crate) struct DebugComment<'a> {
|
|
comment: &'a SourceComment,
|
|
source_code: SourceCode<'a>,
|
|
}
|
|
|
|
impl<'a> DebugComment<'a> {
|
|
pub(super) fn new(comment: &'a SourceComment, source_code: SourceCode<'a>) -> Self {
|
|
Self {
|
|
comment,
|
|
source_code,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Debug for DebugComment<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
let mut strut = f.debug_struct("SourceComment");
|
|
|
|
strut
|
|
.field("text", &self.comment.slice.text(self.source_code))
|
|
.field("position", &self.comment.line_position);
|
|
|
|
#[cfg(debug_assertions)]
|
|
strut.field("formatted", &self.comment.formatted.get());
|
|
|
|
strut.finish()
|
|
}
|
|
}
|
|
|
|
/// Pretty-printed debug representation of [`Comments`].
|
|
pub(crate) struct DebugComments<'a> {
|
|
comments: &'a CommentsMap<'a>,
|
|
source_code: SourceCode<'a>,
|
|
}
|
|
|
|
impl<'a> DebugComments<'a> {
|
|
pub(super) fn new(comments: &'a CommentsMap, source_code: SourceCode<'a>) -> Self {
|
|
Self {
|
|
comments,
|
|
source_code,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Debug for DebugComments<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
let mut map = f.debug_map();
|
|
|
|
for node in self.comments.keys().sorted_by_key(|key| key.node().start()) {
|
|
map.entry(
|
|
&NodeKindWithSource {
|
|
key: *node,
|
|
source: self.source_code,
|
|
},
|
|
&DebugNodeComments {
|
|
comments: self.comments,
|
|
source_code: self.source_code,
|
|
key: *node,
|
|
},
|
|
);
|
|
}
|
|
|
|
map.finish()
|
|
}
|
|
}
|
|
|
|
/// Prints the source code up to the first new line character. Truncates the text if it exceeds 40 characters.
|
|
struct NodeKindWithSource<'a> {
|
|
key: NodeRefEqualityKey<'a>,
|
|
source: SourceCode<'a>,
|
|
}
|
|
|
|
impl Debug for NodeKindWithSource<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
struct TruncatedSource<'a>(&'a str);
|
|
|
|
impl Debug for TruncatedSource<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.write_char('`')?;
|
|
let first_line = if let Some(line_end_pos) = self.0.find(['\n', '\r']) {
|
|
&self.0[..line_end_pos]
|
|
} else {
|
|
self.0
|
|
};
|
|
|
|
if first_line.len() > 40 {
|
|
let (head, rest) = first_line.split_at(27);
|
|
|
|
f.write_str(head)?;
|
|
f.write_str("...")?;
|
|
|
|
// Take the last 10 characters
|
|
let tail = &rest[rest.len().saturating_sub(10)..];
|
|
f.write_str(tail)?;
|
|
} else {
|
|
f.write_str(first_line)?;
|
|
}
|
|
|
|
if first_line.len() < self.0.len() {
|
|
f.write_str("\u{23ce}")?;
|
|
}
|
|
|
|
f.write_char('`')
|
|
}
|
|
}
|
|
|
|
let kind = self.key.node().kind();
|
|
let source = self.source.slice(self.key.node().range()).text(self.source);
|
|
|
|
f.debug_struct("Node")
|
|
.field("kind", &kind)
|
|
.field("range", &self.key.node().range())
|
|
.field("source", &TruncatedSource(source))
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
struct DebugNodeComments<'a> {
|
|
comments: &'a CommentsMap<'a>,
|
|
source_code: SourceCode<'a>,
|
|
key: NodeRefEqualityKey<'a>,
|
|
}
|
|
|
|
impl Debug for DebugNodeComments<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_map()
|
|
.entry(
|
|
&"leading",
|
|
&DebugNodeCommentSlice {
|
|
node_comments: self.comments.leading(&self.key),
|
|
source_code: self.source_code,
|
|
},
|
|
)
|
|
.entry(
|
|
&"dangling",
|
|
&DebugNodeCommentSlice {
|
|
node_comments: self.comments.dangling(&self.key),
|
|
source_code: self.source_code,
|
|
},
|
|
)
|
|
.entry(
|
|
&"trailing",
|
|
&DebugNodeCommentSlice {
|
|
node_comments: self.comments.trailing(&self.key),
|
|
source_code: self.source_code,
|
|
},
|
|
)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
struct DebugNodeCommentSlice<'a> {
|
|
node_comments: &'a [SourceComment],
|
|
source_code: SourceCode<'a>,
|
|
}
|
|
|
|
impl Debug for DebugNodeCommentSlice<'_> {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
let mut list = f.debug_list();
|
|
|
|
for comment in self.node_comments {
|
|
list.entry(&comment.debug(self.source_code));
|
|
}
|
|
|
|
list.finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::comments::map::MultiMap;
|
|
use crate::comments::{CommentLinePosition, Comments, CommentsMap, SourceComment};
|
|
use insta::assert_debug_snapshot;
|
|
use ruff_formatter::SourceCode;
|
|
use ruff_python_ast::node::AnyNode;
|
|
use ruff_text_size::{TextRange, TextSize};
|
|
use rustpython_parser::ast::{StmtBreak, StmtContinue};
|
|
|
|
#[test]
|
|
fn debug() {
|
|
let continue_statement = AnyNode::from(StmtContinue {
|
|
range: TextRange::default(),
|
|
});
|
|
|
|
let break_statement = AnyNode::from(StmtBreak {
|
|
range: TextRange::default(),
|
|
});
|
|
|
|
let source = r#"# leading comment
|
|
continue; # trailing
|
|
# break leading
|
|
break;
|
|
"#;
|
|
|
|
let source_code = SourceCode::new(source);
|
|
|
|
let mut comments_map: CommentsMap = MultiMap::new();
|
|
|
|
comments_map.push_leading(
|
|
continue_statement.as_ref().into(),
|
|
SourceComment::new(
|
|
source_code.slice(TextRange::at(TextSize::new(0), TextSize::new(17))),
|
|
CommentLinePosition::OwnLine,
|
|
),
|
|
);
|
|
|
|
comments_map.push_trailing(
|
|
continue_statement.as_ref().into(),
|
|
SourceComment::new(
|
|
source_code.slice(TextRange::at(TextSize::new(28), TextSize::new(10))),
|
|
CommentLinePosition::EndOfLine,
|
|
),
|
|
);
|
|
|
|
comments_map.push_leading(
|
|
break_statement.as_ref().into(),
|
|
SourceComment::new(
|
|
source_code.slice(TextRange::at(TextSize::new(39), TextSize::new(15))),
|
|
CommentLinePosition::OwnLine,
|
|
),
|
|
);
|
|
|
|
let comments = Comments::new(comments_map);
|
|
|
|
assert_debug_snapshot!(comments.debug(source_code));
|
|
}
|
|
}
|