docs and line/offset numbers in paths

This commit is contained in:
Jana Dönszelmann 2026-04-02 09:41:35 +02:00
parent af09bcd403
commit 2d9a029130
No known key found for this signature in database
9 changed files with 366 additions and 116 deletions

View file

@ -1,8 +1,9 @@
use super::ast::*;
use std::borrow::Cow;
/// Text categories, based on the parsing.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Kind {
pub enum SpanKind {
/// Parentheses e.g.
///
/// Stores the delimiter depth, for e.g. rainbow delimiters.
@ -31,35 +32,27 @@ pub enum Kind {
Text,
}
/// A `Span` is a piece of categorized text, based on the parsing done by
/// [`parse_input`](crate::parse_input).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Span<'a> {
/// The segment of text.
pub text: Cow<'a, str>,
pub kind: Kind,
/// Its category.
pub kind: SpanKind,
}
/// Configuration options for [`into_spans`]
pub struct Config {
/// Turn sequences of more than 1 space into exactly 1 space.
pub collapse_space: bool,
}
pub struct Context<'a> {
config: Config,
res: Vec<Span<'a>>,
depth: usize,
}
impl<'a> Context<'a> {
pub fn push(&mut self, text: impl Into<Cow<'a, str>>, kind: Kind) {
self.res.push(Span {
text: text.into(),
kind,
})
}
}
pub trait IntoSpans<'a>: private::IntoSpansImpl<'a> {}
/// Turn an ast node into [`Span`]s.
pub fn into_spans<'a>(ast: impl IntoSpans<'a>, config: Config) -> Vec<Span<'a>> {
let mut cx = Context {
let mut cx = private::Context {
config,
res: Vec::new(),
depth: 0,
@ -71,6 +64,21 @@ pub fn into_spans<'a>(ast: impl IntoSpans<'a>, config: Config) -> Vec<Span<'a>>
mod private {
use super::*;
pub struct Context<'a> {
pub config: Config,
pub res: Vec<Span<'a>>,
pub depth: usize,
}
impl<'a> Context<'a> {
fn push(&mut self, text: impl Into<Cow<'a, str>>, kind: SpanKind) {
self.res.push(Span {
text: text.into(),
kind,
})
}
}
pub trait IntoSpansImpl<'a> {
fn into_spans(self, cx: &mut Context<'a>);
}
@ -80,9 +88,9 @@ mod private {
impl<'a> IntoSpansImpl<'a> for Separator {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
Separator::Eq => cx.push("=", Kind::Separator),
Separator::Colon => cx.push(":", Kind::Separator),
Separator::DoubleColon => cx.push("::", Kind::Separator),
Separator::Eq => cx.push("=", SpanKind::Separator),
Separator::Colon => cx.push(":", SpanKind::Separator),
Separator::DoubleColon => cx.push("::", SpanKind::Separator),
}
}
}
@ -90,9 +98,9 @@ mod private {
impl<'a> IntoSpansImpl<'a> for QuoteType {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
QuoteType::Single => cx.push("'", Kind::Separator),
QuoteType::Double => cx.push("\"", Kind::Separator),
QuoteType::Backtick => cx.push("`", Kind::Separator),
QuoteType::Single => cx.push("'", SpanKind::Separator),
QuoteType::Double => cx.push("\"", SpanKind::Separator),
QuoteType::Backtick => cx.push("`", SpanKind::Separator),
}
}
}
@ -106,38 +114,38 @@ mod private {
num_hashtags,
suffix,
} = self;
cx.push(prefix, Kind::StringSurroundings);
cx.push(prefix, SpanKind::StringSurroundings);
for _ in 0..num_hashtags {
cx.push("#", Kind::StringSurroundings)
cx.push("#", SpanKind::StringSurroundings)
}
ty.into_spans(cx);
cx.push(contents, Kind::String);
cx.push(contents, SpanKind::String);
ty.into_spans(cx);
for _ in 0..num_hashtags {
cx.push("#", Kind::StringSurroundings)
cx.push("#", SpanKind::StringSurroundings)
}
cx.push(suffix, Kind::StringSurroundings);
cx.push(suffix, SpanKind::StringSurroundings);
}
}
impl<'a> IntoSpansImpl<'a> for Path<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
cx.push(self.to_string(), Kind::Path)
cx.push(self.to_string(), SpanKind::Path)
}
}
impl<'a> IntoSpansImpl<'a> for Number<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
cx.push(self.0, Kind::Number)
cx.push(self.0, SpanKind::Number)
}
}
impl<'a> IntoSpansImpl<'a> for Atom<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
Atom::Text(text) => cx.push(text, Kind::Text),
Atom::Text(text) => cx.push(text, SpanKind::Text),
}
}
}
@ -146,9 +154,9 @@ mod private {
fn into_spans(self, cx: &mut Context<'a>) {
match self.0.len() {
0 => {}
1 => cx.push(self.0, Kind::Space(1)),
n if cx.config.collapse_space => cx.push(" ", Kind::Space(n)),
n => cx.push(self.0, Kind::Space(n)),
1 => cx.push(self.0, SpanKind::Space(1)),
n if cx.config.collapse_space => cx.push(" ", SpanKind::Space(n)),
n => cx.push(self.0, SpanKind::Space(n)),
}
}
}
@ -156,9 +164,9 @@ mod private {
impl<'a> IntoSpansImpl<'a> for Token<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
Token::True => cx.push("true", Kind::Literal),
Token::False => cx.push("false", Kind::Literal),
Token::None => cx.push("None", Kind::Literal),
Token::True => cx.push("true", SpanKind::Literal),
Token::False => cx.push("false", SpanKind::Literal),
Token::None => cx.push("None", SpanKind::Literal),
Token::Path(path) => path.into_spans(cx),
Token::String(string) => string.into_spans(cx),
Token::Number(number) => number.into_spans(cx),
@ -216,15 +224,18 @@ mod private {
} = self;
match prefix {
Some(Atom::Text(text)) => cx.push(text, Kind::Constructor),
Some((Atom::Text(text), space)) => {
cx.push(text, SpanKind::Constructor);
space.into_spans(cx);
}
None => {}
}
match delimiter {
Delimiter::Paren => cx.push("(", Kind::Delimiter(cx.depth)),
Delimiter::Bracket => cx.push("[", Kind::Delimiter(cx.depth)),
Delimiter::Brace => cx.push("{", Kind::Delimiter(cx.depth)),
Delimiter::Angle => cx.push("<", Kind::Delimiter(cx.depth)),
Delimiter::Paren => cx.push("(", SpanKind::Delimiter(cx.depth)),
Delimiter::Bracket => cx.push("[", SpanKind::Delimiter(cx.depth)),
Delimiter::Brace => cx.push("{", SpanKind::Delimiter(cx.depth)),
Delimiter::Angle => cx.push("<", SpanKind::Delimiter(cx.depth)),
}
cx.depth += 1;
@ -232,10 +243,10 @@ mod private {
cx.depth -= 1;
match delimiter {
Delimiter::Paren => cx.push(")", Kind::Delimiter(cx.depth)),
Delimiter::Bracket => cx.push("]", Kind::Delimiter(cx.depth)),
Delimiter::Brace => cx.push("}", Kind::Delimiter(cx.depth)),
Delimiter::Angle => cx.push(">", Kind::Delimiter(cx.depth)),
Delimiter::Paren => cx.push(")", SpanKind::Delimiter(cx.depth)),
Delimiter::Bracket => cx.push("]", SpanKind::Delimiter(cx.depth)),
Delimiter::Brace => cx.push("}", SpanKind::Delimiter(cx.depth)),
Delimiter::Angle => cx.push(">", SpanKind::Delimiter(cx.depth)),
}
}
}
@ -245,10 +256,10 @@ mod private {
mod tests {
use insta::assert_debug_snapshot;
use super::Kind;
use crate::format_debug_output::{Config, into_spans, parse_input};
use super::SpanKind;
use crate::{Config, into_spans, parse_input};
fn spans(input: &str) -> Vec<(String, Kind)> {
fn spans(input: &str) -> Vec<(String, SpanKind)> {
let res = parse_input(input).unwrap();
into_spans(
res,
@ -906,29 +917,13 @@ mod tests {
Separator,
),
(
"tests/ui/impl-trait/unsized_coercion.rs",
"tests/ui/impl-trait/unsized_coercion.rs:12:15",
Path,
),
(
":",
Separator,
),
(
"12",
Number,
),
(
":",
Separator,
),
(
"15",
Number,
),
(
":",
Separator,
),
(
" ",
Space(