debugger: Add data breakpoint access type support (#34639)
Release Notes: - Support specifying a data breakpoint's access type - Read, Write, Read & Write
This commit is contained in:
parent
8980526a85
commit
ae0d4f6a0d
5 changed files with 77 additions and 20 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4427,6 +4427,7 @@ dependencies = [
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"project",
|
"project",
|
||||||
"rpc",
|
"rpc",
|
||||||
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_json_lenient",
|
"serde_json_lenient",
|
||||||
|
|
|
@ -35,6 +35,7 @@ command_palette_hooks.workspace = true
|
||||||
dap.workspace = true
|
dap.workspace = true
|
||||||
dap_adapters = { workspace = true, optional = true }
|
dap_adapters = { workspace = true, optional = true }
|
||||||
db.workspace = true
|
db.workspace = true
|
||||||
|
debugger_tools.workspace = true
|
||||||
editor.workspace = true
|
editor.workspace = true
|
||||||
file_icons.workspace = true
|
file_icons.workspace = true
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
|
@ -54,6 +55,7 @@ picker.workspace = true
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
rpc.workspace = true
|
rpc.workspace = true
|
||||||
|
schemars.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde_json_lenient.workspace = true
|
serde_json_lenient.workspace = true
|
||||||
|
@ -66,14 +68,13 @@ telemetry.workspace = true
|
||||||
terminal_view.workspace = true
|
terminal_view.workspace = true
|
||||||
text.workspace = true
|
text.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
tree-sitter.workspace = true
|
|
||||||
tree-sitter-json.workspace = true
|
tree-sitter-json.workspace = true
|
||||||
|
tree-sitter.workspace = true
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
util.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
workspace-hack.workspace = true
|
|
||||||
debugger_tools.workspace = true
|
|
||||||
unindent = { workspace = true, optional = true }
|
unindent = { workspace = true, optional = true }
|
||||||
|
util.workspace = true
|
||||||
|
workspace-hack.workspace = true
|
||||||
|
workspace.workspace = true
|
||||||
zed_actions.workspace = true
|
zed_actions.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -83,8 +84,8 @@ debugger_tools = { workspace = true, features = ["test-support"] }
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
editor = { workspace = true, features = ["test-support"] }
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
gpui = { workspace = true, features = ["test-support"] }
|
||||||
project = { workspace = true, features = ["test-support"] }
|
project = { workspace = true, features = ["test-support"] }
|
||||||
|
tree-sitter-go.workspace = true
|
||||||
unindent.workspace = true
|
unindent.workspace = true
|
||||||
util = { workspace = true, features = ["test-support"] }
|
util = { workspace = true, features = ["test-support"] }
|
||||||
workspace = { workspace = true, features = ["test-support"] }
|
workspace = { workspace = true, features = ["test-support"] }
|
||||||
zlog.workspace = true
|
zlog.workspace = true
|
||||||
tree-sitter-go.workspace = true
|
|
||||||
|
|
|
@ -3,10 +3,12 @@ use std::any::TypeId;
|
||||||
use dap::debugger_settings::DebuggerSettings;
|
use dap::debugger_settings::DebuggerSettings;
|
||||||
use debugger_panel::DebugPanel;
|
use debugger_panel::DebugPanel;
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use gpui::{App, DispatchPhase, EntityInputHandler, actions};
|
use gpui::{Action, App, DispatchPhase, EntityInputHandler, actions};
|
||||||
use new_process_modal::{NewProcessModal, NewProcessMode};
|
use new_process_modal::{NewProcessModal, NewProcessMode};
|
||||||
use onboarding_modal::DebuggerOnboardingModal;
|
use onboarding_modal::DebuggerOnboardingModal;
|
||||||
use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::ThreadStatus};
|
use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::ThreadStatus};
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
use session::DebugSession;
|
use session::DebugSession;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use stack_trace_view::StackTraceView;
|
use stack_trace_view::StackTraceView;
|
||||||
|
@ -83,11 +85,23 @@ actions!(
|
||||||
Rerun,
|
Rerun,
|
||||||
/// Toggles expansion of the selected item in the debugger UI.
|
/// Toggles expansion of the selected item in the debugger UI.
|
||||||
ToggleExpandItem,
|
ToggleExpandItem,
|
||||||
/// Set a data breakpoint on the selected variable or memory region.
|
|
||||||
ToggleDataBreakpoint,
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Extends selection down by a specified number of lines.
|
||||||
|
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema, Action)]
|
||||||
|
#[action(namespace = debugger)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
/// Set a data breakpoint on the selected variable or memory region.
|
||||||
|
pub struct ToggleDataBreakpoint {
|
||||||
|
/// The type of data breakpoint
|
||||||
|
/// Read & Write
|
||||||
|
/// Read
|
||||||
|
/// Write
|
||||||
|
#[serde(default)]
|
||||||
|
pub access_type: Option<dap::DataBreakpointAccessType>,
|
||||||
|
}
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
dev,
|
dev,
|
||||||
[
|
[
|
||||||
|
|
|
@ -688,7 +688,7 @@ impl MemoryView {
|
||||||
menu = menu.action_disabled_when(
|
menu = menu.action_disabled_when(
|
||||||
*memory_unreadable,
|
*memory_unreadable,
|
||||||
"Set Data Breakpoint",
|
"Set Data Breakpoint",
|
||||||
ToggleDataBreakpoint.boxed_clone(),
|
ToggleDataBreakpoint { access_type: None }.boxed_clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
menu.context(self.focus_handle.clone())
|
menu.context(self.focus_handle.clone())
|
||||||
|
|
|
@ -670,9 +670,9 @@ impl VariableList {
|
||||||
let focus_handle = self.focus_handle.clone();
|
let focus_handle = self.focus_handle.clone();
|
||||||
cx.spawn_in(window, async move |this, cx| {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
let can_toggle_data_breakpoint = if let Some(task) = can_toggle_data_breakpoint {
|
let can_toggle_data_breakpoint = if let Some(task) = can_toggle_data_breakpoint {
|
||||||
task.await.is_some()
|
task.await
|
||||||
} else {
|
} else {
|
||||||
true
|
None
|
||||||
};
|
};
|
||||||
cx.update(|window, cx| {
|
cx.update(|window, cx| {
|
||||||
let context_menu = ContextMenu::build(window, cx, |menu, _, _| {
|
let context_menu = ContextMenu::build(window, cx, |menu, _, _| {
|
||||||
|
@ -686,11 +686,35 @@ impl VariableList {
|
||||||
menu.action("Go To Memory", GoToMemory.boxed_clone())
|
menu.action("Go To Memory", GoToMemory.boxed_clone())
|
||||||
})
|
})
|
||||||
.action("Watch Variable", AddWatch.boxed_clone())
|
.action("Watch Variable", AddWatch.boxed_clone())
|
||||||
.when(can_toggle_data_breakpoint, |menu| {
|
.when_some(can_toggle_data_breakpoint, |mut menu, data_info| {
|
||||||
menu.action(
|
menu = menu.separator();
|
||||||
"Toggle Data Breakpoint",
|
if let Some(access_types) = data_info.access_types {
|
||||||
crate::ToggleDataBreakpoint.boxed_clone(),
|
for access in access_types {
|
||||||
)
|
menu = menu.action(
|
||||||
|
format!(
|
||||||
|
"Toggle {} Data Breakpoint",
|
||||||
|
match access {
|
||||||
|
dap::DataBreakpointAccessType::Read => "Read",
|
||||||
|
dap::DataBreakpointAccessType::Write => "Write",
|
||||||
|
dap::DataBreakpointAccessType::ReadWrite =>
|
||||||
|
"Read/Write",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
crate::ToggleDataBreakpoint {
|
||||||
|
access_type: Some(access),
|
||||||
|
}
|
||||||
|
.boxed_clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu
|
||||||
|
} else {
|
||||||
|
menu.action(
|
||||||
|
"Toggle Data Breakpoint",
|
||||||
|
crate::ToggleDataBreakpoint { access_type: None }
|
||||||
|
.boxed_clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.when(entry.as_watcher().is_some(), |menu| {
|
.when(entry.as_watcher().is_some(), |menu| {
|
||||||
|
@ -729,7 +753,7 @@ impl VariableList {
|
||||||
|
|
||||||
fn toggle_data_breakpoint(
|
fn toggle_data_breakpoint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &crate::ToggleDataBreakpoint,
|
data_info: &crate::ToggleDataBreakpoint,
|
||||||
_window: &mut Window,
|
_window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -759,17 +783,34 @@ impl VariableList {
|
||||||
});
|
});
|
||||||
|
|
||||||
let session = self.session.downgrade();
|
let session = self.session.downgrade();
|
||||||
|
let access_type = data_info.access_type;
|
||||||
cx.spawn(async move |_, cx| {
|
cx.spawn(async move |_, cx| {
|
||||||
let Some(data_id) = data_breakpoint.await.and_then(|info| info.data_id) else {
|
let Some((data_id, access_types)) = data_breakpoint
|
||||||
|
.await
|
||||||
|
.and_then(|info| Some((info.data_id?, info.access_types)))
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Because user's can manually add this action to the keymap
|
||||||
|
// we check if access type is supported
|
||||||
|
let access_type = match access_types {
|
||||||
|
None => None,
|
||||||
|
Some(access_types) => {
|
||||||
|
if access_type.is_some_and(|access_type| access_types.contains(&access_type)) {
|
||||||
|
access_type
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
_ = session.update(cx, |session, cx| {
|
_ = session.update(cx, |session, cx| {
|
||||||
session.create_data_breakpoint(
|
session.create_data_breakpoint(
|
||||||
context,
|
context,
|
||||||
data_id.clone(),
|
data_id.clone(),
|
||||||
dap::DataBreakpoint {
|
dap::DataBreakpoint {
|
||||||
data_id,
|
data_id,
|
||||||
access_type: None,
|
access_type,
|
||||||
condition: None,
|
condition: None,
|
||||||
hit_condition: None,
|
hit_condition: None,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue