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