toolbar_controls.rs

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