From f603d682cdc8e122361de99ac3bdca77c96b6b28 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 27 Sep 2023 17:47:19 -0600 Subject: [PATCH] Add an include/exclude warnings toggle in project diagnostics --- crates/diagnostics/src/diagnostics.rs | 27 ++++- crates/diagnostics/src/toolbar_controls.rs | 115 +++++++++++++++++++++ crates/zed/src/zed.rs | 4 + 3 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 crates/diagnostics/src/toolbar_controls.rs diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index ac45bcbb79..4a2d8cbb78 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -1,4 +1,5 @@ pub mod items; +mod toolbar_controls; use anyhow::Result; use collections::{BTreeSet, HashSet}; @@ -30,18 +31,20 @@ 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) { cx.add_action(ProjectDiagnosticsEditor::deploy); + cx.add_action(ProjectDiagnosticsEditor::toggle_warnings); items::init(cx); } @@ -55,6 +58,7 @@ struct ProjectDiagnosticsEditor { excerpts: ModelHandle, path_states: Vec, paths_to_update: BTreeSet<(ProjectPath, LanguageServerId)>, + include_warnings: bool, } struct PathState { @@ -187,6 +191,7 @@ impl ProjectDiagnosticsEditor { editor, path_states: Default::default(), paths_to_update, + include_warnings: true, }; this.update_excerpts(None, cx); this @@ -204,6 +209,18 @@ impl ProjectDiagnosticsEditor { } } + fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext) { + 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, @@ -277,14 +294,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 { diff --git a/crates/diagnostics/src/toolbar_controls.rs b/crates/diagnostics/src/toolbar_controls.rs new file mode 100644 index 0000000000..421571eede --- /dev/null +++ b/crates/diagnostics/src/toolbar_controls.rs @@ -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>, +} + +impl Entity for ToolbarControls { + type Event = (); +} + +impl View for ToolbarControls { + fn ui_name() -> &'static str { + "ToolbarControls" + } + + fn render(&mut self, cx: &mut ViewContext) -> AnyElement { + 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, + ) -> ToolbarItemLocation { + if let Some(pane_item) = active_pane_item.as_ref() { + if let Some(editor) = pane_item.downcast::() { + 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), +>( + index: usize, + icon: &'static str, + toggled: bool, + tooltip: (String, Option>), + cx: &mut ViewContext, + on_click: F, +) -> AnyElement { + enum Button {} + + let theme = theme::current(cx); + let (tooltip_text, action) = tooltip; + + MouseEventHandler::new::(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::