Debugger implementation (#13433)
### DISCLAIMER > As of 6th March 2025, debugger is still in development. We plan to merge it behind a staff-only feature flag for staff use only, followed by non-public release and then finally a public one (akin to how Git panel release was handled). This is done to ensure the best experience when it gets released. ### END OF DISCLAIMER **The current state of the debugger implementation:** https://github.com/user-attachments/assets/c4deff07-80dd-4dc6-ad2e-0c252a478fe9 https://github.com/user-attachments/assets/e1ed2345-b750-4bb6-9c97-50961b76904f ---- All the todo's are in the following channel, so it's easier to work on this together: https://zed.dev/channel/zed-debugger-11370 If you are on Linux, you can use the following command to join the channel: ```cli zed https://zed.dev/channel/zed-debugger-11370 ``` ## Current Features - Collab - Breakpoints - Sync when you (re)join a project - Sync when you add/remove a breakpoint - Sync active debug line - Stack frames - Click on stack frame - View variables that belong to the stack frame - Visit the source file - Restart stack frame (if adapter supports this) - Variables - Loaded sources - Modules - Controls - Continue - Step back - Stepping granularity (configurable) - Step into - Stepping granularity (configurable) - Step over - Stepping granularity (configurable) - Step out - Stepping granularity (configurable) - Debug console - Breakpoints - Log breakpoints - line breakpoints - Persistent between zed sessions (configurable) - Multi buffer support - Toggle disable/enable all breakpoints - Stack frames - Click on stack frame - View variables that belong to the stack frame - Visit the source file - Show collapsed stack frames - Restart stack frame (if adapter supports this) - Loaded sources - View all used loaded sources if supported by adapter. - Modules - View all used modules (if adapter supports this) - Variables - Copy value - Copy name - Copy memory reference - Set value (if adapter supports this) - keyboard navigation - Debug Console - See logs - View output that was sent from debug adapter - Output grouping - Evaluate code - Updates the variable list - Auto completion - If not supported by adapter, we will show auto-completion for existing variables - Debug Terminal - Run custom commands and change env values right inside your Zed terminal - Attach to process (if adapter supports this) - Process picker - Controls - Continue - Step back - Stepping granularity (configurable) - Step into - Stepping granularity (configurable) - Step over - Stepping granularity (configurable) - Step out - Stepping granularity (configurable) - Disconnect - Restart - Stop - Warning when a debug session exited without hitting any breakpoint - Debug view to see Adapter/RPC log messages - Testing - Fake debug adapter - Fake requests & events --- Release Notes: - N/A --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Anthony <anthony@zed.dev> Co-authored-by: Piotr Osiewicz <peterosiewicz@gmail.com> Co-authored-by: Piotr <piotr@zed.dev>
This commit is contained in:
parent
ed4e654fdf
commit
41a60ffecf
156 changed files with 25840 additions and 451 deletions
|
@ -10,7 +10,7 @@ use language::{
|
|||
ContextProvider as _, LanguageToolchainStore, Location,
|
||||
};
|
||||
use rpc::{proto, AnyProtoClient, TypedEnvelope};
|
||||
use settings::{watch_config_file, SettingsLocation};
|
||||
use settings::{watch_config_file, SettingsLocation, TaskKind};
|
||||
use task::{TaskContext, TaskVariables, VariableName};
|
||||
use text::{BufferId, OffsetRangeExt};
|
||||
use util::ResultExt;
|
||||
|
@ -32,7 +32,7 @@ pub struct StoreState {
|
|||
buffer_store: WeakEntity<BufferStore>,
|
||||
worktree_store: Entity<WorktreeStore>,
|
||||
toolchain_store: Arc<dyn LanguageToolchainStore>,
|
||||
_global_task_config_watcher: Task<()>,
|
||||
_global_task_config_watchers: (Task<()>, Task<()>),
|
||||
}
|
||||
|
||||
enum StoreMode {
|
||||
|
@ -168,7 +168,20 @@ impl TaskStore {
|
|||
buffer_store,
|
||||
toolchain_store,
|
||||
worktree_store,
|
||||
_global_task_config_watcher: Self::subscribe_to_global_task_file_changes(fs, cx),
|
||||
_global_task_config_watchers: (
|
||||
Self::subscribe_to_global_task_file_changes(
|
||||
fs.clone(),
|
||||
TaskKind::Script,
|
||||
paths::tasks_file().clone(),
|
||||
cx,
|
||||
),
|
||||
Self::subscribe_to_global_task_file_changes(
|
||||
fs.clone(),
|
||||
TaskKind::Debug,
|
||||
paths::debug_tasks_file().clone(),
|
||||
cx,
|
||||
),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -190,7 +203,20 @@ impl TaskStore {
|
|||
buffer_store,
|
||||
toolchain_store,
|
||||
worktree_store,
|
||||
_global_task_config_watcher: Self::subscribe_to_global_task_file_changes(fs, cx),
|
||||
_global_task_config_watchers: (
|
||||
Self::subscribe_to_global_task_file_changes(
|
||||
fs.clone(),
|
||||
TaskKind::Script,
|
||||
paths::tasks_file().clone(),
|
||||
cx,
|
||||
),
|
||||
Self::subscribe_to_global_task_file_changes(
|
||||
fs.clone(),
|
||||
TaskKind::Debug,
|
||||
paths::debug_tasks_file().clone(),
|
||||
cx,
|
||||
),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -262,6 +288,7 @@ impl TaskStore {
|
|||
&self,
|
||||
location: Option<SettingsLocation<'_>>,
|
||||
raw_tasks_json: Option<&str>,
|
||||
task_type: TaskKind,
|
||||
cx: &mut Context<'_, Self>,
|
||||
) -> anyhow::Result<()> {
|
||||
let task_inventory = match self {
|
||||
|
@ -273,22 +300,23 @@ impl TaskStore {
|
|||
.filter(|json| !json.is_empty());
|
||||
|
||||
task_inventory.update(cx, |inventory, _| {
|
||||
inventory.update_file_based_tasks(location, raw_tasks_json)
|
||||
inventory.update_file_based_tasks(location, raw_tasks_json, task_type)
|
||||
})
|
||||
}
|
||||
|
||||
fn subscribe_to_global_task_file_changes(
|
||||
fs: Arc<dyn Fs>,
|
||||
task_kind: TaskKind,
|
||||
file_path: PathBuf,
|
||||
cx: &mut Context<'_, Self>,
|
||||
) -> Task<()> {
|
||||
let mut user_tasks_file_rx =
|
||||
watch_config_file(&cx.background_executor(), fs, paths::tasks_file().clone());
|
||||
let mut user_tasks_file_rx = watch_config_file(&cx.background_executor(), fs, file_path);
|
||||
let user_tasks_content = cx.background_executor().block(user_tasks_file_rx.next());
|
||||
cx.spawn(move |task_store, mut cx| async move {
|
||||
if let Some(user_tasks_content) = user_tasks_content {
|
||||
let Ok(_) = task_store.update(&mut cx, |task_store, cx| {
|
||||
task_store
|
||||
.update_user_tasks(None, Some(&user_tasks_content), cx)
|
||||
.update_user_tasks(None, Some(&user_tasks_content), task_kind, cx)
|
||||
.log_err();
|
||||
}) else {
|
||||
return;
|
||||
|
@ -296,12 +324,17 @@ impl TaskStore {
|
|||
}
|
||||
while let Some(user_tasks_content) = user_tasks_file_rx.next().await {
|
||||
let Ok(()) = task_store.update(&mut cx, |task_store, cx| {
|
||||
let result = task_store.update_user_tasks(None, Some(&user_tasks_content), cx);
|
||||
let result = task_store.update_user_tasks(
|
||||
None,
|
||||
Some(&user_tasks_content),
|
||||
task_kind,
|
||||
cx,
|
||||
);
|
||||
if let Err(err) = &result {
|
||||
log::error!("Failed to load user tasks: {err}");
|
||||
log::error!("Failed to load user {:?} tasks: {err}", task_kind);
|
||||
cx.emit(crate::Event::Toast {
|
||||
notification_id: "load-user-tasks".into(),
|
||||
message: format!("Invalid global tasks file\n{err}"),
|
||||
notification_id: format!("load-user-{:?}-tasks", task_kind).into(),
|
||||
message: format!("Invalid global {:?} tasks file\n{err}", task_kind),
|
||||
});
|
||||
}
|
||||
cx.refresh_windows();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue