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