tamer: diagnose::report::SourceLine: Separate variants for each line
Now `SourceLine` _does_ actually correspond to a line of output, which will allow for better formatting (e.g. collapsing padding) and, importantly, proper management of gutters. Note that the seemingly unnecessary `SectionSourceLine` allows for a subtle consistent formatting for all variants' gutters in `SectionLine`, which will allow us to hoist that rendering out in the next commit. The other option was to include a trailing space for padding and marks, but that is not only sloppy and undesirable, but asking for confusion, especially in editors (like mine) that trim trailing whitespace. DEV-12151main
parent
fd1c6430a8
commit
4e03a367a5
|
@ -304,23 +304,26 @@ where
|
||||||
|
|
||||||
let nlines = src.len();
|
let nlines = src.len();
|
||||||
|
|
||||||
body.extend(src.into_iter().enumerate().filter_map(
|
src.into_iter().enumerate().for_each(|(i, srcline)| {
|
||||||
|(i, srcline)| {
|
let label =
|
||||||
let label =
|
if i == nlines - 1 { olabel.take() } else { None };
|
||||||
if i == nlines - 1 { olabel.take() } else { None };
|
|
||||||
|
|
||||||
if let Some(col) = srcline.column() {
|
if let Some(col) = srcline.column() {
|
||||||
Some(SectionLine::SourceLine(SectionSourceLine {
|
body.extend(vec![
|
||||||
src: srcline,
|
SectionLine::SourceLinePadding,
|
||||||
mark: LineMark { col, level, label },
|
SectionLine::SourceLine(srcline.into()),
|
||||||
}))
|
SectionLine::SourceLineMark(LineMark {
|
||||||
} else {
|
col,
|
||||||
label.map(|l| {
|
level,
|
||||||
SectionLine::Footnote(SpanLabel(level, l))
|
label,
|
||||||
})
|
}),
|
||||||
}
|
]);
|
||||||
},
|
} else {
|
||||||
));
|
body.extend(label.map(|l| {
|
||||||
|
SectionLine::Footnote(SpanLabel(level, l))
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
(span, level)
|
(span, level)
|
||||||
}
|
}
|
||||||
|
@ -498,24 +501,23 @@ impl<'d> Display for SpanLabel<'d> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A possibly-annotated line of output.
|
/// Line of output in a [`Section`] body.
|
||||||
///
|
|
||||||
/// Note that a section line doesn't necessarily correspond to a single line
|
|
||||||
/// of output on a terminal;
|
|
||||||
/// lines are likely to be annotated.
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum SectionLine<'d> {
|
enum SectionLine<'d> {
|
||||||
SourceLine(SectionSourceLine<'d>),
|
SourceLinePadding,
|
||||||
|
SourceLine(SectionSourceLine),
|
||||||
|
SourceLineMark(LineMark<'d>),
|
||||||
Footnote(SpanLabel<'d>),
|
Footnote(SpanLabel<'d>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> SectionLine<'d> {
|
impl<'d> SectionLine<'d> {
|
||||||
fn into_footnote(self) -> Option<Self> {
|
fn into_footnote(self) -> Option<Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::SourceLine(SectionSourceLine {
|
Self::SourceLinePadding => None,
|
||||||
mark: LineMark { level, label, .. },
|
Self::SourceLine(..) => None,
|
||||||
..
|
Self::SourceLineMark(LineMark { level, label, .. }) => {
|
||||||
}) => label.map(|l| Self::Footnote(SpanLabel(level, l))),
|
label.map(|l| Self::Footnote(SpanLabel(level, l)))
|
||||||
|
}
|
||||||
|
|
||||||
Self::Footnote(..) => Some(self),
|
Self::Footnote(..) => Some(self),
|
||||||
}
|
}
|
||||||
|
@ -525,24 +527,26 @@ impl<'d> SectionLine<'d> {
|
||||||
impl<'d> Display for SectionLine<'d> {
|
impl<'d> Display for SectionLine<'d> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::SourceLine(line) => line.fmt(f),
|
Self::SourceLinePadding => write!(f, " |\n"),
|
||||||
|
Self::SourceLine(line) => write!(f, " |{line}\n"),
|
||||||
|
Self::SourceLineMark(mark) => write!(f, " |{mark}\n"),
|
||||||
Self::Footnote(label) => write!(f, "{label}\n"),
|
Self::Footnote(label) => write!(f, "{label}\n"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A line representing possibly-annotated source code.
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
struct SectionSourceLine<'d> {
|
struct SectionSourceLine(SourceLine);
|
||||||
src: SourceLine,
|
|
||||||
mark: LineMark<'d>,
|
impl From<SourceLine> for SectionSourceLine {
|
||||||
|
fn from(line: SourceLine) -> Self {
|
||||||
|
Self(line)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Display for SectionSourceLine<'d> {
|
impl Display for SectionSourceLine {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, " |\n")?;
|
write!(f, " {line}", line = self.0)
|
||||||
write!(f, " | {src}\n", src = self.src)?;
|
|
||||||
write!(f, " |{}", self.mark)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,7 +579,7 @@ impl<'d> Display for LineMark<'d> {
|
||||||
write!(f, " {level}: {label}", level = self.level)?;
|
write!(f, " {level}: {label}", level = self.level)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "\n")
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,23 +769,21 @@ mod test {
|
||||||
// Derived from label.
|
// Derived from label.
|
||||||
level: Level::Note,
|
level: Level::Note,
|
||||||
body: vec![
|
body: vec![
|
||||||
SectionLine::SourceLine(SectionSourceLine {
|
SectionLine::SourceLinePadding,
|
||||||
src: src_lines[0].clone(),
|
SectionLine::SourceLine(src_lines[0].clone().into()),
|
||||||
mark: LineMark {
|
SectionLine::SourceLineMark(LineMark {
|
||||||
level: Level::Note,
|
level: Level::Note,
|
||||||
col: col_1,
|
col: col_1,
|
||||||
// Label goes on the last source line.
|
// Label goes on the last source line.
|
||||||
label: None,
|
label: None,
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
SectionLine::SourceLine(SectionSourceLine {
|
SectionLine::SourceLinePadding,
|
||||||
src: src_lines[1].clone(),
|
SectionLine::SourceLine(src_lines[1].clone().into()),
|
||||||
mark: LineMark {
|
SectionLine::SourceLineMark(LineMark {
|
||||||
level: Level::Note,
|
level: Level::Note,
|
||||||
col: col_2,
|
col: col_2,
|
||||||
// Label at last source line
|
// Label at last source line
|
||||||
label: Some("test label".into()),
|
label: Some("test label".into()),
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -882,20 +884,29 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn section_src_line_with_label_into_footnote() {
|
fn section_src_line_into_footnote() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SectionLine::SourceLine(SectionSourceLine {
|
SectionLine::SourceLine(
|
||||||
src: SourceLine::new_stub(
|
SourceLine::new_stub(
|
||||||
1.unwrap_into(),
|
1.unwrap_into(),
|
||||||
None,
|
None,
|
||||||
DUMMY_SPAN,
|
DUMMY_SPAN,
|
||||||
"discarded".into()
|
"discarded".into()
|
||||||
),
|
)
|
||||||
mark: LineMark {
|
.into()
|
||||||
level: Level::Help,
|
)
|
||||||
col: Column::Before(1.unwrap_into()),
|
.into_footnote(),
|
||||||
label: Some("kept label".into())
|
None
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn section_mark_with_label_into_footnote() {
|
||||||
|
assert_eq!(
|
||||||
|
SectionLine::SourceLineMark(LineMark {
|
||||||
|
level: Level::Help,
|
||||||
|
col: Column::Before(1.unwrap_into()),
|
||||||
|
label: Some("kept label".into())
|
||||||
})
|
})
|
||||||
.into_footnote(),
|
.into_footnote(),
|
||||||
Some(SectionLine::Footnote(SpanLabel(
|
Some(SectionLine::Footnote(SpanLabel(
|
||||||
|
@ -906,20 +917,12 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn section_src_line_without_label_into_footnote() {
|
fn section_mark_without_label_into_footnote() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SectionLine::SourceLine(SectionSourceLine {
|
SectionLine::SourceLineMark(LineMark {
|
||||||
src: SourceLine::new_stub(
|
level: Level::Help,
|
||||||
1.unwrap_into(),
|
col: Column::Before(1.unwrap_into()),
|
||||||
None,
|
label: None,
|
||||||
DUMMY_SPAN,
|
|
||||||
"discarded".into()
|
|
||||||
),
|
|
||||||
mark: LineMark {
|
|
||||||
level: Level::Help,
|
|
||||||
col: Column::Before(1.unwrap_into()),
|
|
||||||
label: None,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.into_footnote(),
|
.into_footnote(),
|
||||||
None
|
None
|
||||||
|
|
Loading…
Reference in New Issue