1use std::sync::Arc;
2
3use crate::{ProjectDiagnosticsEditor, ToggleDiagnosticsRefresh};
4use gpui::{Context, Entity, EventEmitter, ParentElement, Render, WeakEntity, Window};
5use ui::prelude::*;
6use ui::{IconButton, IconButtonShape, IconName, Tooltip};
7use workspace::{ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, item::ItemHandle};
8
9pub struct ToolbarControls {
10 editor: Option<WeakEntity<ProjectDiagnosticsEditor>>,
11}
12
13impl Render for ToolbarControls {
14 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
15 let mut include_warnings = false;
16 let mut has_stale_excerpts = false;
17 let mut is_updating = false;
18 let cargo_diagnostics_sources = Arc::new(self.diagnostics().map_or(Vec::new(), |editor| {
19 editor.read(cx).cargo_diagnostics_sources(cx)
20 }));
21 let fetch_cargo_diagnostics = !cargo_diagnostics_sources.is_empty();
22
23 if let Some(editor) = self.diagnostics() {
24 let diagnostics = editor.read(cx);
25 include_warnings = diagnostics.include_warnings;
26 has_stale_excerpts = !diagnostics.paths_to_update.is_empty();
27 is_updating = if fetch_cargo_diagnostics {
28 diagnostics.cargo_diagnostics_fetch.fetch_task.is_some()
29 } else {
30 diagnostics.update_excerpts_task.is_some()
31 || diagnostics
32 .project
33 .read(cx)
34 .language_servers_running_disk_based_diagnostics(cx)
35 .next()
36 .is_some()
37 };
38 }
39
40 let tooltip = if include_warnings {
41 "Exclude Warnings"
42 } else {
43 "Include Warnings"
44 };
45
46 let warning_color = if include_warnings {
47 Color::Warning
48 } else {
49 Color::Muted
50 };
51
52 h_flex()
53 .gap_1()
54 .map(|div| {
55 if is_updating {
56 div.child(
57 IconButton::new("stop-updating", IconName::Stop)
58 .icon_color(Color::Info)
59 .shape(IconButtonShape::Square)
60 .tooltip(Tooltip::for_action_title(
61 "Stop diagnostics update",
62 &ToggleDiagnosticsRefresh,
63 ))
64 .on_click(cx.listener(move |toolbar_controls, _, _, cx| {
65 if let Some(diagnostics) = toolbar_controls.diagnostics() {
66 diagnostics.update(cx, |diagnostics, cx| {
67 diagnostics.stop_cargo_diagnostics_fetch(cx);
68 diagnostics.update_excerpts_task = None;
69 cx.notify();
70 });
71 }
72 })),
73 )
74 } else {
75 div.child(
76 IconButton::new("refresh-diagnostics", IconName::ArrowCircle)
77 .icon_color(Color::Info)
78 .shape(IconButtonShape::Square)
79 .disabled(!has_stale_excerpts && !fetch_cargo_diagnostics)
80 .tooltip(Tooltip::for_action_title(
81 "Refresh diagnostics",
82 &ToggleDiagnosticsRefresh,
83 ))
84 .on_click(cx.listener({
85 move |toolbar_controls, _, window, cx| {
86 if let Some(diagnostics) = toolbar_controls.diagnostics() {
87 let cargo_diagnostics_sources =
88 Arc::clone(&cargo_diagnostics_sources);
89 diagnostics.update(cx, move |diagnostics, cx| {
90 if fetch_cargo_diagnostics {
91 diagnostics.fetch_cargo_diagnostics(
92 cargo_diagnostics_sources,
93 cx,
94 );
95 } else {
96 diagnostics.update_all_excerpts(window, cx);
97 }
98 });
99 }
100 }
101 })),
102 )
103 }
104 })
105 .child(
106 IconButton::new("toggle-warnings", IconName::Warning)
107 .icon_color(warning_color)
108 .shape(IconButtonShape::Square)
109 .tooltip(Tooltip::text(tooltip))
110 .on_click(cx.listener(|this, _, window, cx| {
111 if let Some(editor) = this.diagnostics() {
112 editor.update(cx, |editor, cx| {
113 editor.toggle_warnings(&Default::default(), window, cx);
114 });
115 }
116 })),
117 )
118 }
119}
120
121impl EventEmitter<ToolbarItemEvent> for ToolbarControls {}
122
123impl ToolbarItemView for ToolbarControls {
124 fn set_active_pane_item(
125 &mut self,
126 active_pane_item: Option<&dyn ItemHandle>,
127 _window: &mut Window,
128 _: &mut Context<Self>,
129 ) -> ToolbarItemLocation {
130 if let Some(pane_item) = active_pane_item.as_ref() {
131 if let Some(editor) = pane_item.downcast::<ProjectDiagnosticsEditor>() {
132 self.editor = Some(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 diagnostics(&self) -> Option<Entity<ProjectDiagnosticsEditor>> {
155 self.editor.as_ref()?.upgrade()
156 }
157}