diff --git a/Cargo.lock b/Cargo.lock
index 7322436f51..e69eb264ba 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4300,6 +4300,7 @@ dependencies = [
"sysinfo",
"task",
"tasks_ui",
+ "telemetry",
"terminal_view",
"theme",
"tree-sitter",
diff --git a/assets/images/debugger_grid.svg b/assets/images/debugger_grid.svg
new file mode 100644
index 0000000000..8b40dbd707
--- /dev/null
+++ b/assets/images/debugger_grid.svg
@@ -0,0 +1,890 @@
+
diff --git a/crates/debugger_ui/Cargo.toml b/crates/debugger_ui/Cargo.toml
index 17570bd3d9..e259b8a4b3 100644
--- a/crates/debugger_ui/Cargo.toml
+++ b/crates/debugger_ui/Cargo.toml
@@ -57,6 +57,7 @@ shlex.workspace = true
sysinfo.workspace = true
task.workspace = true
tasks_ui.workspace = true
+telemetry.workspace = true
terminal_view.workspace = true
theme.workspace = true
tree-sitter.workspace = true
diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs
index 159f97a3cd..12f0c78b43 100644
--- a/crates/debugger_ui/src/debugger_panel.rs
+++ b/crates/debugger_ui/src/debugger_panel.rs
@@ -19,7 +19,7 @@ use dap::{DapRegistry, StartDebuggingRequestArguments};
use gpui::{
Action, App, AsyncWindowContext, ClipboardItem, Context, DismissEvent, Entity, EntityId,
EventEmitter, FocusHandle, Focusable, MouseButton, MouseDownEvent, Point, Subscription, Task,
- WeakEntity, actions, anchored, deferred,
+ WeakEntity, anchored, deferred,
};
use itertools::Itertools as _;
@@ -39,6 +39,7 @@ use workspace::{
Pane, Workspace,
dock::{DockPosition, Panel, PanelEvent},
};
+use zed_actions::ToggleFocus;
pub enum DebugPanelEvent {
Exited(SessionId),
@@ -57,8 +58,6 @@ pub enum DebugPanelEvent {
CapabilitiesChanged(SessionId),
}
-actions!(debug_panel, [ToggleFocus]);
-
pub struct DebugPanel {
size: Pixels,
sessions: Vec>,
diff --git a/crates/debugger_ui/src/debugger_ui.rs b/crates/debugger_ui/src/debugger_ui.rs
index 69ef35e7d7..ade1308f06 100644
--- a/crates/debugger_ui/src/debugger_ui.rs
+++ b/crates/debugger_ui/src/debugger_ui.rs
@@ -1,10 +1,11 @@
use std::any::TypeId;
use dap::debugger_settings::DebuggerSettings;
-use debugger_panel::{DebugPanel, ToggleFocus};
+use debugger_panel::DebugPanel;
use editor::Editor;
use gpui::{App, DispatchPhase, EntityInputHandler, actions};
use new_process_modal::{NewProcessModal, NewProcessMode};
+use onboarding_modal::DebuggerOnboardingModal;
use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::ThreadStatus};
use session::DebugSession;
use settings::Settings;
@@ -13,11 +14,14 @@ use tasks_ui::{Spawn, TaskOverrides};
use ui::{FluentBuilder, InteractiveElement};
use util::maybe;
use workspace::{ItemHandle, ShutdownDebugAdapters, Workspace};
+use zed_actions::ToggleFocus;
+use zed_actions::debugger::OpenOnboardingModal;
pub mod attach_modal;
pub mod debugger_panel;
mod dropdown_menus;
mod new_process_modal;
+mod onboarding_modal;
mod persistence;
pub(crate) mod session;
mod stack_trace_view;
@@ -90,6 +94,9 @@ pub fn init(cx: &mut App) {
})
},
)
+ .register_action(|workspace, _: &OpenOnboardingModal, window, cx| {
+ DebuggerOnboardingModal::toggle(workspace, window, cx)
+ })
.register_action_renderer(|div, workspace, _, cx| {
let Some(debug_panel) = workspace.panel::(cx) else {
return div;
diff --git a/crates/debugger_ui/src/onboarding_modal.rs b/crates/debugger_ui/src/onboarding_modal.rs
new file mode 100644
index 0000000000..c9fa009940
--- /dev/null
+++ b/crates/debugger_ui/src/onboarding_modal.rs
@@ -0,0 +1,166 @@
+use gpui::{
+ ClickEvent, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, MouseDownEvent, Render,
+};
+use ui::{TintColor, Vector, VectorName, prelude::*};
+use workspace::{ModalView, Workspace};
+
+use crate::DebugPanel;
+
+macro_rules! debugger_onboarding_event {
+ ($name:expr) => {
+ telemetry::event!($name, source = "Debugger Onboarding");
+ };
+ ($name:expr, $($key:ident $(= $value:expr)?),+ $(,)?) => {
+ telemetry::event!($name, source = "Debugger Onboarding", $($key $(= $value)?),+);
+ };
+}
+
+pub struct DebuggerOnboardingModal {
+ focus_handle: FocusHandle,
+ workspace: Entity,
+}
+
+impl DebuggerOnboardingModal {
+ pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context) {
+ let workspace_entity = cx.entity();
+ workspace.toggle_modal(window, cx, |_window, cx| Self {
+ workspace: workspace_entity,
+ focus_handle: cx.focus_handle(),
+ });
+ }
+
+ fn open_panel(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context) {
+ self.workspace.update(cx, |workspace, cx| {
+ workspace.focus_panel::(window, cx);
+ });
+
+ cx.emit(DismissEvent);
+
+ debugger_onboarding_event!("Open Panel Clicked");
+ }
+
+ fn view_blog(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context) {
+ cx.open_url("http://zed.dev/blog/debugger");
+ cx.notify();
+
+ debugger_onboarding_event!("Blog Link Clicked");
+ }
+
+ fn cancel(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context) {
+ cx.emit(DismissEvent);
+ }
+}
+
+impl EventEmitter for DebuggerOnboardingModal {}
+
+impl Focusable for DebuggerOnboardingModal {
+ fn focus_handle(&self, _cx: &App) -> FocusHandle {
+ self.focus_handle.clone()
+ }
+}
+
+impl ModalView for DebuggerOnboardingModal {}
+
+impl Render for DebuggerOnboardingModal {
+ fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement {
+ let window_height = window.viewport_size().height;
+ let max_height = window_height - px(200.);
+
+ let base = v_flex()
+ .id("debugger-onboarding")
+ .key_context("DebuggerOnboardingModal")
+ .relative()
+ .w(px(450.))
+ .h_full()
+ .max_h(max_height)
+ .p_4()
+ .gap_2()
+ .elevation_3(cx)
+ .track_focus(&self.focus_handle(cx))
+ .overflow_hidden()
+ .on_action(cx.listener(Self::cancel))
+ .on_action(cx.listener(|_, _: &menu::Cancel, _window, cx| {
+ debugger_onboarding_event!("Canceled", trigger = "Action");
+ cx.emit(DismissEvent);
+ }))
+ .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
+ this.focus_handle.focus(window);
+ }))
+ .child(
+ div()
+ .absolute()
+ .top(px(-8.0))
+ .right_0()
+ .w(px(400.))
+ .h(px(92.))
+ .child(
+ Vector::new(
+ VectorName::DebuggerGrid,
+ rems_from_px(400.),
+ rems_from_px(92.),
+ )
+ .color(ui::Color::Custom(cx.theme().colors().text.alpha(0.32))),
+ ),
+ )
+ .child(
+ div()
+ .absolute()
+ .inset_0()
+ .size_full()
+ .bg(gpui::linear_gradient(
+ 175.,
+ gpui::linear_color_stop(
+ cx.theme().colors().elevated_surface_background,
+ 0.,
+ ),
+ gpui::linear_color_stop(
+ cx.theme().colors().elevated_surface_background.opacity(0.),
+ 0.8,
+ ),
+ )),
+ )
+ .child(
+ v_flex()
+ .w_full()
+ .gap_1()
+ .child(
+ Label::new("Introducing")
+ .size(LabelSize::Small)
+ .color(Color::Muted),
+ )
+ .child(Headline::new("Zed's Debugger").size(HeadlineSize::Large)),
+ )
+ .child(h_flex().absolute().top_2().right_2().child(
+ IconButton::new("cancel", IconName::X).on_click(cx.listener(
+ |_, _: &ClickEvent, _window, cx| {
+ debugger_onboarding_event!("Cancelled", trigger = "X click");
+ cx.emit(DismissEvent);
+ },
+ )),
+ ));
+
+ let open_panel_button = Button::new("open-panel", "Get Started with the Debugger")
+ .icon_size(IconSize::Indicator)
+ .style(ButtonStyle::Tinted(TintColor::Accent))
+ .full_width()
+ .on_click(cx.listener(Self::open_panel));
+
+ let blog_post_button = Button::new("view-blog", "Check out the Blog Post")
+ .icon(IconName::ArrowUpRight)
+ .icon_size(IconSize::Indicator)
+ .icon_color(Color::Muted)
+ .full_width()
+ .on_click(cx.listener(Self::view_blog));
+
+ let copy = "It's finally here: Native support for debugging across multiple programming languages.";
+
+ base.child(Label::new(copy).color(Color::Muted)).child(
+ v_flex()
+ .w_full()
+ .mt_2()
+ .gap_2()
+ .child(open_panel_button)
+ .child(blog_post_button),
+ )
+ }
+}
diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs
index d5a4d50580..418bb70f8d 100644
--- a/crates/title_bar/src/title_bar.rs
+++ b/crates/title_bar/src/title_bar.rs
@@ -336,11 +336,11 @@ impl TitleBar {
let banner = cx.new(|cx| {
OnboardingBanner::new(
- "Agentic Onboarding",
- IconName::ZedAssistant,
- "Agentic Editing",
+ "Debugger Onboarding",
+ IconName::Debug,
+ "The Debugger",
None,
- zed_actions::agent::OpenOnboardingModal.boxed_clone(),
+ zed_actions::debugger::OpenOnboardingModal.boxed_clone(),
cx,
)
});
diff --git a/crates/ui/src/components/image.rs b/crates/ui/src/components/image.rs
index 38b7a9ae29..2deba68d88 100644
--- a/crates/ui/src/components/image.rs
+++ b/crates/ui/src/components/image.rs
@@ -16,6 +16,7 @@ pub enum VectorName {
ZedXCopilot,
Grid,
AiGrid,
+ DebuggerGrid,
}
impl VectorName {
diff --git a/crates/zed_actions/src/lib.rs b/crates/zed_actions/src/lib.rs
index 5c28140b11..7dd29d72fc 100644
--- a/crates/zed_actions/src/lib.rs
+++ b/crates/zed_actions/src/lib.rs
@@ -249,6 +249,12 @@ pub mod assistant {
impl_actions!(assistant, [InlineAssist]);
}
+pub mod debugger {
+ use gpui::actions;
+
+ actions!(debugger, [OpenOnboardingModal, ResetOnboarding]);
+}
+
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct OpenRecent {
@@ -349,6 +355,7 @@ pub mod outline {
actions!(zed_predict_onboarding, [OpenZedPredictOnboarding]);
actions!(git_onboarding, [OpenGitIntegrationOnboarding]);
+actions!(debug_panel, [ToggleFocus]);
actions!(
debugger,
[