mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-26 06:01:41 +03:00
Introduce the ability to include or exclude warnings from project diagnostics (#3056)
![CleanShot 2023-09-27 at 18 09 37](https://github.com/zed-industries/zed/assets/482957/317d31e4-81f8-44d8-b94f-8ca7150d3fd2) Release Notes: - Added the ability to exclude warnings from project diagnostics. By default, they will be on but they can be disabled temporarily by clicking on the warnings icon. The default behavior can be changed by changing the new `diagnostics.include_warnings` setting.
This commit is contained in:
commit
4dd9c9e2b9
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -2210,6 +2210,9 @@ dependencies = [
|
||||
"lsp",
|
||||
"postage",
|
||||
"project",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"smallvec",
|
||||
|
@ -227,6 +227,11 @@
|
||||
},
|
||||
// Automatically update Zed
|
||||
"auto_update": true,
|
||||
// Diagnostics configuration.
|
||||
"diagnostics": {
|
||||
// Whether to show warnings or not by default.
|
||||
"include_warnings": true
|
||||
},
|
||||
// Git gutter behavior configuration.
|
||||
"git": {
|
||||
// Control whether the git gutter is shown. May take 2 values:
|
||||
|
@ -21,6 +21,9 @@ util = { path = "../util" }
|
||||
workspace = { path = "../workspace" }
|
||||
|
||||
anyhow.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
smallvec.workspace = true
|
||||
postage.workspace = true
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
pub mod items;
|
||||
mod project_diagnostics_settings;
|
||||
mod toolbar_controls;
|
||||
|
||||
use anyhow::Result;
|
||||
use collections::{BTreeSet, HashSet};
|
||||
@ -19,6 +21,7 @@ use language::{
|
||||
};
|
||||
use lsp::LanguageServerId;
|
||||
use project::{DiagnosticSummary, Project, ProjectPath};
|
||||
use project_diagnostics_settings::ProjectDiagnosticsSettings;
|
||||
use serde_json::json;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
@ -30,18 +33,21 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
use theme::ThemeSettings;
|
||||
pub use toolbar_controls::ToolbarControls;
|
||||
use util::TryFutureExt;
|
||||
use workspace::{
|
||||
item::{BreadcrumbText, Item, ItemEvent, ItemHandle},
|
||||
ItemNavHistory, Pane, PaneBackdrop, ToolbarItemLocation, Workspace,
|
||||
};
|
||||
|
||||
actions!(diagnostics, [Deploy]);
|
||||
actions!(diagnostics, [Deploy, ToggleWarnings]);
|
||||
|
||||
const CONTEXT_LINE_COUNT: u32 = 1;
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
settings::register::<ProjectDiagnosticsSettings>(cx);
|
||||
cx.add_action(ProjectDiagnosticsEditor::deploy);
|
||||
cx.add_action(ProjectDiagnosticsEditor::toggle_warnings);
|
||||
items::init(cx);
|
||||
}
|
||||
|
||||
@ -55,6 +61,7 @@ struct ProjectDiagnosticsEditor {
|
||||
excerpts: ModelHandle<MultiBuffer>,
|
||||
path_states: Vec<PathState>,
|
||||
paths_to_update: BTreeSet<(ProjectPath, LanguageServerId)>,
|
||||
include_warnings: bool,
|
||||
}
|
||||
|
||||
struct PathState {
|
||||
@ -187,6 +194,7 @@ impl ProjectDiagnosticsEditor {
|
||||
editor,
|
||||
path_states: Default::default(),
|
||||
paths_to_update,
|
||||
include_warnings: settings::get::<ProjectDiagnosticsSettings>(cx).include_warnings,
|
||||
};
|
||||
this.update_excerpts(None, cx);
|
||||
this
|
||||
@ -204,6 +212,18 @@ impl ProjectDiagnosticsEditor {
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext<Self>) {
|
||||
self.include_warnings = !self.include_warnings;
|
||||
self.paths_to_update = self
|
||||
.project
|
||||
.read(cx)
|
||||
.diagnostic_summaries(cx)
|
||||
.map(|(path, server_id, _)| (path, server_id))
|
||||
.collect();
|
||||
self.update_excerpts(None, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn update_excerpts(
|
||||
&mut self,
|
||||
language_server_id: Option<LanguageServerId>,
|
||||
@ -277,14 +297,18 @@ impl ProjectDiagnosticsEditor {
|
||||
let mut blocks_to_add = Vec::new();
|
||||
let mut blocks_to_remove = HashSet::default();
|
||||
let mut first_excerpt_id = None;
|
||||
let max_severity = if self.include_warnings {
|
||||
DiagnosticSeverity::WARNING
|
||||
} else {
|
||||
DiagnosticSeverity::ERROR
|
||||
};
|
||||
let excerpts_snapshot = self.excerpts.update(cx, |excerpts, excerpts_cx| {
|
||||
let mut old_groups = path_state.diagnostic_groups.iter().enumerate().peekable();
|
||||
let mut new_groups = snapshot
|
||||
.diagnostic_groups(language_server_id)
|
||||
.into_iter()
|
||||
.filter(|(_, group)| {
|
||||
group.entries[group.primary_ix].diagnostic.severity
|
||||
<= DiagnosticSeverity::WARNING
|
||||
group.entries[group.primary_ix].diagnostic.severity <= max_severity
|
||||
})
|
||||
.peekable();
|
||||
loop {
|
||||
@ -1501,6 +1525,7 @@ mod tests {
|
||||
client::init_settings(cx);
|
||||
workspace::init_settings(cx);
|
||||
Project::init_settings(cx);
|
||||
crate::init(cx);
|
||||
});
|
||||
}
|
||||
|
||||
|
28
crates/diagnostics/src/project_diagnostics_settings.rs
Normal file
28
crates/diagnostics/src/project_diagnostics_settings.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ProjectDiagnosticsSettings {
|
||||
pub include_warnings: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
pub struct ProjectDiagnosticsSettingsContent {
|
||||
include_warnings: Option<bool>,
|
||||
}
|
||||
|
||||
impl settings::Setting for ProjectDiagnosticsSettings {
|
||||
const KEY: Option<&'static str> = Some("diagnostics");
|
||||
type FileContent = ProjectDiagnosticsSettingsContent;
|
||||
|
||||
fn load(
|
||||
default_value: &Self::FileContent,
|
||||
user_values: &[&Self::FileContent],
|
||||
_cx: &gpui::AppContext,
|
||||
) -> anyhow::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self::load_via_json_merge(default_value, user_values)
|
||||
}
|
||||
}
|
115
crates/diagnostics/src/toolbar_controls.rs
Normal file
115
crates/diagnostics/src/toolbar_controls.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use crate::{ProjectDiagnosticsEditor, ToggleWarnings};
|
||||
use gpui::{
|
||||
elements::*,
|
||||
platform::{CursorStyle, MouseButton},
|
||||
Action, Entity, EventContext, View, ViewContext, WeakViewHandle,
|
||||
};
|
||||
use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView};
|
||||
|
||||
pub struct ToolbarControls {
|
||||
editor: Option<WeakViewHandle<ProjectDiagnosticsEditor>>,
|
||||
}
|
||||
|
||||
impl Entity for ToolbarControls {
|
||||
type Event = ();
|
||||
}
|
||||
|
||||
impl View for ToolbarControls {
|
||||
fn ui_name() -> &'static str {
|
||||
"ToolbarControls"
|
||||
}
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
let include_warnings = self
|
||||
.editor
|
||||
.as_ref()
|
||||
.and_then(|editor| editor.upgrade(cx))
|
||||
.map(|editor| editor.read(cx).include_warnings)
|
||||
.unwrap_or(false);
|
||||
let tooltip = if include_warnings {
|
||||
"Exclude Warnings".into()
|
||||
} else {
|
||||
"Include Warnings".into()
|
||||
};
|
||||
Flex::row()
|
||||
.with_child(render_toggle_button(
|
||||
0,
|
||||
"icons/warning.svg",
|
||||
include_warnings,
|
||||
(tooltip, Some(Box::new(ToggleWarnings))),
|
||||
cx,
|
||||
move |this, cx| {
|
||||
if let Some(editor) = this.editor.and_then(|editor| editor.upgrade(cx)) {
|
||||
editor.update(cx, |editor, cx| {
|
||||
editor.toggle_warnings(&Default::default(), cx)
|
||||
});
|
||||
}
|
||||
},
|
||||
))
|
||||
.into_any()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolbarItemView for ToolbarControls {
|
||||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
active_pane_item: Option<&dyn ItemHandle>,
|
||||
_: &mut ViewContext<Self>,
|
||||
) -> ToolbarItemLocation {
|
||||
if let Some(pane_item) = active_pane_item.as_ref() {
|
||||
if let Some(editor) = pane_item.downcast::<ProjectDiagnosticsEditor>() {
|
||||
self.editor = Some(editor.downgrade());
|
||||
ToolbarItemLocation::PrimaryRight { flex: None }
|
||||
} else {
|
||||
ToolbarItemLocation::Hidden
|
||||
}
|
||||
} else {
|
||||
ToolbarItemLocation::Hidden
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolbarControls {
|
||||
pub fn new() -> Self {
|
||||
ToolbarControls { editor: None }
|
||||
}
|
||||
}
|
||||
|
||||
fn render_toggle_button<
|
||||
F: 'static + Fn(&mut ToolbarControls, &mut EventContext<ToolbarControls>),
|
||||
>(
|
||||
index: usize,
|
||||
icon: &'static str,
|
||||
toggled: bool,
|
||||
tooltip: (String, Option<Box<dyn Action>>),
|
||||
cx: &mut ViewContext<ToolbarControls>,
|
||||
on_click: F,
|
||||
) -> AnyElement<ToolbarControls> {
|
||||
enum Button {}
|
||||
|
||||
let theme = theme::current(cx);
|
||||
let (tooltip_text, action) = tooltip;
|
||||
|
||||
MouseEventHandler::new::<Button, _>(index, cx, |mouse_state, _| {
|
||||
let style = theme
|
||||
.workspace
|
||||
.toolbar
|
||||
.toggleable_tool
|
||||
.in_state(toggled)
|
||||
.style_for(mouse_state);
|
||||
Svg::new(icon)
|
||||
.with_color(style.color)
|
||||
.constrained()
|
||||
.with_width(style.icon_width)
|
||||
.aligned()
|
||||
.constrained()
|
||||
.with_width(style.button_width)
|
||||
.with_height(style.button_width)
|
||||
.contained()
|
||||
.with_style(style.container)
|
||||
})
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(MouseButton::Left, move |_, view, cx| on_click(view, cx))
|
||||
.with_tooltip::<Button>(index, tooltip_text, action, theme.tooltip.clone(), cx)
|
||||
.into_any_named("quick action bar button")
|
||||
}
|
@ -275,6 +275,10 @@ pub fn initialize_workspace(
|
||||
QuickActionBar::new(buffer_search_bar, workspace)
|
||||
});
|
||||
toolbar.add_item(quick_action_bar, cx);
|
||||
let diagnostic_editor_controls = cx.add_view(|_| {
|
||||
diagnostics::ToolbarControls::new()
|
||||
});
|
||||
toolbar.add_item(diagnostic_editor_controls, cx);
|
||||
let project_search_bar = cx.add_view(|_| ProjectSearchBar::new());
|
||||
toolbar.add_item(project_search_bar, cx);
|
||||
let submit_feedback_button =
|
||||
|
Loading…
Reference in New Issue
Block a user