From 3c9fe363d583b60386e60c73029bfe802e86200e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 17 Jun 2025 13:56:19 -0600 Subject: [PATCH] debugger: Remove feature flag (#32877) Release Notes: - debugger: Now available for everyone! --- Cargo.lock | 3 - crates/debugger_ui/Cargo.toml | 1 - crates/debugger_ui/src/debugger_ui.rs | 301 +++++++++++----------- crates/editor/Cargo.toml | 1 - crates/editor/src/editor.rs | 76 +++--- crates/editor/src/element.rs | 68 +++-- crates/feature_flags/src/feature_flags.rs | 5 - crates/zed/Cargo.toml | 1 - crates/zed/src/zed.rs | 27 +- 9 files changed, 217 insertions(+), 266 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 990b052cdf..ebfa47bfd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4278,7 +4278,6 @@ dependencies = [ "db", "debugger_tools", "editor", - "feature_flags", "file_icons", "futures 0.3.31", "fuzzy", @@ -4746,7 +4745,6 @@ dependencies = [ "dap", "db", "emojis", - "feature_flags", "file_icons", "fs", "futures 0.3.31", @@ -19994,7 +19992,6 @@ dependencies = [ "extension", "extension_host", "extensions_ui", - "feature_flags", "feedback", "file_finder", "fs", diff --git a/crates/debugger_ui/Cargo.toml b/crates/debugger_ui/Cargo.toml index fc38538965..5ac4a46f14 100644 --- a/crates/debugger_ui/Cargo.toml +++ b/crates/debugger_ui/Cargo.toml @@ -35,7 +35,6 @@ dap.workspace = true dap_adapters = { workspace = true, optional = true } db.workspace = true editor.workspace = true -feature_flags.workspace = true file_icons.workspace = true futures.workspace = true fuzzy.workspace = true diff --git a/crates/debugger_ui/src/debugger_ui.rs b/crates/debugger_ui/src/debugger_ui.rs index f1caae28e0..69ef35e7d7 100644 --- a/crates/debugger_ui/src/debugger_ui.rs +++ b/crates/debugger_ui/src/debugger_ui.rs @@ -3,7 +3,6 @@ use std::any::TypeId; use dap::debugger_settings::DebuggerSettings; use debugger_panel::{DebugPanel, ToggleFocus}; use editor::Editor; -use feature_flags::{DebuggerFeatureFlag, FeatureFlagViewExt}; use gpui::{App, DispatchPhase, EntityInputHandler, actions}; use new_process_modal::{NewProcessModal, NewProcessMode}; use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::ThreadStatus}; @@ -62,173 +61,163 @@ pub fn init(cx: &mut App) { DebuggerSettings::register(cx); workspace::FollowableViewRegistry::register::(cx); - cx.observe_new(|_: &mut Workspace, window, cx| { - let Some(window) = window else { - return; - }; - - cx.when_flag_enabled::(window, |workspace, _, _| { - workspace - .register_action(spawn_task_or_modal) - .register_action(|workspace, _: &ToggleFocus, window, cx| { - workspace.toggle_panel_focus::(window, cx); - }) - .register_action(|workspace: &mut Workspace, _: &Start, window, cx| { - NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx); - }) - .register_action( - |workspace: &mut Workspace, _: &RerunLastSession, window, cx| { - let Some(debug_panel) = workspace.panel::(cx) else { - return; - }; - - debug_panel.update(cx, |debug_panel, cx| { - debug_panel.rerun_last_session(workspace, window, cx); - }) - }, - ) - .register_action( - |workspace: &mut Workspace, _: &ShutdownDebugAdapters, _window, cx| { - workspace.project().update(cx, |project, cx| { - project.dap_store().update(cx, |store, cx| { - store.shutdown_sessions(cx).detach(); - }) - }) - }, - ) - .register_action_renderer(|div, workspace, _, cx| { + cx.observe_new(|workspace: &mut Workspace, _, _| { + workspace + .register_action(spawn_task_or_modal) + .register_action(|workspace, _: &ToggleFocus, window, cx| { + workspace.toggle_panel_focus::(window, cx); + }) + .register_action(|workspace: &mut Workspace, _: &Start, window, cx| { + NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx); + }) + .register_action( + |workspace: &mut Workspace, _: &RerunLastSession, window, cx| { let Some(debug_panel) = workspace.panel::(cx) else { - return div; + return; }; - let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - else { - return div; - }; - let running_state = active_item.read(cx); - if running_state.session().read(cx).is_terminated() { - return div; - } - let caps = running_state.capabilities(cx); - let supports_step_back = caps.supports_step_back.unwrap_or_default(); - let supports_detach = running_state.session().read(cx).is_attached(); - let status = running_state.thread_status(cx); - - let active_item = active_item.downgrade(); - div.when(status == Some(ThreadStatus::Running), |div| { - let active_item = active_item.clone(); - div.on_action(move |_: &Pause, _, cx| { - active_item - .update(cx, |item, cx| item.pause_thread(cx)) - .ok(); + debug_panel.update(cx, |debug_panel, cx| { + debug_panel.rerun_last_session(workspace, window, cx); + }) + }, + ) + .register_action( + |workspace: &mut Workspace, _: &ShutdownDebugAdapters, _window, cx| { + workspace.project().update(cx, |project, cx| { + project.dap_store().update(cx, |store, cx| { + store.shutdown_sessions(cx).detach(); }) }) - .when(status == Some(ThreadStatus::Stopped), |div| { - div.on_action({ - let active_item = active_item.clone(); - move |_: &StepInto, _, cx| { - active_item.update(cx, |item, cx| item.step_in(cx)).ok(); - } + }, + ) + .register_action_renderer(|div, workspace, _, cx| { + let Some(debug_panel) = workspace.panel::(cx) else { + return div; + }; + let Some(active_item) = debug_panel + .read(cx) + .active_session() + .map(|session| session.read(cx).running_state().clone()) + else { + return div; + }; + let running_state = active_item.read(cx); + if running_state.session().read(cx).is_terminated() { + return div; + } + + let caps = running_state.capabilities(cx); + let supports_step_back = caps.supports_step_back.unwrap_or_default(); + let supports_detach = running_state.session().read(cx).is_attached(); + let status = running_state.thread_status(cx); + + let active_item = active_item.downgrade(); + div.when(status == Some(ThreadStatus::Running), |div| { + let active_item = active_item.clone(); + div.on_action(move |_: &Pause, _, cx| { + active_item + .update(cx, |item, cx| item.pause_thread(cx)) + .ok(); + }) + }) + .when(status == Some(ThreadStatus::Stopped), |div| { + div.on_action({ + let active_item = active_item.clone(); + move |_: &StepInto, _, cx| { + active_item.update(cx, |item, cx| item.step_in(cx)).ok(); + } + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &StepOver, _, cx| { + active_item.update(cx, |item, cx| item.step_over(cx)).ok(); + } + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &StepOut, _, cx| { + active_item.update(cx, |item, cx| item.step_out(cx)).ok(); + } + }) + .when(supports_step_back, |div| { + let active_item = active_item.clone(); + div.on_action(move |_: &StepBack, _, cx| { + active_item.update(cx, |item, cx| item.step_back(cx)).ok(); }) - .on_action({ - let active_item = active_item.clone(); - move |_: &StepOver, _, cx| { - active_item.update(cx, |item, cx| item.step_over(cx)).ok(); - } - }) - .on_action({ - let active_item = active_item.clone(); - move |_: &StepOut, _, cx| { - active_item.update(cx, |item, cx| item.step_out(cx)).ok(); - } - }) - .when(supports_step_back, |div| { - let active_item = active_item.clone(); - div.on_action(move |_: &StepBack, _, cx| { - active_item.update(cx, |item, cx| item.step_back(cx)).ok(); - }) - }) - .on_action({ - let active_item = active_item.clone(); - move |_: &Continue, _, cx| { - active_item - .update(cx, |item, cx| item.continue_thread(cx)) - .ok(); - } - }) - .on_action(cx.listener( - |workspace, _: &ShowStackTrace, window, cx| { - let Some(debug_panel) = workspace.panel::(cx) else { + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &Continue, _, cx| { + active_item + .update(cx, |item, cx| item.continue_thread(cx)) + .ok(); + } + }) + .on_action(cx.listener( + |workspace, _: &ShowStackTrace, window, cx| { + let Some(debug_panel) = workspace.panel::(cx) else { + return; + }; + + if let Some(existing) = workspace.item_of_type::(cx) { + let is_active = workspace + .active_item(cx) + .is_some_and(|item| item.item_id() == existing.item_id()); + workspace.activate_item(&existing, true, !is_active, window, cx); + } else { + let Some(active_session) = debug_panel.read(cx).active_session() + else { return; }; - if let Some(existing) = workspace.item_of_type::(cx) - { - let is_active = workspace - .active_item(cx) - .is_some_and(|item| item.item_id() == existing.item_id()); - workspace - .activate_item(&existing, true, !is_active, window, cx); - } else { - let Some(active_session) = - debug_panel.read(cx).active_session() - else { - return; - }; + let project = workspace.project(); - let project = workspace.project(); + let stack_trace_view = active_session.update(cx, |session, cx| { + session.stack_trace_view(project, window, cx).clone() + }); - let stack_trace_view = - active_session.update(cx, |session, cx| { - session.stack_trace_view(project, window, cx).clone() - }); - - workspace.add_item_to_active_pane( - Box::new(stack_trace_view), - None, - true, - window, - cx, - ); - } - }, - )) + workspace.add_item_to_active_pane( + Box::new(stack_trace_view), + None, + true, + window, + cx, + ); + } + }, + )) + }) + .when(supports_detach, |div| { + let active_item = active_item.clone(); + div.on_action(move |_: &Detach, _, cx| { + active_item + .update(cx, |item, cx| item.detach_client(cx)) + .ok(); }) - .when(supports_detach, |div| { - let active_item = active_item.clone(); - div.on_action(move |_: &Detach, _, cx| { - active_item - .update(cx, |item, cx| item.detach_client(cx)) - .ok(); - }) - }) - .on_action({ - let active_item = active_item.clone(); - move |_: &Restart, _, cx| { - active_item - .update(cx, |item, cx| item.restart_session(cx)) - .ok(); - } - }) - .on_action({ - let active_item = active_item.clone(); - move |_: &Stop, _, cx| { - active_item.update(cx, |item, cx| item.stop_thread(cx)).ok(); - } - }) - .on_action({ - let active_item = active_item.clone(); - move |_: &ToggleIgnoreBreakpoints, _, cx| { - active_item - .update(cx, |item, cx| item.toggle_ignore_breakpoints(cx)) - .ok(); - } - }) - }); - }) + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &Restart, _, cx| { + active_item + .update(cx, |item, cx| item.restart_session(cx)) + .ok(); + } + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &Stop, _, cx| { + active_item.update(cx, |item, cx| item.stop_thread(cx)).ok(); + } + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &ToggleIgnoreBreakpoints, _, cx| { + active_item + .update(cx, |item, cx| item.toggle_ignore_breakpoints(cx)) + .ok(); + } + }) + }); }) .detach(); diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index bc901fece3..c42b58729e 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -40,7 +40,6 @@ dap.workspace = true db.workspace = true buffer_diff.workspace = true emojis.workspace = true -feature_flags.workspace = true file_icons.workspace = true futures.workspace = true fuzzy.workspace = true diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index e99fe7fc98..8493c80583 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -73,7 +73,6 @@ use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layo pub use element::{ CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition, }; -use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt}; use futures::{ FutureExt, StreamExt as _, future::{self, Shared, join}, @@ -5969,45 +5968,41 @@ impl Editor { buffer: &Entity, cx: &mut App, ) -> Task> { - if cx.has_flag::() { - maybe!({ - let project = self.project.as_ref()?; - let dap_store = project.read(cx).dap_store(); - let mut scenarios = vec![]; - let resolved_tasks = resolved_tasks.as_ref()?; - let buffer = buffer.read(cx); - let language = buffer.language()?; - let file = buffer.file(); - let debug_adapter = language_settings(language.name().into(), file, cx) - .debuggers - .first() - .map(SharedString::from) - .or_else(|| language.config().debuggers.first().map(SharedString::from))?; + maybe!({ + let project = self.project.as_ref()?; + let dap_store = project.read(cx).dap_store(); + let mut scenarios = vec![]; + let resolved_tasks = resolved_tasks.as_ref()?; + let buffer = buffer.read(cx); + let language = buffer.language()?; + let file = buffer.file(); + let debug_adapter = language_settings(language.name().into(), file, cx) + .debuggers + .first() + .map(SharedString::from) + .or_else(|| language.config().debuggers.first().map(SharedString::from))?; - dap_store.update(cx, |dap_store, cx| { - for (_, task) in &resolved_tasks.templates { - let maybe_scenario = dap_store.debug_scenario_for_build_task( - task.original_task().clone(), - debug_adapter.clone().into(), - task.display_label().to_owned().into(), - cx, - ); - scenarios.push(maybe_scenario); - } - }); - Some(cx.background_spawn(async move { - let scenarios = futures::future::join_all(scenarios) - .await - .into_iter() - .flatten() - .collect::>(); - scenarios - })) - }) - .unwrap_or_else(|| Task::ready(vec![])) - } else { - Task::ready(vec![]) - } + dap_store.update(cx, |dap_store, cx| { + for (_, task) in &resolved_tasks.templates { + let maybe_scenario = dap_store.debug_scenario_for_build_task( + task.original_task().clone(), + debug_adapter.clone().into(), + task.display_label().to_owned().into(), + cx, + ); + scenarios.push(maybe_scenario); + } + }); + Some(cx.background_spawn(async move { + let scenarios = futures::future::join_all(scenarios) + .await + .into_iter() + .flatten() + .collect::>(); + scenarios + })) + }) + .unwrap_or_else(|| Task::ready(vec![])) } fn code_actions( @@ -10155,9 +10150,6 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - if !cx.has_flag::() { - return; - } let source = self .buffer .read(cx) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index a42a6734fc..ab3cc331c0 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -32,7 +32,6 @@ use crate::{ }; use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind}; use collections::{BTreeMap, HashMap}; -use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt}; use file_icons::FileIcons; use git::{ Oid, @@ -567,12 +566,10 @@ impl EditorElement { register_action(editor, window, Editor::insert_uuid_v4); register_action(editor, window, Editor::insert_uuid_v7); register_action(editor, window, Editor::open_selections_in_multibuffer); - if cx.has_flag::() { - register_action(editor, window, Editor::toggle_breakpoint); - register_action(editor, window, Editor::edit_log_breakpoint); - register_action(editor, window, Editor::enable_breakpoint); - register_action(editor, window, Editor::disable_breakpoint); - } + register_action(editor, window, Editor::toggle_breakpoint); + register_action(editor, window, Editor::edit_log_breakpoint); + register_action(editor, window, Editor::enable_breakpoint); + register_action(editor, window, Editor::disable_breakpoint); } fn register_key_listeners(&self, window: &mut Window, _: &mut App, layout: &EditorLayout) { @@ -8173,11 +8170,9 @@ impl Element for EditorElement { let mut breakpoint_rows = self.editor.update(cx, |editor, cx| { editor.active_breakpoints(start_row..end_row, window, cx) }); - if cx.has_flag::() { - for (display_row, (_, bp, state)) in &breakpoint_rows { - if bp.is_enabled() && state.is_none_or(|s| s.verified) { - active_rows.entry(*display_row).or_default().breakpoint = true; - } + for (display_row, (_, bp, state)) in &breakpoint_rows { + if bp.is_enabled() && state.is_none_or(|s| s.verified) { + active_rows.entry(*display_row).or_default().breakpoint = true; } } @@ -8198,30 +8193,27 @@ impl Element for EditorElement { // We add the gutter breakpoint indicator to breakpoint_rows after painting // line numbers so we don't paint a line number debug accent color if a user // has their mouse over that line when a breakpoint isn't there - if cx.has_flag::() { - self.editor.update(cx, |editor, _| { - if let Some(phantom_breakpoint) = &mut editor - .gutter_breakpoint_indicator - .0 - .filter(|phantom_breakpoint| phantom_breakpoint.is_active) - { - // Is there a non-phantom breakpoint on this line? - phantom_breakpoint.collides_with_existing_breakpoint = true; - breakpoint_rows - .entry(phantom_breakpoint.display_row) - .or_insert_with(|| { - let position = snapshot.display_point_to_anchor( - DisplayPoint::new(phantom_breakpoint.display_row, 0), - Bias::Right, - ); - let breakpoint = Breakpoint::new_standard(); - phantom_breakpoint.collides_with_existing_breakpoint = - false; - (position, breakpoint, None) - }); - } - }) - } + self.editor.update(cx, |editor, _| { + if let Some(phantom_breakpoint) = &mut editor + .gutter_breakpoint_indicator + .0 + .filter(|phantom_breakpoint| phantom_breakpoint.is_active) + { + // Is there a non-phantom breakpoint on this line? + phantom_breakpoint.collides_with_existing_breakpoint = true; + breakpoint_rows + .entry(phantom_breakpoint.display_row) + .or_insert_with(|| { + let position = snapshot.display_point_to_anchor( + DisplayPoint::new(phantom_breakpoint.display_row, 0), + Bias::Right, + ); + let breakpoint = Breakpoint::new_standard(); + phantom_breakpoint.collides_with_existing_breakpoint = false; + (position, breakpoint, None) + }); + } + }); let mut expand_toggles = window.with_element_namespace("expand_toggles", |window| { @@ -8690,7 +8682,7 @@ impl Element for EditorElement { let show_breakpoints = snapshot .show_breakpoints .unwrap_or(gutter_settings.breakpoints); - let breakpoints = if cx.has_flag::() && show_breakpoints { + let breakpoints = if show_breakpoints { self.layout_breakpoints( line_height, start_row..end_row, @@ -8705,7 +8697,7 @@ impl Element for EditorElement { cx, ) } else { - vec![] + Vec::new() }; self.layout_signature_help( diff --git a/crates/feature_flags/src/feature_flags.rs b/crates/feature_flags/src/feature_flags.rs index b991f1b71c..6c0cb763ef 100644 --- a/crates/feature_flags/src/feature_flags.rs +++ b/crates/feature_flags/src/feature_flags.rs @@ -77,11 +77,6 @@ impl FeatureFlag for NotebookFeatureFlag { const NAME: &'static str = "notebooks"; } -pub struct DebuggerFeatureFlag {} -impl FeatureFlag for DebuggerFeatureFlag { - const NAME: &'static str = "debugger"; -} - pub struct ThreadAutoCaptureFeatureFlag {} impl FeatureFlag for ThreadAutoCaptureFeatureFlag { const NAME: &'static str = "thread-auto-capture"; diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 457ce2b81b..ef53f43880 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -55,7 +55,6 @@ env_logger.workspace = true extension.workspace = true extension_host.workspace = true extensions_ui.workspace = true -feature_flags.workspace = true feedback.workspace = true file_finder.workspace = true fs.workspace = true diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 419065d4a5..cf158c918f 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -20,16 +20,15 @@ use collections::VecDeque; use debugger_ui::debugger_panel::DebugPanel; use editor::ProposedChangesEditorToolbar; use editor::{Editor, MultiBuffer, scroll::Autoscroll}; -use feature_flags::{DebuggerFeatureFlag, FeatureFlagViewExt}; use futures::future::Either; use futures::{StreamExt, channel::mpsc, select_biased}; use git_ui::git_panel::GitPanel; use git_ui::project_diff::ProjectDiffToolbar; use gpui::{ - Action, App, AppContext as _, AsyncWindowContext, Context, DismissEvent, Element, Entity, - Focusable, KeyBinding, ParentElement, PathPromptOptions, PromptLevel, ReadGlobal, SharedString, - Styled, Task, TitlebarOptions, UpdateGlobal, Window, WindowKind, WindowOptions, actions, - image_cache, point, px, retain_all, + Action, App, AppContext as _, Context, DismissEvent, Element, Entity, Focusable, KeyBinding, + ParentElement, PathPromptOptions, PromptLevel, ReadGlobal, SharedString, Styled, Task, + TitlebarOptions, UpdateGlobal, Window, WindowKind, WindowOptions, actions, image_cache, point, + px, retain_all, }; use image_viewer::ImageInfo; use migrate::{MigrationBanner, MigrationEvent, MigrationNotification, MigrationType}; @@ -480,6 +479,7 @@ fn initialize_panels( workspace_handle.clone(), cx.clone(), ); + let debug_panel = DebugPanel::load(workspace_handle.clone(), cx); let ( project_panel, @@ -489,6 +489,7 @@ fn initialize_panels( channels_panel, chat_panel, notification_panel, + debug_panel, ) = futures::try_join!( project_panel, outline_panel, @@ -497,6 +498,7 @@ fn initialize_panels( channels_panel, chat_panel, notification_panel, + debug_panel, )?; workspace_handle.update_in(cx, |workspace, window, cx| { @@ -507,20 +509,7 @@ fn initialize_panels( workspace.add_panel(channels_panel, window, cx); workspace.add_panel(chat_panel, window, cx); workspace.add_panel(notification_panel, window, cx); - cx.when_flag_enabled::(window, |_, window, cx| { - cx.spawn_in( - window, - async move |workspace: gpui::WeakEntity, - cx: &mut AsyncWindowContext| { - let debug_panel = DebugPanel::load(workspace.clone(), cx).await?; - workspace.update_in(cx, |workspace, window, cx| { - workspace.add_panel(debug_panel, window, cx); - })?; - anyhow::Ok(()) - }, - ) - .detach() - }); + workspace.add_panel(debug_panel, window, cx); })?; let is_assistant2_enabled = !cfg!(test);