Show diagnostics in scrollbar (#7175)

This PR implements support for displaying diagnostics in the scrollbar,
similar to what is already done for search results, symbols, git diff,
...

For example, changing a field name (`text`) without changing the
references looks like this in `buffer.rs` (note the red lines in the
scrollbar):

![image](https://github.com/zed-industries/zed/assets/53836821/c46f0d55-32e3-4334-8ad7-66d1578d5725)

As you can see, the errors, warnings, ... are displayed in the scroll
bar, which helps to identify possible problems with the current file.

Relevant issues: #4866, #6819

Release Notes:

- Added diagnostic indicators to the scrollbar
This commit is contained in:
Bennet Bo Fenner 2024-02-02 11:10:42 +01:00 committed by GitHub
parent 2940a0ebd8
commit ce4c15dca6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 81 additions and 1 deletions

View file

@ -127,7 +127,9 @@
// Whether to show selections in the scrollbar.
"selections": true,
// Whether to show symbols selections in the scrollbar.
"symbols_selections": true
"symbols_selections": true,
// Whether to show diagnostic indicators in the scrollbar.
"diagnostics": true
},
"relative_line_numbers": false,
// When to populate a new search's query based on the text under the cursor.

View file

@ -34,6 +34,7 @@ pub struct Scrollbar {
pub git_diff: bool,
pub selections: bool,
pub symbols_selections: bool,
pub diagnostics: bool,
}
/// When to show the scrollbar in the editor.
@ -122,6 +123,10 @@ pub struct ScrollbarContent {
///
/// Default: true
pub symbols_selections: Option<bool>,
/// Whether to show diagnostic indicators in the scrollbar.
///
/// Default: true
pub diagnostics: Option<bool>,
}
impl Settings for EditorSettings {

View file

@ -35,6 +35,7 @@ use gpui::{
};
use itertools::Itertools;
use language::language_settings::ShowWhitespaceSetting;
use lsp::DiagnosticSeverity;
use multi_buffer::Anchor;
use project::{
project_settings::{GitGutterSetting, ProjectSettings},
@ -1477,6 +1478,64 @@ impl EditorElement {
}
}
if layout.is_singleton && scrollbar_settings.diagnostics {
let max_point = layout
.position_map
.snapshot
.display_snapshot
.buffer_snapshot
.max_point();
let diagnostics = layout
.position_map
.snapshot
.buffer_snapshot
.diagnostics_in_range::<_, Point>(Point::zero()..max_point, false)
// We want to sort by severity, in order to paint the most severe diagnostics last.
.sorted_by_key(|diagnostic| std::cmp::Reverse(diagnostic.diagnostic.severity));
for diagnostic in diagnostics {
let start_display = diagnostic
.range
.start
.to_display_point(&layout.position_map.snapshot.display_snapshot);
let end_display = diagnostic
.range
.end
.to_display_point(&layout.position_map.snapshot.display_snapshot);
let start_y = y_for_row(start_display.row() as f32);
let mut end_y = if diagnostic.range.start == diagnostic.range.end {
y_for_row((end_display.row() + 1) as f32)
} else {
y_for_row((end_display.row()) as f32)
};
if end_y - start_y < px(1.) {
end_y = start_y + px(1.);
}
let bounds = Bounds::from_corners(point(left, start_y), point(right, end_y));
let color = match diagnostic.diagnostic.severity {
DiagnosticSeverity::ERROR => cx.theme().status().error,
DiagnosticSeverity::WARNING => cx.theme().status().warning,
DiagnosticSeverity::INFORMATION => cx.theme().status().info,
_ => cx.theme().status().hint,
};
cx.paint_quad(quad(
bounds,
Corners::default(),
color,
Edges {
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
cx.theme().colors().scrollbar_thumb_border,
));
}
}
cx.paint_quad(quad(
thumb_bounds,
Corners::default(),
@ -2106,6 +2165,9 @@ impl EditorElement {
// Symbols Selections
(is_singleton && scrollbar_settings.symbols_selections && (editor.has_background_highlights::<DocumentHighlightRead>() || editor.has_background_highlights::<DocumentHighlightWrite>()))
||
// Diagnostics
(is_singleton && scrollbar_settings.diagnostics && snapshot.buffer_snapshot.has_diagnostics())
||
// Scrollmanager
editor.scroll_manager.scrollbars_visible()
}

View file

@ -2993,6 +2993,11 @@ impl BufferSnapshot {
self.git_diff.hunks_intersecting_range_rev(range, self)
}
/// Returns if the buffer contains any diagnostics.
pub fn has_diagnostics(&self) -> bool {
!self.diagnostics.is_empty()
}
/// Returns all the diagnostics intersecting the given range.
pub fn diagnostics_in_range<'a, T, O>(
&'a self,

View file

@ -3052,6 +3052,12 @@ impl MultiBufferSnapshot {
self.has_conflict
}
pub fn has_diagnostics(&self) -> bool {
self.excerpts
.iter()
.any(|excerpt| excerpt.buffer.has_diagnostics())
}
pub fn diagnostic_group<'a, O>(
&'a self,
group_id: usize,