Skip to content

Commit

Permalink
fix: Prevent diagnostics from displaying out of view, fixing a panic
Browse files Browse the repository at this point in the history
  • Loading branch information
poliorcetics committed Feb 26, 2023
1 parent b68feeb commit 883a6db
Showing 1 changed file with 26 additions and 8 deletions.
34 changes: 26 additions & 8 deletions helix-term/src/ui/editor/diagnostics_annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ pub fn inline_diagnostics_decorator(
let whole_view_area = view.area;
let background = theme.get("ui.virtual.diagnostics");

// The maximum Y that diagnostics can be printed on. Necessary because we may want to print
// 5 lines of diagnostics while the view only has 3 left at the bottom and two more just out
// of bounds.
let max_y = viewport.height.saturating_sub(1).saturating_add(viewport.y);

let hint = theme.get("hint");
let info = theme.get("info");
let warning = theme.get("warning");
Expand Down Expand Up @@ -167,7 +172,7 @@ pub fn inline_diagnostics_decorator(

// When several diagnostics are present in the same virtual block, we will start by
// displaying the last one and go up one at a time
let mut pos_y = viewport
let mut code_pos_y = viewport
.y
.saturating_add(pos.visual_line)
.saturating_add(line_count);
Expand All @@ -179,6 +184,16 @@ pub fn inline_diagnostics_decorator(
_ => continue,
};

// Do the line count and check of pos_y now, it avoids having to build the display items
// for nothing
let lines_offset = text.lines().count() as u16;
code_pos_y -= lines_offset;

// If the first line to be printed is out of bound, don't display anything more of the current diagnostic
if code_pos_y + 1 > max_y {
continue;
}

left.clear();
let mut overlap = false;
let mut multi = 0;
Expand Down Expand Up @@ -229,22 +244,25 @@ pub fn inline_diagnostics_decorator(
// c. Is just one line.
// d. Is not an overlap.

let lines_offset = text.lines().count() as u16;
pos_y -= lines_offset;

// Use `view` since it's the whole outer view instead of just the inner area so that the background
// is also applied to the gutters and other elements that are not in the editable part of the document
let diag_area = Rect::new(
whole_view_area.x,
pos_y + 1,
// We checked at the start of the loop that this is valid
code_pos_y + 1,
whole_view_area.width,
lines_offset,
);
renderer.surface.set_style(diag_area, background);

for (offset, line) in text.lines().enumerate() {
let mut pos_x = viewport.x;
let pos_y = pos_y + 1 + offset as u16;
let diag_pos_y = code_pos_y + 1 + offset as u16;
// If we're out of bounds, don't display this diagnostic line, nor the following
// ones since they'll be out of bounds too.
if diag_pos_y > max_y {
break;
}

for item in left.iter().chain(center.iter()) {
let (text, style, width): (Cow<str>, _, _) = match *item {
Expand All @@ -258,13 +276,13 @@ pub fn inline_diagnostics_decorator(
DisplayItem::String(ref s, style, n) => (s.into(), style, n),
};

renderer.surface.set_string(pos_x, pos_y, text, style);
renderer.surface.set_string(pos_x, diag_pos_y, text, style);
pos_x = pos_x.saturating_add(width);
}

renderer
.surface
.set_string(pos_x, pos_y, line.trim(), style);
.set_string(pos_x, diag_pos_y, line.trim(), style);

center.clear();
// Special-case for continuation lines
Expand Down

0 comments on commit 883a6db

Please sign in to comment.