Cargo.lock 🔗
@@ -11474,6 +11474,7 @@ dependencies = [
"copilot2",
"ctor",
"db2",
+ "diagnostics2",
"editor2",
"env_logger 0.9.3",
"feature_flags2",
Julia created
Cargo.lock | 1
crates/command_palette2/src/command_palette.rs | 1
crates/diagnostics2/src/diagnostics.rs | 67 ++++++------
crates/diagnostics2/src/items.rs | 43 ++++++-
crates/diagnostics2/src/toolbar_controls.rs | 102 ++++---------------
crates/ui2/src/components/icon.rs | 2
crates/zed2/Cargo.toml | 2
crates/zed2/src/main.rs | 1
crates/zed2/src/zed2.rs | 8
9 files changed, 100 insertions(+), 127 deletions(-)
@@ -11474,6 +11474,7 @@ dependencies = [
"copilot2",
"ctor",
"db2",
+ "diagnostics2",
"editor2",
"env_logger 0.9.3",
"feature_flags2",
@@ -116,6 +116,7 @@ impl Clone for Command {
}
}
}
+
/// Hit count for each command in the palette.
/// We only account for commands triggered directly via command palette and not by e.g. keystrokes because
/// if an user already knows a keystroke for a command, they are unlikely to use a command palette to look for it.
@@ -14,8 +14,9 @@ use editor::{
use futures::future::try_join_all;
use gpui::{
actions, div, AnyElement, AnyView, AppContext, Component, Context, Div, EventEmitter,
- FocusHandle, InteractiveComponent, Model, ParentComponent, Render, SharedString, Styled,
- Subscription, Task, View, ViewContext, VisualContext, WeakView,
+ FocusEvent, FocusHandle, Focusable, FocusableComponent, InteractiveComponent, Model,
+ ParentComponent, Render, SharedString, Styled, Subscription, Task, View, ViewContext,
+ VisualContext, WeakView,
};
use language::{
Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
@@ -48,9 +49,8 @@ const CONTEXT_LINE_COUNT: u32 = 1;
pub fn init(cx: &mut AppContext) {
ProjectDiagnosticsSettings::register(cx);
- // todo!()
- // cx.add_action(ProjectDiagnosticsEditor::deploy);
- // cx.add_action(ProjectDiagnosticsEditor::toggle_warnings);
+ cx.observe_new_views(ProjectDiagnosticsEditor::register)
+ .detach();
}
struct ProjectDiagnosticsEditor {
@@ -91,39 +91,34 @@ struct DiagnosticGroupState {
impl EventEmitter<ItemEvent> for ProjectDiagnosticsEditor {}
impl Render for ProjectDiagnosticsEditor {
- type Element = Div<Self>;
+ type Element = Focusable<Self, Div<Self>>;
+
+ fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
+ let child = if self.path_states.is_empty() {
+ div()
+ .flex()
+ .items_center()
+ .justify_center()
+ .size_full()
+ .child(Label::new("No problems in workspace"))
+ } else {
+ div().size_full().child(self.editor.clone())
+ };
- fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
- div().size_full().bg(gpui::red())
+ div()
+ .track_focus(&self.focus_handle)
+ .size_full()
+ .on_focus_in(Self::focus_in)
+ .on_action(Self::toggle_warnings)
+ .child(child)
}
}
-// impl View for ProjectDiagnosticsEditor {
-// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-// if self.path_states.is_empty() {
-// let theme = &theme::current(cx).project_diagnostics;
-// PaneBackdrop::new(
-// cx.view_id(),
-// Label::new("No problems in workspace", theme.empty_message.clone())
-// .aligned()
-// .contained()
-// .with_style(theme.container)
-// .into_any(),
-// )
-// .into_any()
-// } else {
-// ChildView::new(&self.editor, cx).into_any()
-// }
-// }
-
-// fn focus_in(&mut self, _: AnyView, cx: &mut ViewContext<Self>) {
-// if cx.is_self_focused() && !self.path_states.is_empty() {
-// cx.focus(&self.editor);
-// }
-// }
-// }
-
impl ProjectDiagnosticsEditor {
+ fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
+ workspace.register_action(Self::deploy);
+ }
+
fn new(
project_handle: Model<Project>,
workspace: WeakView<Workspace>,
@@ -240,6 +235,12 @@ impl ProjectDiagnosticsEditor {
cx.notify();
}
+ fn focus_in(&mut self, _: &FocusEvent, cx: &mut ViewContext<Self>) {
+ if self.focus_handle.is_focused(cx) && !self.path_states.is_empty() {
+ self.editor.focus_handle(cx).focus(cx)
+ }
+ }
+
fn update_excerpts(
&mut self,
language_server_id: Option<LanguageServerId>,
@@ -1,20 +1,18 @@
use collections::HashSet;
use editor::{Editor, GoToDiagnostic};
use gpui::{
- div, serde_json, AppContext, CursorStyle, Div, Entity, EventEmitter, MouseButton, Render,
- Styled, Subscription, View, ViewContext, WeakView,
+ div, serde_json, svg, AppContext, CursorStyle, Div, Entity, EventEmitter, InteractiveComponent,
+ MouseButton, ParentComponent, Render, Stateful, Styled, Subscription, Svg, View, ViewContext,
+ WeakView,
};
use language::Diagnostic;
use lsp::LanguageServerId;
+use theme::ActiveTheme;
+use ui::{Icon, IconElement, Label, TextColor};
use workspace::{item::ItemHandle, StatusItemView, ToolbarItemEvent, Workspace};
use crate::ProjectDiagnosticsEditor;
-// todo!()
-// pub fn init(cx: &mut AppContext) {
-// cx.add_action(DiagnosticIndicator::go_to_next_diagnostic);
-// }
-
pub struct DiagnosticIndicator {
summary: project::DiagnosticSummary,
active_editor: Option<WeakView<Editor>>,
@@ -25,10 +23,33 @@ pub struct DiagnosticIndicator {
}
impl Render for DiagnosticIndicator {
- type Element = Div<Self>;
+ type Element = Stateful<Self, Div<Self>>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
- div().size_full().bg(gpui::red())
+ let mut summary_row = div().flex().flex_row().size_full();
+
+ if self.summary.error_count > 0 {
+ summary_row =
+ summary_row.child(IconElement::new(Icon::XCircle).color(TextColor::Error));
+ summary_row = summary_row.child(Label::new(self.summary.error_count.to_string()));
+ }
+
+ if self.summary.warning_count > 0 {
+ summary_row = summary_row
+ .child(IconElement::new(Icon::ExclamationTriangle).color(TextColor::Warning));
+ summary_row = summary_row.child(Label::new(self.summary.warning_count.to_string()));
+ }
+
+ if self.summary.error_count == 0 && self.summary.warning_count == 0 {
+ summary_row =
+ summary_row.child(IconElement::new(Icon::Check).color(TextColor::Success));
+ }
+
+ div()
+ .id(cx.entity_id())
+ .on_action(Self::go_to_next_diagnostic)
+ .size_full()
+ .child(summary_row)
}
}
@@ -40,19 +61,23 @@ impl DiagnosticIndicator {
this.in_progress_checks.insert(*language_server_id);
cx.notify();
}
+
project::Event::DiskBasedDiagnosticsFinished { language_server_id }
| project::Event::LanguageServerRemoved(language_server_id) => {
this.summary = project.read(cx).diagnostic_summary(cx);
this.in_progress_checks.remove(language_server_id);
cx.notify();
}
+
project::Event::DiagnosticsUpdated { .. } => {
this.summary = project.read(cx).diagnostic_summary(cx);
cx.notify();
}
+
_ => {}
})
.detach();
+
Self {
summary: project.read(cx).diagnostic_summary(cx),
in_progress_checks: project
@@ -14,50 +14,35 @@ impl Render for ToolbarControls {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
- div()
- .h_flex()
- .child(IconButton::new("toggle-warnings", Icon::Warning).on_click(|view, cx| todo!()))
+ let include_warnings = self
+ .editor
+ .as_ref()
+ .and_then(|editor| editor.upgrade())
+ .map(|editor| editor.read(cx).include_warnings)
+ .unwrap_or(false);
+
+ let tooltip = if include_warnings {
+ "Exclude Warnings"
+ } else {
+ "Include Warnings"
+ };
+
+ div().child(
+ IconButton::new("toggle-warnings", Icon::ExclamationTriangle)
+ .tooltip(tooltip)
+ .on_click(|this: &mut Self, cx| {
+ if let Some(editor) = this.editor.as_ref().and_then(|editor| editor.upgrade()) {
+ editor.update(cx, |editor, cx| {
+ editor.toggle_warnings(&Default::default(), cx);
+ });
+ }
+ }),
+ )
}
}
impl EventEmitter<ToolbarItemEvent> for ToolbarControls {}
-// impl View for ToolbarControls {
-// fn ui_name() -> &'static str {
-// "ToolbarControls"
-// }
-
-// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-// let include_warnings = self
-// .editor
-// .as_ref()
-// .and_then(|editor| editor.upgrade(cx))
-// .map(|editor| editor.read(cx).include_warnings)
-// .unwrap_or(false);
-// let tooltip = if include_warnings {
-// "Exclude Warnings".into()
-// } else {
-// "Include Warnings".into()
-// };
-// Flex::row()
-// .with_child(render_toggle_button(
-// 0,
-// "icons/warning.svg",
-// include_warnings,
-// (tooltip, Some(Box::new(ToggleWarnings))),
-// cx,
-// move |this, cx| {
-// if let Some(editor) = this.editor.and_then(|editor| editor.upgrade(cx)) {
-// editor.update(cx, |editor, cx| {
-// editor.toggle_warnings(&Default::default(), cx)
-// });
-// }
-// },
-// ))
-// .into_any()
-// }
-// }
-
impl ToolbarItemView for ToolbarControls {
fn set_active_pane_item(
&mut self,
@@ -82,42 +67,3 @@ impl ToolbarControls {
ToolbarControls { editor: None }
}
}
-
-// fn render_toggle_button<
-// F: 'static + Fn(&mut ToolbarControls, &mut EventContext<ToolbarControls>),
-// >(
-// index: usize,
-// icon: &'static str,
-// toggled: bool,
-// tooltip: (String, Option<Box<dyn Action>>),
-// cx: &mut ViewContext<ToolbarControls>,
-// on_click: F,
-// ) -> AnyElement<ToolbarControls> {
-// enum Button {}
-
-// let theme = theme::current(cx);
-// let (tooltip_text, action) = tooltip;
-
-// MouseEventHandler::new::<Button, _>(index, cx, |mouse_state, _| {
-// let style = theme
-// .workspace
-// .toolbar
-// .toggleable_tool
-// .in_state(toggled)
-// .style_for(mouse_state);
-// Svg::new(icon)
-// .with_color(style.color)
-// .constrained()
-// .with_width(style.icon_width)
-// .aligned()
-// .constrained()
-// .with_width(style.button_width)
-// .with_height(style.button_width)
-// .contained()
-// .with_style(style.container)
-// })
-// .with_cursor_style(CursorStyle::PointingHand)
-// .on_click(MouseButton::Left, move |_, view, cx| on_click(view, cx))
-// .with_tooltip::<Button>(index, tooltip_text, action, theme.tooltip.clone(), cx)
-// .into_any_named("quick action bar button")
-// }
@@ -64,7 +64,6 @@ pub enum Icon {
Split,
SplitMessage,
Terminal,
- Warning,
XCircle,
}
@@ -123,7 +122,6 @@ impl Icon {
Icon::Split => "icons/split.svg",
Icon::SplitMessage => "icons/split_message.svg",
Icon::Terminal => "icons/terminal.svg",
- Icon::Warning => "icons/warning.svg",
Icon::XCircle => "icons/error.svg",
}
}
@@ -32,7 +32,7 @@ client = { package = "client2", path = "../client2" }
# clock = { path = "../clock" }
copilot = { package = "copilot2", path = "../copilot2" }
# copilot_button = { path = "../copilot_button" }
-# diagnostics = { path = "../diagnostics" }
+diagnostics = { package = "diagnostics2", path = "../diagnostics2" }
db = { package = "db2", path = "../db2" }
editor = { package="editor2", path = "../editor2" }
# feedback = { path = "../feedback" }
@@ -147,6 +147,7 @@ fn main() {
command_palette::init(cx);
language::init(cx);
editor::init(cx);
+ diagnostics::init(cx);
copilot::init(
copilot_language_server_id,
http.clone(),
@@ -314,8 +314,8 @@ pub fn initialize_workspace(
// QuickActionBar::new(buffer_search_bar, workspace)
// });
// toolbar.add_item(quick_action_bar, cx);
- // let diagnostic_editor_controls =
- // cx.add_view(|_| diagnostics2::ToolbarControls::new());
+ let diagnostic_editor_controls =
+ cx.build_view(|_| diagnostics::ToolbarControls::new());
// toolbar.add_item(diagnostic_editor_controls, cx);
// let project_search_bar = cx.add_view(|_| ProjectSearchBar::new());
// toolbar.add_item(project_search_bar, cx);
@@ -347,8 +347,8 @@ pub fn initialize_workspace(
// let copilot =
// cx.add_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx));
- // let diagnostic_summary =
- // cx.add_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
+ let diagnostic_summary =
+ cx.build_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
// let activity_indicator = activity_indicator::ActivityIndicator::new(
// workspace,
// app_state.languages.clone(),