move handling of label start to renderer

this eliminates a failure condition from RichDiagnostic::render
because the full source code does not have to be loaded here any more
This commit is contained in:
Johann150 2020-09-15 22:42:18 +02:00
parent 593ed5372b
commit 56b3f2f7e2
2 changed files with 25 additions and 37 deletions

View File

@ -25,17 +25,18 @@ pub type SingleLabel<'diagnostic> = (LabelStyle, Range<usize>, &'diagnostic str)
///
/// Locations are relative to the start of where the source code is rendered.
pub enum MultiLabel<'diagnostic> {
/// Left top corner for multi-line labels.
///
/// ```text
/// ╭
/// ```
TopLeft,
/// Multi-line label top.
///
/// ```text
/// ╭────────────^
/// ```
///
/// Can also be rendered at the beginning of the line
/// if there is only whitespace before the label starts.
///
/// /// ```text
/// ╭
/// ```
Top(RangeTo<usize>),
/// Left vertical labels for multi-line labels.
///
@ -263,7 +264,9 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
match multi_labels_iter.peek() {
Some((label_index, label_style, label)) if *label_index == label_column => {
match label {
MultiLabel::TopLeft => {
MultiLabel::Top(range)
if range.end <= source.len() - source.trim_start().len() =>
{
self.label_multi_top_left(severity, *label_style)?;
}
MultiLabel::Top(..) => self.inner_gutter_space()?,
@ -290,7 +293,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
*ls == LabelStyle::Primary
&& match label {
MultiLabel::Top(range) => column_range.start >= range.end,
MultiLabel::TopLeft | MultiLabel::Left => true,
MultiLabel::Left => true,
MultiLabel::Bottom(range, _) => column_range.end <= range.end,
}
});
@ -537,7 +540,13 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
// ```
for (multi_label_index, (_, label_style, label)) in multi_labels.iter().enumerate() {
let (label_style, range, bottom_message) = match label {
MultiLabel::TopLeft | MultiLabel::Left => continue, // no label caret needed
MultiLabel::Left => continue, // no label caret needed
// no label caret needed if this can be started in front of the line
MultiLabel::Top(range_to)
if range_to.end <= source.len() - source.trim_start().len() =>
{
continue
}
MultiLabel::Top(range) => (*label_style, range, None),
MultiLabel::Bottom(range, message) => (*label_style, range, Some(message)),
};
@ -556,7 +565,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
match multi_labels_iter.peek() {
Some((i, (label_index, ls, label))) if *label_index == label_column => {
match label {
MultiLabel::TopLeft | MultiLabel::Left => {
MultiLabel::Left => {
self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?;
}
MultiLabel::Top(..) if multi_label_index > *i => {
@ -944,7 +953,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
for label_column in 0..num_multi_labels {
match multi_labels_iter.peek() {
Some((label_index, ls, label)) if *label_index == label_column => match label {
MultiLabel::TopLeft | MultiLabel::Left | MultiLabel::Bottom(..) => {
MultiLabel::Left | MultiLabel::Bottom(..) => {
self.label_multi_left(severity, *ls, None)?;
multi_labels_iter.next();
}

View File

@ -83,11 +83,6 @@ where
// Group labels by file
for label in &self.diagnostic.labels {
let source = files
.source(label.file_id)
.ok_or(RenderError::FileMissing)?;
let source = source.as_ref();
let start_line_index = files
.line_index(label.file_id, label.range.start)
.ok_or(RenderError::InvalidIndex)?;
@ -213,7 +208,6 @@ where
// First labeled line
let label_start = label.range.start - start_line_range.start;
let prefix_source = &source[start_line_range.start..label.range.start];
let start_line = labeled_file.get_or_insert_line(
start_line_index,
@ -221,26 +215,11 @@ where
start_line_number,
);
start_line
.multi_labels
// TODO: Do this in the `Renderer`?
.push(match prefix_source.trim() {
// Section is prefixed by empty space, so we don't need to take
// up a new line.
//
// ```text
// 4 │ ╭ case (mod num 5) (mod num 3) of
// ```
"" => (label_index, label.style, MultiLabel::TopLeft),
// There's source code in the prefix, so run a label
// underneath it to get to the start of the range.
//
// ```text
// 4 │ fizz₁ num = case (mod num 5) (mod num 3) of
// │ ╭─────────────^
// ```
_ => (label_index, label.style, MultiLabel::Top(..label_start)),
});
start_line.multi_labels.push((
label_index,
label.style,
MultiLabel::Top(..label_start),
));
// The first line has to be rendered so the start of the label is visible.
start_line.must_render = true;