debugger: Improve variable list keyboard navigation (#27308)

This PR improves the keyboard navigation for the variable list. 
Before this PR, if you want to open/close nested variables, you had to
use the right/left & up/down arrow keys.
Now you can step through with just only using your left/right arrow
keys, this feels a bit more natural and more similar to how other
editors allow you to navigate through variables.

This PR also fixes the following issues:
- Allow selecting a scope to be the start of your selection
- Allow selecting previous item if the first item is selected

-----


https://github.com/user-attachments/assets/aff0b133-97be-4c09-8ee6-b11495ad5568

Release Notes:

- N/A
This commit is contained in:
Remco Smits 2025-03-25 00:36:09 +01:00 committed by GitHub
parent a52095f558
commit bcfc9e4437
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 256 additions and 26 deletions

View file

@ -1103,6 +1103,219 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
});
});
// select scope 2 backwards
cx.dispatch_action(SelectPrevious);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec!["> Scope 1", "> Scope 2 <=== selected"]);
});
});
// select scope 1 backwards
cx.dispatch_action(SelectNext);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec!["> Scope 1 <=== selected", "> Scope 2"]);
});
});
// test stepping through nested with ExpandSelectedEntry/CollapseSelectedEntry actions
cx.dispatch_action(ExpandSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1 <=== selected",
" > variable1",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(ExpandSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" > variable1 <=== selected",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(ExpandSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" v variable1 <=== selected",
" > nested1",
" > nested2",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(ExpandSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" v variable1",
" > nested1 <=== selected",
" > nested2",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(ExpandSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" v variable1",
" > nested1",
" > nested2 <=== selected",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(ExpandSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" v variable1",
" > nested1",
" > nested2",
" > variable2 <=== selected",
"> Scope 2",
]);
});
});
cx.dispatch_action(CollapseSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" v variable1",
" > nested1",
" > nested2 <=== selected",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(CollapseSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" v variable1",
" > nested1 <=== selected",
" > nested2",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(CollapseSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" v variable1 <=== selected",
" > nested1",
" > nested2",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(CollapseSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1",
" > variable1 <=== selected",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(CollapseSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec![
"v Scope 1 <=== selected",
" > variable1",
" > variable2",
"> Scope 2",
]);
});
});
cx.dispatch_action(CollapseSelectedEntry);
cx.run_until_parked();
running_state.update(cx, |debug_panel_item, cx| {
debug_panel_item
.variable_list()
.update(cx, |variable_list, _| {
variable_list.assert_visual_entries(vec!["> Scope 1 <=== selected", "> Scope 2"]);
});
});
let shutdown_session = project.update(cx, |project, cx| {
project.dap_store().update(cx, |dap_store, cx| {
dap_store.shutdown_session(session.read(cx).session_id(), cx)