debugger: Remove feature flag (#32877)

Release Notes:

- debugger: Now available for everyone!
This commit is contained in:
Conrad Irwin 2025-06-17 13:56:19 -06:00 committed by GitHub
parent 8883885ecb
commit 3c9fe363d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 217 additions and 266 deletions

3
Cargo.lock generated
View file

@ -4278,7 +4278,6 @@ dependencies = [
"db", "db",
"debugger_tools", "debugger_tools",
"editor", "editor",
"feature_flags",
"file_icons", "file_icons",
"futures 0.3.31", "futures 0.3.31",
"fuzzy", "fuzzy",
@ -4746,7 +4745,6 @@ dependencies = [
"dap", "dap",
"db", "db",
"emojis", "emojis",
"feature_flags",
"file_icons", "file_icons",
"fs", "fs",
"futures 0.3.31", "futures 0.3.31",
@ -19994,7 +19992,6 @@ dependencies = [
"extension", "extension",
"extension_host", "extension_host",
"extensions_ui", "extensions_ui",
"feature_flags",
"feedback", "feedback",
"file_finder", "file_finder",
"fs", "fs",

View file

@ -35,7 +35,6 @@ dap.workspace = true
dap_adapters = { workspace = true, optional = true } dap_adapters = { workspace = true, optional = true }
db.workspace = true db.workspace = true
editor.workspace = true editor.workspace = true
feature_flags.workspace = true
file_icons.workspace = true file_icons.workspace = true
futures.workspace = true futures.workspace = true
fuzzy.workspace = true fuzzy.workspace = true

View file

@ -3,7 +3,6 @@ use std::any::TypeId;
use dap::debugger_settings::DebuggerSettings; use dap::debugger_settings::DebuggerSettings;
use debugger_panel::{DebugPanel, ToggleFocus}; use debugger_panel::{DebugPanel, ToggleFocus};
use editor::Editor; use editor::Editor;
use feature_flags::{DebuggerFeatureFlag, FeatureFlagViewExt};
use gpui::{App, DispatchPhase, EntityInputHandler, actions}; use gpui::{App, DispatchPhase, EntityInputHandler, actions};
use new_process_modal::{NewProcessModal, NewProcessMode}; use new_process_modal::{NewProcessModal, NewProcessMode};
use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::ThreadStatus}; use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::ThreadStatus};
@ -62,173 +61,163 @@ pub fn init(cx: &mut App) {
DebuggerSettings::register(cx); DebuggerSettings::register(cx);
workspace::FollowableViewRegistry::register::<DebugSession>(cx); workspace::FollowableViewRegistry::register::<DebugSession>(cx);
cx.observe_new(|_: &mut Workspace, window, cx| { cx.observe_new(|workspace: &mut Workspace, _, _| {
let Some(window) = window else { workspace
return; .register_action(spawn_task_or_modal)
}; .register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<DebugPanel>(window, cx);
cx.when_flag_enabled::<DebuggerFeatureFlag>(window, |workspace, _, _| { })
workspace .register_action(|workspace: &mut Workspace, _: &Start, window, cx| {
.register_action(spawn_task_or_modal) NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx);
.register_action(|workspace, _: &ToggleFocus, window, cx| { })
workspace.toggle_panel_focus::<DebugPanel>(window, cx); .register_action(
}) |workspace: &mut Workspace, _: &RerunLastSession, 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::<DebugPanel>(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| {
let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else { let Some(debug_panel) = workspace.panel::<DebugPanel>(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); debug_panel.update(cx, |debug_panel, cx| {
let supports_step_back = caps.supports_step_back.unwrap_or_default(); debug_panel.rerun_last_session(workspace, window, cx);
let supports_detach = running_state.session().read(cx).is_attached(); })
let status = running_state.thread_status(cx); },
)
let active_item = active_item.downgrade(); .register_action(
div.when(status == Some(ThreadStatus::Running), |div| { |workspace: &mut Workspace, _: &ShutdownDebugAdapters, _window, cx| {
let active_item = active_item.clone(); workspace.project().update(cx, |project, cx| {
div.on_action(move |_: &Pause, _, cx| { project.dap_store().update(cx, |store, cx| {
active_item store.shutdown_sessions(cx).detach();
.update(cx, |item, cx| item.pause_thread(cx))
.ok();
}) })
}) })
.when(status == Some(ThreadStatus::Stopped), |div| { },
div.on_action({ )
let active_item = active_item.clone(); .register_action_renderer(|div, workspace, _, cx| {
move |_: &StepInto, _, cx| { let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
active_item.update(cx, |item, cx| item.step_in(cx)).ok(); 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(); .on_action({
move |_: &StepOver, _, cx| { let active_item = active_item.clone();
active_item.update(cx, |item, cx| item.step_over(cx)).ok(); move |_: &Continue, _, cx| {
} active_item
}) .update(cx, |item, cx| item.continue_thread(cx))
.on_action({ .ok();
let active_item = active_item.clone(); }
move |_: &StepOut, _, cx| { })
active_item.update(cx, |item, cx| item.step_out(cx)).ok(); .on_action(cx.listener(
} |workspace, _: &ShowStackTrace, window, cx| {
}) let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
.when(supports_step_back, |div| { return;
let active_item = active_item.clone(); };
div.on_action(move |_: &StepBack, _, cx| {
active_item.update(cx, |item, cx| item.step_back(cx)).ok(); if let Some(existing) = workspace.item_of_type::<StackTraceView>(cx) {
}) let is_active = workspace
}) .active_item(cx)
.on_action({ .is_some_and(|item| item.item_id() == existing.item_id());
let active_item = active_item.clone(); workspace.activate_item(&existing, true, !is_active, window, cx);
move |_: &Continue, _, cx| { } else {
active_item let Some(active_session) = debug_panel.read(cx).active_session()
.update(cx, |item, cx| item.continue_thread(cx)) else {
.ok();
}
})
.on_action(cx.listener(
|workspace, _: &ShowStackTrace, window, cx| {
let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
return; return;
}; };
if let Some(existing) = workspace.item_of_type::<StackTraceView>(cx) let project = workspace.project();
{
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 stack_trace_view = active_session.update(cx, |session, cx| {
session.stack_trace_view(project, window, cx).clone()
});
let stack_trace_view = workspace.add_item_to_active_pane(
active_session.update(cx, |session, cx| { Box::new(stack_trace_view),
session.stack_trace_view(project, window, cx).clone() None,
}); true,
window,
workspace.add_item_to_active_pane( cx,
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(); .on_action({
div.on_action(move |_: &Detach, _, cx| { let active_item = active_item.clone();
active_item move |_: &Restart, _, cx| {
.update(cx, |item, cx| item.detach_client(cx)) active_item
.ok(); .update(cx, |item, cx| item.restart_session(cx))
}) .ok();
}) }
.on_action({ })
let active_item = active_item.clone(); .on_action({
move |_: &Restart, _, cx| { let active_item = active_item.clone();
active_item move |_: &Stop, _, cx| {
.update(cx, |item, cx| item.restart_session(cx)) active_item.update(cx, |item, cx| item.stop_thread(cx)).ok();
.ok(); }
} })
}) .on_action({
.on_action({ let active_item = active_item.clone();
let active_item = active_item.clone(); move |_: &ToggleIgnoreBreakpoints, _, cx| {
move |_: &Stop, _, cx| { active_item
active_item.update(cx, |item, cx| item.stop_thread(cx)).ok(); .update(cx, |item, cx| item.toggle_ignore_breakpoints(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(); .detach();

View file

@ -40,7 +40,6 @@ dap.workspace = true
db.workspace = true db.workspace = true
buffer_diff.workspace = true buffer_diff.workspace = true
emojis.workspace = true emojis.workspace = true
feature_flags.workspace = true
file_icons.workspace = true file_icons.workspace = true
futures.workspace = true futures.workspace = true
fuzzy.workspace = true fuzzy.workspace = true

View file

@ -73,7 +73,6 @@ use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layo
pub use element::{ pub use element::{
CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition, CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
}; };
use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
use futures::{ use futures::{
FutureExt, StreamExt as _, FutureExt, StreamExt as _,
future::{self, Shared, join}, future::{self, Shared, join},
@ -5969,45 +5968,41 @@ impl Editor {
buffer: &Entity<Buffer>, buffer: &Entity<Buffer>,
cx: &mut App, cx: &mut App,
) -> Task<Vec<task::DebugScenario>> { ) -> Task<Vec<task::DebugScenario>> {
if cx.has_flag::<DebuggerFeatureFlag>() { maybe!({
maybe!({ let project = self.project.as_ref()?;
let project = self.project.as_ref()?; let dap_store = project.read(cx).dap_store();
let dap_store = project.read(cx).dap_store(); let mut scenarios = vec![];
let mut scenarios = vec![]; let resolved_tasks = resolved_tasks.as_ref()?;
let resolved_tasks = resolved_tasks.as_ref()?; let buffer = buffer.read(cx);
let buffer = buffer.read(cx); let language = buffer.language()?;
let language = buffer.language()?; let file = buffer.file();
let file = buffer.file(); let debug_adapter = language_settings(language.name().into(), file, cx)
let debug_adapter = language_settings(language.name().into(), file, cx) .debuggers
.debuggers .first()
.first() .map(SharedString::from)
.map(SharedString::from) .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
.or_else(|| language.config().debuggers.first().map(SharedString::from))?;
dap_store.update(cx, |dap_store, cx| { dap_store.update(cx, |dap_store, cx| {
for (_, task) in &resolved_tasks.templates { for (_, task) in &resolved_tasks.templates {
let maybe_scenario = dap_store.debug_scenario_for_build_task( let maybe_scenario = dap_store.debug_scenario_for_build_task(
task.original_task().clone(), task.original_task().clone(),
debug_adapter.clone().into(), debug_adapter.clone().into(),
task.display_label().to_owned().into(), task.display_label().to_owned().into(),
cx, cx,
); );
scenarios.push(maybe_scenario); scenarios.push(maybe_scenario);
} }
}); });
Some(cx.background_spawn(async move { Some(cx.background_spawn(async move {
let scenarios = futures::future::join_all(scenarios) let scenarios = futures::future::join_all(scenarios)
.await .await
.into_iter() .into_iter()
.flatten() .flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
scenarios scenarios
})) }))
}) })
.unwrap_or_else(|| Task::ready(vec![])) .unwrap_or_else(|| Task::ready(vec![]))
} else {
Task::ready(vec![])
}
} }
fn code_actions( fn code_actions(
@ -10155,9 +10150,6 @@ impl Editor {
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
if !cx.has_flag::<DebuggerFeatureFlag>() {
return;
}
let source = self let source = self
.buffer .buffer
.read(cx) .read(cx)

View file

@ -32,7 +32,6 @@ use crate::{
}; };
use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind}; use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};
use collections::{BTreeMap, HashMap}; use collections::{BTreeMap, HashMap};
use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
use file_icons::FileIcons; use file_icons::FileIcons;
use git::{ use git::{
Oid, Oid,
@ -567,12 +566,10 @@ impl EditorElement {
register_action(editor, window, Editor::insert_uuid_v4); register_action(editor, window, Editor::insert_uuid_v4);
register_action(editor, window, Editor::insert_uuid_v7); register_action(editor, window, Editor::insert_uuid_v7);
register_action(editor, window, Editor::open_selections_in_multibuffer); register_action(editor, window, Editor::open_selections_in_multibuffer);
if cx.has_flag::<DebuggerFeatureFlag>() { register_action(editor, window, Editor::toggle_breakpoint);
register_action(editor, window, Editor::toggle_breakpoint); register_action(editor, window, Editor::edit_log_breakpoint);
register_action(editor, window, Editor::edit_log_breakpoint); register_action(editor, window, Editor::enable_breakpoint);
register_action(editor, window, Editor::enable_breakpoint); register_action(editor, window, Editor::disable_breakpoint);
register_action(editor, window, Editor::disable_breakpoint);
}
} }
fn register_key_listeners(&self, window: &mut Window, _: &mut App, layout: &EditorLayout) { 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| { let mut breakpoint_rows = self.editor.update(cx, |editor, cx| {
editor.active_breakpoints(start_row..end_row, window, cx) editor.active_breakpoints(start_row..end_row, window, cx)
}); });
if cx.has_flag::<DebuggerFeatureFlag>() { for (display_row, (_, bp, state)) in &breakpoint_rows {
for (display_row, (_, bp, state)) in &breakpoint_rows { if bp.is_enabled() && state.is_none_or(|s| s.verified) {
if bp.is_enabled() && state.is_none_or(|s| s.verified) { active_rows.entry(*display_row).or_default().breakpoint = true;
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 // 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 // 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 // has their mouse over that line when a breakpoint isn't there
if cx.has_flag::<DebuggerFeatureFlag>() { self.editor.update(cx, |editor, _| {
self.editor.update(cx, |editor, _| { if let Some(phantom_breakpoint) = &mut editor
if let Some(phantom_breakpoint) = &mut editor .gutter_breakpoint_indicator
.gutter_breakpoint_indicator .0
.0 .filter(|phantom_breakpoint| phantom_breakpoint.is_active)
.filter(|phantom_breakpoint| phantom_breakpoint.is_active) {
{ // Is there a non-phantom breakpoint on this line?
// Is there a non-phantom breakpoint on this line? phantom_breakpoint.collides_with_existing_breakpoint = true;
phantom_breakpoint.collides_with_existing_breakpoint = true; breakpoint_rows
breakpoint_rows .entry(phantom_breakpoint.display_row)
.entry(phantom_breakpoint.display_row) .or_insert_with(|| {
.or_insert_with(|| { let position = snapshot.display_point_to_anchor(
let position = snapshot.display_point_to_anchor( DisplayPoint::new(phantom_breakpoint.display_row, 0),
DisplayPoint::new(phantom_breakpoint.display_row, 0), Bias::Right,
Bias::Right, );
); let breakpoint = Breakpoint::new_standard();
let breakpoint = Breakpoint::new_standard(); phantom_breakpoint.collides_with_existing_breakpoint = false;
phantom_breakpoint.collides_with_existing_breakpoint = (position, breakpoint, None)
false; });
(position, breakpoint, None) }
}); });
}
})
}
let mut expand_toggles = let mut expand_toggles =
window.with_element_namespace("expand_toggles", |window| { window.with_element_namespace("expand_toggles", |window| {
@ -8690,7 +8682,7 @@ impl Element for EditorElement {
let show_breakpoints = snapshot let show_breakpoints = snapshot
.show_breakpoints .show_breakpoints
.unwrap_or(gutter_settings.breakpoints); .unwrap_or(gutter_settings.breakpoints);
let breakpoints = if cx.has_flag::<DebuggerFeatureFlag>() && show_breakpoints { let breakpoints = if show_breakpoints {
self.layout_breakpoints( self.layout_breakpoints(
line_height, line_height,
start_row..end_row, start_row..end_row,
@ -8705,7 +8697,7 @@ impl Element for EditorElement {
cx, cx,
) )
} else { } else {
vec![] Vec::new()
}; };
self.layout_signature_help( self.layout_signature_help(

View file

@ -77,11 +77,6 @@ impl FeatureFlag for NotebookFeatureFlag {
const NAME: &'static str = "notebooks"; const NAME: &'static str = "notebooks";
} }
pub struct DebuggerFeatureFlag {}
impl FeatureFlag for DebuggerFeatureFlag {
const NAME: &'static str = "debugger";
}
pub struct ThreadAutoCaptureFeatureFlag {} pub struct ThreadAutoCaptureFeatureFlag {}
impl FeatureFlag for ThreadAutoCaptureFeatureFlag { impl FeatureFlag for ThreadAutoCaptureFeatureFlag {
const NAME: &'static str = "thread-auto-capture"; const NAME: &'static str = "thread-auto-capture";

View file

@ -55,7 +55,6 @@ env_logger.workspace = true
extension.workspace = true extension.workspace = true
extension_host.workspace = true extension_host.workspace = true
extensions_ui.workspace = true extensions_ui.workspace = true
feature_flags.workspace = true
feedback.workspace = true feedback.workspace = true
file_finder.workspace = true file_finder.workspace = true
fs.workspace = true fs.workspace = true

View file

@ -20,16 +20,15 @@ use collections::VecDeque;
use debugger_ui::debugger_panel::DebugPanel; use debugger_ui::debugger_panel::DebugPanel;
use editor::ProposedChangesEditorToolbar; use editor::ProposedChangesEditorToolbar;
use editor::{Editor, MultiBuffer, scroll::Autoscroll}; use editor::{Editor, MultiBuffer, scroll::Autoscroll};
use feature_flags::{DebuggerFeatureFlag, FeatureFlagViewExt};
use futures::future::Either; use futures::future::Either;
use futures::{StreamExt, channel::mpsc, select_biased}; use futures::{StreamExt, channel::mpsc, select_biased};
use git_ui::git_panel::GitPanel; use git_ui::git_panel::GitPanel;
use git_ui::project_diff::ProjectDiffToolbar; use git_ui::project_diff::ProjectDiffToolbar;
use gpui::{ use gpui::{
Action, App, AppContext as _, AsyncWindowContext, Context, DismissEvent, Element, Entity, Action, App, AppContext as _, Context, DismissEvent, Element, Entity, Focusable, KeyBinding,
Focusable, KeyBinding, ParentElement, PathPromptOptions, PromptLevel, ReadGlobal, SharedString, ParentElement, PathPromptOptions, PromptLevel, ReadGlobal, SharedString, Styled, Task,
Styled, Task, TitlebarOptions, UpdateGlobal, Window, WindowKind, WindowOptions, actions, TitlebarOptions, UpdateGlobal, Window, WindowKind, WindowOptions, actions, image_cache, point,
image_cache, point, px, retain_all, px, retain_all,
}; };
use image_viewer::ImageInfo; use image_viewer::ImageInfo;
use migrate::{MigrationBanner, MigrationEvent, MigrationNotification, MigrationType}; use migrate::{MigrationBanner, MigrationEvent, MigrationNotification, MigrationType};
@ -480,6 +479,7 @@ fn initialize_panels(
workspace_handle.clone(), workspace_handle.clone(),
cx.clone(), cx.clone(),
); );
let debug_panel = DebugPanel::load(workspace_handle.clone(), cx);
let ( let (
project_panel, project_panel,
@ -489,6 +489,7 @@ fn initialize_panels(
channels_panel, channels_panel,
chat_panel, chat_panel,
notification_panel, notification_panel,
debug_panel,
) = futures::try_join!( ) = futures::try_join!(
project_panel, project_panel,
outline_panel, outline_panel,
@ -497,6 +498,7 @@ fn initialize_panels(
channels_panel, channels_panel,
chat_panel, chat_panel,
notification_panel, notification_panel,
debug_panel,
)?; )?;
workspace_handle.update_in(cx, |workspace, window, cx| { 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(channels_panel, window, cx);
workspace.add_panel(chat_panel, window, cx); workspace.add_panel(chat_panel, window, cx);
workspace.add_panel(notification_panel, window, cx); workspace.add_panel(notification_panel, window, cx);
cx.when_flag_enabled::<DebuggerFeatureFlag>(window, |_, window, cx| { workspace.add_panel(debug_panel, window, cx);
cx.spawn_in(
window,
async move |workspace: gpui::WeakEntity<Workspace>,
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()
});
})?; })?;
let is_assistant2_enabled = !cfg!(test); let is_assistant2_enabled = !cfg!(test);