debugger: Add comment-preserving debug.json editing (#32896)

Release Notes:

- Re-added "Save to `debug.json`" for custom debug tasks

---------

Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
Julia Ryan 2025-06-17 15:51:05 -07:00 committed by GitHub
parent 2f1d25d7f3
commit e47c48fd3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 186 additions and 134 deletions

View file

@ -6,6 +6,7 @@ use std::{
borrow::Cow,
path::{Path, PathBuf},
sync::Arc,
time::Duration,
usize,
};
use tasks_ui::{TaskOverrides, TasksModal};
@ -39,11 +40,12 @@ use workspace::{ModalView, Workspace, pane};
use crate::{attach_modal::AttachModal, debugger_panel::DebugPanel};
// enum SaveScenarioState {
// Saving,
// Saved((ProjectPath, SharedString)),
// Failed(SharedString),
// }
#[allow(unused)]
enum SaveScenarioState {
Saving,
Saved((ProjectPath, SharedString)),
Failed(SharedString),
}
pub(super) struct NewProcessModal {
workspace: WeakEntity<Workspace>,
@ -54,7 +56,7 @@ pub(super) struct NewProcessModal {
configure_mode: Entity<ConfigureMode>,
task_mode: TaskMode,
debugger: Option<DebugAdapterName>,
// save_scenario_state: Option<SaveScenarioState>,
save_scenario_state: Option<SaveScenarioState>,
_subscriptions: [Subscription; 3],
}
@ -265,7 +267,7 @@ impl NewProcessModal {
mode,
debug_panel: debug_panel.downgrade(),
workspace: workspace_handle,
// save_scenario_state: None,
save_scenario_state: None,
_subscriptions,
}
});
@ -352,12 +354,11 @@ impl NewProcessModal {
return;
}
// TODO: Restore once we have proper, comment preserving edits
// if let NewProcessMode::Launch = &self.mode {
// if self.launch_mode.read(cx).save_to_debug_json.selected() {
// self.save_debug_scenario(window, cx);
// }
// }
if let NewProcessMode::Launch = &self.mode {
if self.configure_mode.read(cx).save_to_debug_json.selected() {
self.save_debug_scenario(window, cx);
}
}
let Some(debugger) = self.debugger.clone() else {
return;
@ -418,47 +419,64 @@ impl NewProcessModal {
self.debug_picker.read(cx).delegate.task_contexts.clone()
}
// fn save_debug_scenario(&mut self, window: &mut Window, cx: &mut Context<Self>) {
// let Some((save_scenario, scenario_label)) = self
// .debugger
// .as_ref()
// .and_then(|debugger| self.debug_scenario(&debugger, cx))
// .zip(self.task_contexts(cx).and_then(|tcx| tcx.worktree()))
// .and_then(|(scenario, worktree_id)| {
// self.debug_panel
// .update(cx, |panel, cx| {
// panel.save_scenario(&scenario, worktree_id, window, cx)
// })
// .ok()
// .zip(Some(scenario.label.clone()))
// })
// else {
// return;
// };
fn save_debug_scenario(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let task_contents = self.task_contexts(cx);
let Some(adapter) = self.debugger.as_ref() else {
return;
};
let scenario = self.debug_scenario(&adapter, cx);
// self.save_scenario_state = Some(SaveScenarioState::Saving);
self.save_scenario_state = Some(SaveScenarioState::Saving);
// cx.spawn(async move |this, cx| {
// let res = save_scenario.await;
cx.spawn_in(window, async move |this, cx| {
let Some((scenario, worktree_id)) = scenario
.await
.zip(task_contents.and_then(|tcx| tcx.worktree()))
else {
this.update(cx, |this, _| {
this.save_scenario_state = Some(SaveScenarioState::Failed(
"Couldn't get scenario or task contents".into(),
))
})
.ok();
return;
};
// this.update(cx, |this, _| match res {
// Ok(saved_file) => {
// this.save_scenario_state =
// Some(SaveScenarioState::Saved((saved_file, scenario_label)))
// }
// Err(error) => {
// this.save_scenario_state =
// Some(SaveScenarioState::Failed(error.to_string().into()))
// }
// })
// .ok();
let Some(save_scenario) = this
.update_in(cx, |this, window, cx| {
this.debug_panel
.update(cx, |panel, cx| {
panel.save_scenario(&scenario, worktree_id, window, cx)
})
.ok()
})
.ok()
.flatten()
else {
return;
};
let res = save_scenario.await;
// cx.background_executor().timer(Duration::from_secs(3)).await;
// this.update(cx, |this, _| this.save_scenario_state.take())
// .ok();
// })
// .detach();
// }
this.update(cx, |this, _| match res {
Ok(saved_file) => {
this.save_scenario_state = Some(SaveScenarioState::Saved((
saved_file,
scenario.label.clone(),
)))
}
Err(error) => {
this.save_scenario_state =
Some(SaveScenarioState::Failed(error.to_string().into()))
}
})
.ok();
cx.background_executor().timer(Duration::from_secs(3)).await;
this.update(cx, |this, _| this.save_scenario_state.take())
.ok();
})
.detach();
}
fn adapter_drop_down_menu(
&mut self,
@ -903,7 +921,7 @@ pub(super) struct ConfigureMode {
program: Entity<Editor>,
cwd: Entity<Editor>,
stop_on_entry: ToggleState,
// save_to_debug_json: ToggleState,
save_to_debug_json: ToggleState,
}
impl ConfigureMode {
@ -922,7 +940,7 @@ impl ConfigureMode {
program,
cwd,
stop_on_entry: ToggleState::Unselected,
// save_to_debug_json: ToggleState::Unselected,
save_to_debug_json: ToggleState::Unselected,
})
}
@ -1028,27 +1046,25 @@ impl ConfigureMode {
)
.checkbox_position(ui::IconPosition::End),
)
// TODO: restore once we have proper, comment preserving
// file edits.
// .child(
// CheckboxWithLabel::new(
// "debugger-save-to-debug-json",
// Label::new("Save to debug.json")
// .size(ui::LabelSize::Small)
// .color(Color::Muted),
// self.save_to_debug_json,
// {
// let this = cx.weak_entity();
// move |state, _, cx| {
// this.update(cx, |this, _| {
// this.save_to_debug_json = *state;
// })
// .ok();
// }
// },
// )
// .checkbox_position(ui::IconPosition::End),
// )
.child(
CheckboxWithLabel::new(
"debugger-save-to-debug-json",
Label::new("Save to debug.json")
.size(ui::LabelSize::Small)
.color(Color::Muted),
self.save_to_debug_json,
{
let this = cx.weak_entity();
move |state, _, cx| {
this.update(cx, |this, _| {
this.save_to_debug_json = *state;
})
.ok();
}
},
)
.checkbox_position(ui::IconPosition::End),
)
}
}