toolbar_controls.rs

  1use crate::{BufferDiagnosticsEditor, ProjectDiagnosticsEditor, ToggleDiagnosticsRefresh};
  2use gpui::{Context, EventEmitter, ParentElement, Render, Window};
  3use language::DiagnosticEntry;
  4use text::{Anchor, BufferId};
  5use ui::prelude::*;
  6use ui::{IconButton, IconButtonShape, IconName, Tooltip};
  7use workspace::{ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, item::ItemHandle};
  8
  9pub struct ToolbarControls {
 10    editor: Option<Box<dyn DiagnosticsToolbarEditor>>,
 11}
 12
 13pub(crate) trait DiagnosticsToolbarEditor: Send + Sync {
 14    /// Informs the toolbar whether warnings are included in the diagnostics.
 15    fn include_warnings(&self, cx: &App) -> bool;
 16    /// Toggles whether warning diagnostics should be displayed by the
 17    /// diagnostics editor.
 18    fn toggle_warnings(&self, window: &mut Window, cx: &mut App);
 19    /// Indicates whether the diagnostics editor is currently updating the
 20    /// diagnostics.
 21    fn is_updating(&self, cx: &App) -> bool;
 22    /// Requests that the diagnostics editor stop updating the diagnostics.
 23    fn stop_updating(&self, cx: &mut App);
 24    /// Requests that the diagnostics editor updates the displayed diagnostics
 25    /// with the latest information.
 26    fn refresh_diagnostics(&self, window: &mut Window, cx: &mut App);
 27    /// Returns a list of diagnostics for the provided buffer id.
 28    fn get_diagnostics_for_buffer(
 29        &self,
 30        buffer_id: BufferId,
 31        cx: &App,
 32    ) -> Vec<DiagnosticEntry<Anchor>>;
 33}
 34
 35impl Render for ToolbarControls {
 36    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 37        let mut include_warnings = false;
 38        let mut is_updating = false;
 39
 40        match &self.editor {
 41            Some(editor) => {
 42                include_warnings = editor.include_warnings(cx);
 43                is_updating = editor.is_updating(cx);
 44            }
 45            None => {}
 46        }
 47
 48        let warning_tooltip = if include_warnings {
 49            "Exclude Warnings"
 50        } else {
 51            "Include Warnings"
 52        };
 53
 54        let warning_color = if include_warnings {
 55            Color::Warning
 56        } else {
 57            Color::Muted
 58        };
 59
 60        h_flex()
 61            .gap_1()
 62            .map(|div| {
 63                if is_updating {
 64                    div.child(
 65                        IconButton::new("stop-updating", IconName::Stop)
 66                            .icon_color(Color::Info)
 67                            .shape(IconButtonShape::Square)
 68                            .tooltip(Tooltip::for_action_title(
 69                                "Stop diagnostics update",
 70                                &ToggleDiagnosticsRefresh,
 71                            ))
 72                            .on_click(cx.listener(move |toolbar_controls, _, _, cx| {
 73                                if let Some(editor) = toolbar_controls.editor() {
 74                                    editor.stop_updating(cx);
 75                                    cx.notify();
 76                                }
 77                            })),
 78                    )
 79                } else {
 80                    div.child(
 81                        IconButton::new("refresh-diagnostics", IconName::ArrowCircle)
 82                            .icon_color(Color::Info)
 83                            .shape(IconButtonShape::Square)
 84                            .tooltip(Tooltip::for_action_title(
 85                                "Refresh diagnostics",
 86                                &ToggleDiagnosticsRefresh,
 87                            ))
 88                            .on_click(cx.listener({
 89                                move |toolbar_controls, _, window, cx| {
 90                                    if let Some(editor) = toolbar_controls.editor() {
 91                                        editor.refresh_diagnostics(window, cx)
 92                                    }
 93                                }
 94                            })),
 95                    )
 96                }
 97            })
 98            .child(
 99                IconButton::new("toggle-warnings", IconName::Warning)
100                    .icon_color(warning_color)
101                    .shape(IconButtonShape::Square)
102                    .tooltip(Tooltip::text(warning_tooltip))
103                    .on_click(cx.listener(|this, _, window, cx| {
104                        if let Some(editor) = &this.editor {
105                            editor.toggle_warnings(window, cx)
106                        }
107                    })),
108            )
109    }
110}
111
112impl EventEmitter<ToolbarItemEvent> for ToolbarControls {}
113
114impl ToolbarItemView for ToolbarControls {
115    fn set_active_pane_item(
116        &mut self,
117        active_pane_item: Option<&dyn ItemHandle>,
118        _window: &mut Window,
119        _: &mut Context<Self>,
120    ) -> ToolbarItemLocation {
121        if let Some(pane_item) = active_pane_item.as_ref() {
122            if let Some(editor) = pane_item.downcast::<ProjectDiagnosticsEditor>() {
123                self.editor = Some(Box::new(editor.downgrade()));
124                ToolbarItemLocation::PrimaryRight
125            } else if let Some(editor) = pane_item.downcast::<BufferDiagnosticsEditor>() {
126                self.editor = Some(Box::new(editor.downgrade()));
127                ToolbarItemLocation::PrimaryRight
128            } else {
129                ToolbarItemLocation::Hidden
130            }
131        } else {
132            ToolbarItemLocation::Hidden
133        }
134    }
135}
136
137impl Default for ToolbarControls {
138    fn default() -> Self {
139        Self::new()
140    }
141}
142
143impl ToolbarControls {
144    pub fn new() -> Self {
145        ToolbarControls { editor: None }
146    }
147
148    fn editor(&self) -> Option<&dyn DiagnosticsToolbarEditor> {
149        self.editor.as_deref()
150    }
151}