From 4b6e0da752a82b25ea0b94c6c0fe5c99ce8d95ab Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 20:46:04 +0200 Subject: [PATCH 01/13] WIP Co-authored-by: Anthony Eid --- crates/debugger_ui/src/session.rs | 31 ++- crates/project/src/debugger/dap_command.rs | 270 ++++++++------------- crates/project/src/debugger/dap_store.rs | 63 +++-- crates/project/src/debugger/session.rs | 124 ++++++++-- crates/proto/proto/call.proto | 5 + crates/proto/proto/debugger.proto | 14 ++ 6 files changed, 284 insertions(+), 223 deletions(-) diff --git a/crates/debugger_ui/src/session.rs b/crates/debugger_ui/src/session.rs index e0e6126867462e..710738db25f3f9 100644 --- a/crates/debugger_ui/src/session.rs +++ b/crates/debugger_ui/src/session.rs @@ -186,17 +186,33 @@ impl FollowableItem for DebugSession { self.remote_id } - fn to_state_proto(&self, _window: &Window, _cx: &App) -> Option { - None + fn to_state_proto(&self, _window: &Window, cx: &App) -> Option { + let session_id = self.running_state.read(cx).session_id().to_proto(); + + dbg!("here"); + + Some(proto::view::Variant::DebugSession( + proto::view::DebugSession { session_id }, + )) } fn from_state_proto( - _workspace: Entity, - _remote_id: ViewId, - _state: &mut Option, - _window: &mut Window, - _cx: &mut App, + workspace: Entity, + remote_id: ViewId, + state: &mut Option, + window: &mut Window, + cx: &mut App, ) -> Option>>> { + let proto::view::Variant::DebugSession(_) = state.as_ref()? else { + return None; + }; + let Some(proto::view::Variant::DebugSession(state)) = state.take() else { + unreachable!() + }; + + let session_id = state.session_id; + + dbg!("here"); None } @@ -219,6 +235,7 @@ impl FollowableItem for DebugSession { _window: &mut Window, _cx: &mut Context, ) -> gpui::Task> { + dbg!("here"); Task::ready(Ok(())) } diff --git a/crates/project/src/debugger/dap_command.rs b/crates/project/src/debugger/dap_command.rs index 735444b3f31f64..7dca0c639532da 100644 --- a/crates/project/src/debugger/dap_command.rs +++ b/crates/project/src/debugger/dap_command.rs @@ -36,19 +36,16 @@ pub trait DapCommand: LocalDapCommand { const CACHEABLE: bool = false; #[allow(dead_code)] - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId; + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId; #[allow(dead_code)] fn from_proto(request: &Self::ProtoRequest) -> Self; #[allow(unused)] - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest; + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest; #[allow(dead_code)] - fn response_to_proto( - debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse; + fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse; #[allow(unused)] fn response_from_proto(&self, message: Self::ProtoResponse) -> Result; @@ -78,23 +75,20 @@ impl DapCommand for Arc { type ProtoRequest = T::ProtoRequest; type ProtoResponse = T::ProtoResponse; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - T::client_id_from_proto(request) + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + T::session_id_from_proto(request) } fn from_proto(request: &Self::ProtoRequest) -> Self { Arc::new(T::from_proto(request)) } - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { - T::to_proto(self, debug_client_id, upstream_project_id) + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + T::to_proto(self, session_id, upstream_project_id) } - fn response_to_proto( - debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { - T::response_to_proto(debug_client_id, message) + fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { + T::response_to_proto(session_id, message) } fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { @@ -156,7 +150,7 @@ impl DapCommand for NextCommand { type ProtoRequest = proto::DapNextRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -166,21 +160,14 @@ impl DapCommand for NextCommand { } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } - fn to_proto( - &self, - debug_client_id: SessionId, - upstream_project_id: u64, - ) -> proto::DapNextRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> proto::DapNextRequest { proto::DapNextRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -222,7 +209,7 @@ impl DapCommand for StepInCommand { type ProtoRequest = proto::DapStepInRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -238,21 +225,14 @@ impl DapCommand for StepInCommand { } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } - fn to_proto( - &self, - debug_client_id: SessionId, - upstream_project_id: u64, - ) -> proto::DapStepInRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> proto::DapStepInRequest { proto::DapStepInRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -294,7 +274,7 @@ impl DapCommand for StepOutCommand { type ProtoRequest = proto::DapStepOutRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -310,21 +290,18 @@ impl DapCommand for StepOutCommand { } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapStepOutRequest { proto::DapStepOutRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -368,7 +345,7 @@ impl DapCommand for StepBackCommand { type ProtoRequest = proto::DapStepBackRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -384,21 +361,18 @@ impl DapCommand for StepBackCommand { } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapStepBackRequest { proto::DapStepBackRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -435,18 +409,18 @@ impl DapCommand for ContinueCommand { type ProtoRequest = proto::DapContinueRequest; type ProtoResponse = proto::DapContinueResponse; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapContinueRequest { proto::DapContinueRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_id: self.args.thread_id, single_thread: self.args.single_thread, } @@ -467,12 +441,9 @@ impl DapCommand for ContinueCommand { }) } - fn response_to_proto( - debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapContinueResponse { - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), all_threads_continued: message.all_threads_continued, } } @@ -504,7 +475,7 @@ impl DapCommand for PauseCommand { type ProtoRequest = proto::DapPauseRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -514,22 +485,15 @@ impl DapCommand for PauseCommand { } } - fn to_proto( - &self, - debug_client_id: SessionId, - upstream_project_id: u64, - ) -> proto::DapPauseRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> proto::DapPauseRequest { proto::DapPauseRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_id: self.thread_id, } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } @@ -569,7 +533,7 @@ impl DapCommand for DisconnectCommand { type ProtoRequest = proto::DapDisconnectRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -583,22 +547,19 @@ impl DapCommand for DisconnectCommand { fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapDisconnectRequest { proto::DapDisconnectRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), restart: self.restart, terminate_debuggee: self.terminate_debuggee, suspend_debuggee: self.suspend_debuggee, } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } @@ -640,7 +601,7 @@ impl DapCommand for TerminateThreadsCommand { type ProtoRequest = proto::DapTerminateThreadsRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -656,20 +617,17 @@ impl DapCommand for TerminateThreadsCommand { fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapTerminateThreadsRequest { proto::DapTerminateThreadsRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_ids: self.thread_ids.clone().unwrap_or_default(), } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } @@ -708,7 +666,7 @@ impl DapCommand for TerminateCommand { type ProtoRequest = proto::DapTerminateRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -720,20 +678,17 @@ impl DapCommand for TerminateCommand { fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapTerminateRequest { proto::DapTerminateRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), restart: self.restart, } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } @@ -773,7 +728,7 @@ impl DapCommand for RestartCommand { type ProtoRequest = proto::DapRestartRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -787,22 +742,19 @@ impl DapCommand for RestartCommand { fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapRestartRequest { let raw_args = serde_json::to_vec(&self.raw).log_err().unwrap_or_default(); proto::DapRestartRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), raw_args, } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } @@ -847,14 +799,14 @@ impl DapCommand for VariablesCommand { type ProtoResponse = proto::DapVariables; const CACHEABLE: bool = true; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::VariablesRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), variables_reference: self.variables_reference, filter: None, start: self.start, @@ -873,12 +825,9 @@ impl DapCommand for VariablesCommand { } } - fn response_to_proto( - debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapVariables { - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), variables: message.to_proto(), } } @@ -920,14 +869,14 @@ impl DapCommand for SetVariableValueCommand { type ProtoRequest = proto::DapSetVariableValueRequest; type ProtoResponse = proto::DapSetVariableValueResponse; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapSetVariableValueRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), variables_reference: self.variables_reference, value: self.value.clone(), name: self.name.clone(), @@ -942,12 +891,9 @@ impl DapCommand for SetVariableValueCommand { } } - fn response_to_proto( - debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapSetVariableValueResponse { - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), value: message.value, variable_type: message.type_, named_variables: message.named_variables, @@ -1001,7 +947,7 @@ impl DapCommand for RestartStackFrameCommand { type ProtoRequest = proto::DapRestartStackFrameRequest; type ProtoResponse = proto::Ack; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1013,20 +959,17 @@ impl DapCommand for RestartStackFrameCommand { fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapRestartStackFrameRequest { proto::DapRestartStackFrameRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), stack_frame_id: self.stack_frame_id, } } - fn response_to_proto( - _debug_client_id: SessionId, - _message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, _message: Self::Response) -> Self::ProtoResponse { proto::Ack {} } @@ -1066,7 +1009,7 @@ impl DapCommand for ModulesCommand { type ProtoResponse = proto::DapModulesResponse; const CACHEABLE: bool = true; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1076,25 +1019,22 @@ impl DapCommand for ModulesCommand { fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapModulesRequest { proto::DapModulesRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), } } - fn response_to_proto( - debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapModulesResponse { modules: message .into_iter() .map(|module| module.to_proto()) .collect(), - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), } } @@ -1136,7 +1076,7 @@ impl DapCommand for LoadedSourcesCommand { type ProtoResponse = proto::DapLoadedSourcesResponse; const CACHEABLE: bool = true; - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1146,25 +1086,22 @@ impl DapCommand for LoadedSourcesCommand { fn to_proto( &self, - debug_client_id: SessionId, + session_id: SessionId, upstream_project_id: u64, ) -> proto::DapLoadedSourcesRequest { proto::DapLoadedSourcesRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), } } - fn response_to_proto( - debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapLoadedSourcesResponse { sources: message .into_iter() .map(|source| source.to_proto()) .collect(), - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), } } @@ -1210,10 +1147,10 @@ impl DapCommand for StackTraceCommand { type ProtoResponse = proto::DapStackTraceResponse; const CACHEABLE: bool = true; - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapStackTraceRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), thread_id: self.thread_id, start_frame: self.start_frame, stack_trace_levels: self.levels, @@ -1228,7 +1165,7 @@ impl DapCommand for StackTraceCommand { } } - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1240,10 +1177,7 @@ impl DapCommand for StackTraceCommand { .collect()) } - fn response_to_proto( - _debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapStackTraceResponse { frames: message.to_proto(), } @@ -1278,10 +1212,10 @@ impl DapCommand for ScopesCommand { type ProtoResponse = proto::DapScopesResponse; const CACHEABLE: bool = true; - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapScopesRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), stack_frame_id: self.stack_frame_id, } } @@ -1292,7 +1226,7 @@ impl DapCommand for ScopesCommand { } } - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1300,10 +1234,7 @@ impl DapCommand for ScopesCommand { Ok(Vec::from_proto(message.scopes)) } - fn response_to_proto( - _debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapScopesResponse { scopes: message.to_proto(), } @@ -1342,9 +1273,9 @@ impl DapCommand for super::session::CompletionsQuery { type ProtoResponse = proto::DapCompletionResponse; const CACHEABLE: bool = true; - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapCompletionRequest { - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), project_id: upstream_project_id, frame_id: self.frame_id, query: self.query.clone(), @@ -1353,7 +1284,7 @@ impl DapCommand for super::session::CompletionsQuery { } } - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1372,12 +1303,9 @@ impl DapCommand for super::session::CompletionsQuery { }) } - fn response_to_proto( - _debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapCompletionResponse { - client_id: _debug_client_id.to_proto(), + client_id: _session_id.to_proto(), completions: message.targets.to_proto(), } } @@ -1417,9 +1345,9 @@ impl DapCommand for EvaluateCommand { type ProtoRequest = proto::DapEvaluateRequest; type ProtoResponse = proto::DapEvaluateResponse; - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapEvaluateRequest { - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), project_id: upstream_project_id, expression: self.expression.clone(), frame_id: self.frame_id, @@ -1430,7 +1358,7 @@ impl DapCommand for EvaluateCommand { } } - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1456,10 +1384,7 @@ impl DapCommand for EvaluateCommand { }) } - fn response_to_proto( - _debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapEvaluateResponse { result: message.result, evaluate_type: message.type_, @@ -1495,10 +1420,10 @@ impl DapCommand for ThreadsCommand { type ProtoResponse = proto::DapThreadsResponse; const CACHEABLE: bool = true; - fn to_proto(&self, debug_client_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { + fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapThreadsRequest { project_id: upstream_project_id, - client_id: debug_client_id.to_proto(), + client_id: session_id.to_proto(), } } @@ -1506,7 +1431,7 @@ impl DapCommand for ThreadsCommand { Self {} } - fn client_id_from_proto(request: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(request.client_id) } @@ -1514,10 +1439,7 @@ impl DapCommand for ThreadsCommand { Ok(Vec::from_proto(message.threads)) } - fn response_to_proto( - _debug_client_id: SessionId, - message: Self::Response, - ) -> Self::ProtoResponse { + fn response_to_proto(_session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapThreadsResponse { threads: message.to_proto(), } @@ -1733,7 +1655,7 @@ impl DapCommand for LocationsCommand { const CACHEABLE: bool = true; - fn client_id_from_proto(message: &Self::ProtoRequest) -> SessionId { + fn session_id_from_proto(message: &Self::ProtoRequest) -> SessionId { SessionId::from_proto(message.session_id) } diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index b54c4c1e45e0e3..e9df8c1de8eb12 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -69,7 +69,7 @@ pub enum DapStoreEvent { enum DapStoreMode { Local(LocalDapStore), Ssh(SshDapStore), - Collab, + Collab(CollabDapStore), } pub struct LocalDapStore { @@ -86,6 +86,11 @@ pub struct SshDapStore { upstream_project_id: u64, } +pub struct CollabDapStore { + upstream_client: AnyProtoClient, + project_id: u64, +} + pub struct DapStore { mode: DapStoreMode, downstream_client: Option<(AnyProtoClient, u64)>, @@ -151,13 +156,21 @@ impl DapStore { } pub fn new_collab( - _project_id: u64, - _upstream_client: AnyProtoClient, + project_id: u64, + upstream_client: AnyProtoClient, breakpoint_store: Entity, worktree_store: Entity, cx: &mut Context, ) -> Self { - Self::new(DapStoreMode::Collab, breakpoint_store, worktree_store, cx) + Self::new( + DapStoreMode::Collab(CollabDapStore { + upstream_client, + project_id, + }), + breakpoint_store, + worktree_store, + cx, + ) } fn new( @@ -275,8 +288,17 @@ impl DapStore { }) }) } - DapStoreMode::Collab => { - Task::ready(Err(anyhow!("Debugging is not yet supported via collab"))) + DapStoreMode::Collab(collab) => { + let request = collab + .upstream_client + .request(proto::GetDebugAdapterBinary { + session_id: session_id.to_proto(), + project_id: collab.project_id, + worktree_id: worktree.read(cx).id().to_proto(), + definition: Some(definition.to_proto()), + }); + + cx.background_spawn(async move { DebugAdapterBinary::from_proto(request.await?) }) } } } @@ -345,8 +367,13 @@ impl DapStore { DebugRequest::from_proto(response) }) } - DapStoreMode::Collab => { - Task::ready(Err(anyhow!("Debugging is not yet supported via collab"))) + DapStoreMode::Collab(collab) => { + let request = collab.upstream_client.request(proto::RunDebugLocators { + project_id: collab.project_id, + build_command: Some(build_command.to_proto()), + locator: locator_name.to_owned(), + }); + cx.background_spawn(async move { DebugRequest::from_proto(request.await?) }) } } } @@ -629,18 +656,22 @@ impl DapStore { }); } VariableLookupKind::Expression => { - let Ok(eval_task) = session.read_with(cx, |session, _| { - session.mode.request_dap(EvaluateCommand { - expression: inline_value_location.variable_name.clone(), - frame_id: Some(stack_frame_id), - source: None, - context: Some(EvaluateArgumentsContext::Variables), - }) + let Ok(eval_task) = session.update(cx, |session, cx| { + session.request( + EvaluateCommand { + expression: inline_value_location.variable_name.clone(), + frame_id: Some(stack_frame_id), + source: None, + context: Some(EvaluateArgumentsContext::Variables), + }, + |_, result, _| result, + cx, + ) }) else { continue; }; - if let Some(response) = eval_task.await.log_err() { + if let Some(response) = eval_task.await { inlay_hints.push(InlayHint { position, label: InlayHintLabel::String(format_value(response.result)), diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 8a7d55fc594695..40bfa01363f911 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -1,5 +1,3 @@ -use crate::debugger::breakpoint_store::BreakpointSessionState; - use super::breakpoint_store::{ BreakpointStore, BreakpointStoreEvent, BreakpointUpdatedReason, SourceBreakpoint, }; @@ -12,6 +10,8 @@ use super::dap_command::{ TerminateThreadsCommand, ThreadsCommand, VariablesCommand, }; use super::dap_store::DapStore; +use crate::debugger::breakpoint_store::BreakpointSessionState; +use crate::debugger::session; use anyhow::{Context as _, Result, anyhow}; use collections::{HashMap, HashSet, IndexMap}; use dap::adapters::{DebugAdapterBinary, DebugAdapterName}; @@ -36,8 +36,7 @@ use gpui::{ App, AppContext, AsyncApp, BackgroundExecutor, Context, Entity, EventEmitter, SharedString, Task, WeakEntity, }; - -use rpc::ErrorExt; +use rpc::{AnyProtoClient, ErrorExt}; use serde_json::Value; use smol::stream::StreamExt; use std::any::TypeId; @@ -137,6 +136,7 @@ pub struct Watcher { pub enum Mode { Building, Running(RunningMode), + Remote(RemoteMode), } #[derive(Clone)] @@ -151,6 +151,15 @@ pub struct RunningMode { messages_tx: UnboundedSender, } +#[derive(Clone)] +pub struct RemoteMode { + client: AnyProtoClient, + has_ever_stopped: bool, + upstream_project_id: u64, + executor: BackgroundExecutor, + building: bool, +} + fn client_source(abs_path: &Path) -> dap::Source { dap::Source { name: abs_path @@ -525,8 +534,49 @@ impl RunningMode { } } +impl RemoteMode { + pub fn new( + client: AnyProtoClient, + upstream_project_id: u64, + executor: BackgroundExecutor, + ) -> Self { + Self { + client, + executor, + upstream_project_id, + has_ever_stopped: false, + building: true, + } + } + + pub fn request( + &self, + session_id: SessionId, + request: R, + ) -> Task> + where + ::Response: 'static, + ::Arguments: 'static + Send, + { + let request = Arc::new(request); + + let request_clone = request.clone(); + let client = self.client.clone(); + let project_id = self.upstream_project_id; + self.executor.spawn(async move { + let args = request_clone.to_proto(session_id, project_id); + let response = client.request::(args).await?; + request.response_from_proto(response) + }) + } +} + impl Mode { - pub(super) fn request_dap(&self, request: R) -> Task> + pub(super) fn request_dap( + &self, + session_id: SessionId, + request: R, + ) -> Task> where ::Response: 'static, ::Arguments: 'static + Send, @@ -536,6 +586,7 @@ impl Mode { Mode::Building => Task::ready(Err(anyhow!( "no adapter running to send request: {request:?}" ))), + Mode::Remote(remote_mode) => remote_mode.request(session_id, request), } } @@ -544,6 +595,7 @@ impl Mode { match self { Mode::Building => false, Mode::Running(running_mode) => running_mode.has_ever_stopped, + Mode::Remote(remote_mode) => remote_mode.has_ever_stopped, } } @@ -829,7 +881,7 @@ impl Session { pub fn worktree(&self) -> Option> { match &self.mode { - Mode::Building => None, + Mode::Building | Mode::Remote(_) => None, Mode::Running(local_mode) => local_mode.worktree.upgrade(), } } @@ -951,7 +1003,7 @@ impl Session { pub fn binary(&self) -> Option<&DebugAdapterBinary> { match &self.mode { - Mode::Building => None, + Mode::Building | Mode::Remote(_) => None, Mode::Running(running_mode) => Some(&running_mode.binary), } } @@ -999,6 +1051,7 @@ impl Session { match &self.mode { Mode::Building => false, Mode::Running(running) => running.is_started, + Mode::Remote(_) => true, } } @@ -1013,14 +1066,14 @@ impl Session { pub fn as_running_mut(&mut self) -> Option<&mut RunningMode> { match &mut self.mode { Mode::Running(local_mode) => Some(local_mode), - Mode::Building => None, + Mode::Building | Mode::Remote(_) => None, } } pub fn as_running(&self) -> Option<&RunningMode> { match &self.mode { Mode::Running(local_mode) => Some(local_mode), - Mode::Building => None, + Mode::Building | Mode::Remote(_) => None, } } @@ -1226,6 +1279,7 @@ impl Session { local_mode.initialize_sequence(&self.capabilities, initialize_rx, dap_store, cx) } Mode::Building => Task::ready(Err(anyhow!("cannot initialize, still building"))), + Mode::Remote(_) => Task::ready(Err(anyhow!("cannot initialize on remote side"))), } } @@ -1260,7 +1314,7 @@ impl Session { }) .detach(); } - Mode::Building => {} + Mode::Building | Mode::Remote(_) => {} } } @@ -1494,6 +1548,7 @@ impl Session { let command = vacant.key().0.clone().as_any_arc().downcast::().unwrap(); let task = Self::request_inner::>( + &self.session_id(), &self.capabilities, &self.mode, command, @@ -1517,6 +1572,7 @@ impl Session { } fn request_inner( + session_id: SessionId, capabilities: &Capabilities, mode: &Mode, request: T, @@ -1543,7 +1599,7 @@ impl Session { }); } - let request = mode.request_dap(request); + let request = mode.request_dap(session_id, request); cx.spawn(async move |this, cx| { let result = request.await; this.update(cx, |this, cx| process_result(this, result, cx)) @@ -1552,7 +1608,7 @@ impl Session { }) } - fn request( + pub fn request( &self, request: T, process_result: impl FnOnce( @@ -1563,7 +1619,14 @@ impl Session { + 'static, cx: &mut Context, ) -> Task> { - Self::request_inner(&self.capabilities, &self.mode, request, process_result, cx) + Self::request_inner( + &self.id, + &self.capabilities, + &self.mode, + request, + process_result, + cx, + ) } fn invalidate_command_type(&mut self) { @@ -1904,7 +1967,7 @@ impl Session { pub fn adapter_client(&self) -> Option> { match self.mode { Mode::Running(ref local) => Some(local.client.clone()), - Mode::Building => None, + Mode::Building | Mode::Remote(_) => None, } } @@ -2176,12 +2239,16 @@ impl Session { frame_id: u64, cx: &mut Context, ) -> Task> { - let request = self.mode.request_dap(EvaluateCommand { - expression: expression.to_string(), - context: Some(EvaluateArgumentsContext::Watch), - frame_id: Some(frame_id), - source: None, - }); + let request = self.request( + EvaluateCommand { + expression: expression.to_string(), + context: Some(EvaluateArgumentsContext::Watch), + frame_id: Some(frame_id), + source: None, + }, + |_, result, _| result, + cx, + ); cx.spawn(async move |this, cx| { let response = request.await?; @@ -2295,12 +2362,17 @@ impl Session { location_reference: None, }; self.push_output(event, cx); - let request = self.mode.request_dap(EvaluateCommand { - expression, - context, - frame_id, - source, - }); + + let request = self.request( + EvaluateCommand { + expression, + context, + frame_id, + source, + }, + |_, result, _| result, + cx, + ); cx.spawn(async move |this, cx| { let response = request.await; this.update(cx, |this, cx| { diff --git a/crates/proto/proto/call.proto b/crates/proto/proto/call.proto index 5212f3b43f5e78..1a3e5fe2ef86d3 100644 --- a/crates/proto/proto/call.proto +++ b/crates/proto/proto/call.proto @@ -368,6 +368,7 @@ message View { Editor editor = 3; ChannelView channel_view = 4; ContextEditor context_editor = 5; + DebugSession debug_session = 7; } message Editor { @@ -390,6 +391,10 @@ message View { string context_id = 1; Editor editor = 2; } + + message DebugSession { + uint64 session_id = 1; + } } message ExcerptInsertion { diff --git a/crates/proto/proto/debugger.proto b/crates/proto/proto/debugger.proto index 3979265accaa07..e39874e166741a 100644 --- a/crates/proto/proto/debugger.proto +++ b/crates/proto/proto/debugger.proto @@ -546,3 +546,17 @@ message LogToDebugConsole { uint64 session_id = 2; string message = 3; } + +message SessionStarted { + uint64 project_id = 1; + uint64 session_id = 2; +} + +message InvalidateSessionRequest { + uint64 project_id = 1; + uint64 session_id = 2; +} + +message InvalidateSessionResponse { + uint64 session_id = 1; +} From 1137c24b8c7de6d46febb65b05d91319cea3d95a Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 21:43:26 +0200 Subject: [PATCH 02/13] More wip --- crates/project/src/debugger/dap_command.rs | 150 ++++++++++++++------- crates/project/src/debugger/dap_store.rs | 2 +- crates/project/src/debugger/session.rs | 64 ++++----- crates/proto/proto/debugger.proto | 98 +++++++++----- crates/proto/proto/zed.proto | 33 +++++ crates/proto/src/proto.rs | 60 ++++++++- 6 files changed, 282 insertions(+), 125 deletions(-) diff --git a/crates/project/src/debugger/dap_command.rs b/crates/project/src/debugger/dap_command.rs index 7dca0c639532da..5e4d81e6097d4d 100644 --- a/crates/project/src/debugger/dap_command.rs +++ b/crates/project/src/debugger/dap_command.rs @@ -151,7 +151,7 @@ impl DapCommand for NextCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -167,7 +167,7 @@ impl DapCommand for NextCommand { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> proto::DapNextRequest { proto::DapNextRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -210,14 +210,14 @@ impl DapCommand for StepInCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { Self { inner: StepCommand::from_proto(proto::DapNextRequest { project_id: request.project_id, - client_id: request.client_id, + session_id: request.session_id, thread_id: request.thread_id, single_thread: request.single_thread, granularity: request.granularity, @@ -232,7 +232,7 @@ impl DapCommand for StepInCommand { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> proto::DapStepInRequest { proto::DapStepInRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -275,14 +275,14 @@ impl DapCommand for StepOutCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { Self { inner: StepCommand::from_proto(proto::DapNextRequest { project_id: request.project_id, - client_id: request.client_id, + session_id: request.session_id, thread_id: request.thread_id, single_thread: request.single_thread, granularity: request.granularity, @@ -301,7 +301,7 @@ impl DapCommand for StepOutCommand { ) -> proto::DapStepOutRequest { proto::DapStepOutRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -346,14 +346,14 @@ impl DapCommand for StepBackCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { Self { inner: StepCommand::from_proto(proto::DapNextRequest { project_id: request.project_id, - client_id: request.client_id, + session_id: request.session_id, thread_id: request.thread_id, single_thread: request.single_thread, granularity: request.granularity, @@ -372,7 +372,7 @@ impl DapCommand for StepBackCommand { ) -> proto::DapStepBackRequest { proto::DapStepBackRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_id: self.inner.thread_id, single_thread: self.inner.single_thread, granularity: self.inner.granularity.map(|gran| gran.to_proto() as i32), @@ -410,7 +410,7 @@ impl DapCommand for ContinueCommand { type ProtoResponse = proto::DapContinueResponse; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn to_proto( @@ -420,7 +420,7 @@ impl DapCommand for ContinueCommand { ) -> proto::DapContinueRequest { proto::DapContinueRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_id: self.args.thread_id, single_thread: self.args.single_thread, } @@ -443,7 +443,7 @@ impl DapCommand for ContinueCommand { fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapContinueResponse { - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), all_threads_continued: message.all_threads_continued, } } @@ -476,7 +476,7 @@ impl DapCommand for PauseCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -488,7 +488,7 @@ impl DapCommand for PauseCommand { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> proto::DapPauseRequest { proto::DapPauseRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_id: self.thread_id, } } @@ -534,7 +534,7 @@ impl DapCommand for DisconnectCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -552,7 +552,7 @@ impl DapCommand for DisconnectCommand { ) -> proto::DapDisconnectRequest { proto::DapDisconnectRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), restart: self.restart, terminate_debuggee: self.terminate_debuggee, suspend_debuggee: self.suspend_debuggee, @@ -602,7 +602,7 @@ impl DapCommand for TerminateThreadsCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -622,7 +622,7 @@ impl DapCommand for TerminateThreadsCommand { ) -> proto::DapTerminateThreadsRequest { proto::DapTerminateThreadsRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_ids: self.thread_ids.clone().unwrap_or_default(), } } @@ -667,7 +667,7 @@ impl DapCommand for TerminateCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -683,7 +683,7 @@ impl DapCommand for TerminateCommand { ) -> proto::DapTerminateRequest { proto::DapTerminateRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), restart: self.restart, } } @@ -729,7 +729,7 @@ impl DapCommand for RestartCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -749,7 +749,7 @@ impl DapCommand for RestartCommand { proto::DapRestartRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), raw_args, } } @@ -795,18 +795,18 @@ impl LocalDapCommand for VariablesCommand { } impl DapCommand for VariablesCommand { - type ProtoRequest = proto::VariablesRequest; + type ProtoRequest = proto::DapVariablesRequest; type ProtoResponse = proto::DapVariables; const CACHEABLE: bool = true; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { - proto::VariablesRequest { + proto::DapVariablesRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), variables_reference: self.variables_reference, filter: None, start: self.start, @@ -827,7 +827,7 @@ impl DapCommand for VariablesCommand { fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapVariables { - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), variables: message.to_proto(), } } @@ -870,13 +870,13 @@ impl DapCommand for SetVariableValueCommand { type ProtoResponse = proto::DapSetVariableValueResponse; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapSetVariableValueRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), variables_reference: self.variables_reference, value: self.value.clone(), name: self.name.clone(), @@ -893,7 +893,7 @@ impl DapCommand for SetVariableValueCommand { fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapSetVariableValueResponse { - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), value: message.value, variable_type: message.type_, named_variables: message.named_variables, @@ -948,7 +948,7 @@ impl DapCommand for RestartStackFrameCommand { type ProtoResponse = proto::Ack; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -964,7 +964,7 @@ impl DapCommand for RestartStackFrameCommand { ) -> proto::DapRestartStackFrameRequest { proto::DapRestartStackFrameRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), stack_frame_id: self.stack_frame_id, } } @@ -1010,7 +1010,7 @@ impl DapCommand for ModulesCommand { const CACHEABLE: bool = true; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(_request: &Self::ProtoRequest) -> Self { @@ -1024,7 +1024,7 @@ impl DapCommand for ModulesCommand { ) -> proto::DapModulesRequest { proto::DapModulesRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), } } @@ -1034,7 +1034,7 @@ impl DapCommand for ModulesCommand { .into_iter() .map(|module| module.to_proto()) .collect(), - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), } } @@ -1077,7 +1077,7 @@ impl DapCommand for LoadedSourcesCommand { const CACHEABLE: bool = true; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(_request: &Self::ProtoRequest) -> Self { @@ -1091,7 +1091,7 @@ impl DapCommand for LoadedSourcesCommand { ) -> proto::DapLoadedSourcesRequest { proto::DapLoadedSourcesRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), } } @@ -1101,7 +1101,7 @@ impl DapCommand for LoadedSourcesCommand { .into_iter() .map(|source| source.to_proto()) .collect(), - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), } } @@ -1150,7 +1150,7 @@ impl DapCommand for StackTraceCommand { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapStackTraceRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), thread_id: self.thread_id, start_frame: self.start_frame, stack_trace_levels: self.levels, @@ -1166,7 +1166,7 @@ impl DapCommand for StackTraceCommand { } fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { @@ -1215,7 +1215,7 @@ impl DapCommand for ScopesCommand { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapScopesRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), stack_frame_id: self.stack_frame_id, } } @@ -1227,7 +1227,7 @@ impl DapCommand for ScopesCommand { } fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { @@ -1275,7 +1275,7 @@ impl DapCommand for super::session::CompletionsQuery { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapCompletionRequest { - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), project_id: upstream_project_id, frame_id: self.frame_id, query: self.query.clone(), @@ -1285,7 +1285,7 @@ impl DapCommand for super::session::CompletionsQuery { } fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -1305,7 +1305,7 @@ impl DapCommand for super::session::CompletionsQuery { fn response_to_proto(_session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { proto::DapCompletionResponse { - client_id: _session_id.to_proto(), + session_id: _session_id.to_proto(), completions: message.targets.to_proto(), } } @@ -1347,7 +1347,7 @@ impl DapCommand for EvaluateCommand { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapEvaluateRequest { - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), project_id: upstream_project_id, expression: self.expression.clone(), frame_id: self.frame_id, @@ -1359,7 +1359,7 @@ impl DapCommand for EvaluateCommand { } fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn from_proto(request: &Self::ProtoRequest) -> Self { @@ -1423,7 +1423,7 @@ impl DapCommand for ThreadsCommand { fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest { proto::DapThreadsRequest { project_id: upstream_project_id, - client_id: session_id.to_proto(), + session_id: session_id.to_proto(), } } @@ -1432,7 +1432,7 @@ impl DapCommand for ThreadsCommand { } fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { - SessionId::from_proto(request.client_id) + SessionId::from_proto(request.session_id) } fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { @@ -1626,6 +1626,54 @@ impl LocalDapCommand for SetExceptionBreakpoints { } } +impl DapCommand for SetExceptionBreakpoints { + type ProtoRequest = proto::DapSetExceptionBreakpointsRequest; + type ProtoResponse = proto::DapSetExceptionBreakpointsResponse; + + fn session_id_from_proto(message: &Self::ProtoRequest) -> SessionId { + SessionId::from_proto(message.session_id) + } + + fn from_proto(message: &Self::ProtoRequest) -> Self { + Self { + filters: message.filters.clone(), + filter_options: message.filter_options.clone(), + exception_options: message.exception_options.clone(), + } + } + + fn to_proto(&self, session_id: SessionId, project_id: u64) -> Self::ProtoRequest { + proto::DapLocationsRequest { + project_id, + session_id: session_id.to_proto(), + location_reference: self.reference, + } + } + + fn response_to_proto(_: SessionId, response: Self::Response) -> Self::ProtoResponse { + proto::DapLocationsResponse { + source: Some(response.source.to_proto()), + line: response.line, + column: response.column, + end_line: response.end_line, + end_column: response.end_column, + } + } + + fn response_from_proto(&self, response: Self::ProtoResponse) -> Result { + Ok(dap::LocationsResponse { + source: response + .source + .map(::from_proto) + .context("Missing `source` field in Locations proto")?, + line: response.line, + column: response.column, + end_line: response.end_line, + end_column: response.end_column, + }) + } +} + #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub(super) struct LocationsCommand { pub(super) reference: u64, diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index e9df8c1de8eb12..d01c89151510ba 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -664,7 +664,7 @@ impl DapStore { source: None, context: Some(EvaluateArgumentsContext::Variables), }, - |_, result, _| result, + |_, result, _| result.ok(), cx, ) }) else { diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 40bfa01363f911..6f5ead406f1453 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -11,7 +11,6 @@ use super::dap_command::{ }; use super::dap_store::DapStore; use crate::debugger::breakpoint_store::BreakpointSessionState; -use crate::debugger::session; use anyhow::{Context as _, Result, anyhow}; use collections::{HashMap, HashSet, IndexMap}; use dap::adapters::{DebugAdapterBinary, DebugAdapterName}; @@ -1539,6 +1538,7 @@ impl Session { return; } + let session_id = self.session_id(); let request_map = self .requests .entry(std::any::TypeId::of::()) @@ -1548,7 +1548,7 @@ impl Session { let command = vacant.key().0.clone().as_any_arc().downcast::().unwrap(); let task = Self::request_inner::>( - &self.session_id(), + session_id, &self.capabilities, &self.mode, command, @@ -1620,7 +1620,7 @@ impl Session { cx: &mut Context, ) -> Task> { Self::request_inner( - &self.id, + self.id.clone(), &self.capabilities, &self.mode, request, @@ -2246,24 +2246,26 @@ impl Session { frame_id: Some(frame_id), source: None, }, - |_, result, _| result, + |_, result, _| result.ok(), cx, ); cx.spawn(async move |this, cx| { - let response = request.await?; + let response = request.await; this.update(cx, |session, cx| { - session.watchers.insert( - expression.clone(), - Watcher { - expression, - value: response.result.into(), - variables_reference: response.variables_reference, - presentation_hint: response.presentation_hint, - }, - ); - cx.emit(SessionEvent::Watchers); + if let Some(response) = response { + session.watchers.insert( + expression.clone(), + Watcher { + expression, + value: response.result.into(), + variables_reference: response.variables_reference, + presentation_hint: response.presentation_hint, + }, + ); + cx.emit(SessionEvent::Watchers); + } }) }) } @@ -2370,15 +2372,15 @@ impl Session { frame_id, source, }, - |_, result, _| result, + |_, result, _| result.ok(), cx, ); cx.spawn(async move |this, cx| { let response = request.await; this.update(cx, |this, cx| { - match response { - Ok(response) => { - let event = dap::OutputEvent { + if let Some(response) = response { + this.push_output( + dap::OutputEvent { category: None, output: format!("< {}", &response.result), group: None, @@ -2388,25 +2390,11 @@ impl Session { column: None, data: None, location_reference: None, - }; - this.push_output(event, cx); - } - Err(e) => { - let event = dap::OutputEvent { - category: None, - output: format!("{}", e), - group: None, - variables_reference: None, - source: None, - line: None, - column: None, - data: None, - location_reference: None, - }; - this.push_output(event, cx); - } - }; - cx.notify(); + }, + cx, + ); + cx.notify(); + } }) .ok(); }) diff --git a/crates/proto/proto/debugger.proto b/crates/proto/proto/debugger.proto index e39874e166741a..36b4805d9eed77 100644 --- a/crates/proto/proto/debugger.proto +++ b/crates/proto/proto/debugger.proto @@ -52,9 +52,9 @@ message ValueFormat { optional bool hex = 1; } -message VariablesRequest { +message DapVariablesRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 variables_reference = 3; optional VariablesArgumentsFilter filter = 4; optional uint64 start = 5; @@ -93,7 +93,7 @@ enum DapEvaluateContext { message DapEvaluateRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; string expression = 3; optional uint64 frame_id = 4; optional DapEvaluateContext context = 5; @@ -111,7 +111,7 @@ message DapEvaluateResponse { message DapCompletionRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; string query = 3; optional uint64 frame_id = 4; optional uint64 line = 5; @@ -153,13 +153,13 @@ message DapCompletionItem { } message DapCompletionResponse { - uint64 client_id = 1; + uint64 session_id = 1; repeated DapCompletionItem completions = 2; } message DapScopesRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 stack_frame_id = 3; } @@ -169,14 +169,14 @@ message DapScopesResponse { message DapSetVariableValueRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; string name = 3; string value = 4; uint64 variables_reference = 5; } message DapSetVariableValueResponse { - uint64 client_id = 1; + uint64 session_id = 1; string value = 2; optional string variable_type = 3; optional uint64 variables_reference = 4; @@ -187,13 +187,13 @@ message DapSetVariableValueResponse { message DapPauseRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 thread_id = 3; } message DapDisconnectRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; optional bool restart = 3; optional bool terminate_debuggee = 4; optional bool suspend_debuggee = 5; @@ -201,13 +201,13 @@ message DapDisconnectRequest { message DapTerminateThreadsRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; repeated uint64 thread_ids = 3; } message DapThreadsRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; } message DapThreadsResponse { @@ -216,19 +216,19 @@ message DapThreadsResponse { message DapTerminateRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; optional bool restart = 3; } message DapRestartRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; bytes raw_args = 3; } message DapRestartStackFrameRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 stack_frame_id = 3; } @@ -245,7 +245,7 @@ message IgnoreBreakpointState { message DapNextRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 thread_id = 3; optional bool single_thread = 4; optional SteppingGranularity granularity = 5; @@ -253,7 +253,7 @@ message DapNextRequest { message DapStepInRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 thread_id = 3; optional uint64 target_id = 4; optional bool single_thread = 5; @@ -262,7 +262,7 @@ message DapStepInRequest { message DapStepOutRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 thread_id = 3; optional bool single_thread = 4; optional SteppingGranularity granularity = 5; @@ -270,7 +270,7 @@ message DapStepOutRequest { message DapStepBackRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 thread_id = 3; optional bool single_thread = 4; optional SteppingGranularity granularity = 5; @@ -278,39 +278,39 @@ message DapStepBackRequest { message DapContinueRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 thread_id = 3; optional bool single_thread = 4; } message DapContinueResponse { - uint64 client_id = 1; + uint64 session_id = 1; optional bool all_threads_continued = 2; } message DapModulesRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; } message DapModulesResponse { - uint64 client_id = 1; + uint64 session_id = 1; repeated DapModule modules = 2; } message DapLoadedSourcesRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; } message DapLoadedSourcesResponse { - uint64 client_id = 1; + uint64 session_id = 1; repeated DapSource sources = 2; } message DapStackTraceRequest { uint64 project_id = 1; - uint64 client_id = 2; + uint64 session_id = 2; uint64 thread_id = 3; optional uint64 start_frame = 4; optional uint64 stack_trace_levels = 5; @@ -334,13 +334,25 @@ message DapStackFrame { optional DapStackPresentationHint presentation_hint = 11; } +message DapSetExceptionBreakpointsRequest { + uint64 project_id = 1; + uint64 session_id = 2; + repeated string filters = 3; + repeated ExceptionFilterOptions filter_options = 4; + repeated ExceptionOptions exception_options = 5; +} + +message DapSetExceptionBreakpointsResponse { + repeated Breakpoint breakpoints = 1; +} + message DebuggerLoadedSourceList { - uint64 client_id = 1; + uint64 session_id = 1; repeated DapSource sources = 2; } -message DapVariables { - uint64 client_id = 1; +message DapVariablesResponse { + uint64 session_id = 1; repeated DapVariable variables = 2; } @@ -445,6 +457,30 @@ enum DapStackPresentationHint { Subtle = 2; StackUnknown = 3; } + +enum ExceptionBreakMode { + Never = 0; + Always = 1; + Unhandled = 2; + AlwaysUnhandled = 3; +} + +message ExceptionPathSegment { + optional bool negate = 1; + repeated string names = 2; +} + +message ExceptionOptions { + repeated ExceptionPathSegment path = 1; + ExceptionBreakMode break_mode = 2; +} + +message ExceptionFilterOptions { + string filter_id = 1; + optional string condition = 2; + optional string mode = 3; +} + message DapModule { DapModuleId id = 1; string name = 2; @@ -556,7 +592,3 @@ message InvalidateSessionRequest { uint64 project_id = 1; uint64 session_id = 2; } - -message InvalidateSessionResponse { - uint64 session_id = 1; -} diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index 31f929ec9054c1..1582f466646432 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -398,6 +398,39 @@ message Envelope { GetColorPresentation get_color_presentation = 355; GetColorPresentationResponse get_color_presentation_response = 356; // current max + DapNextRequest dap_next_request = 357; + DapStepInRequest dap_step_in_request = 358; + DapStepOutRequest dap_step_out_request = 359; + DapStepBackRequest dap_step_back_request = 360; + DapContinueRequest dap_continue_request = 361; + DapPauseRequest dap_pause_request = 362; + DapDisconnectRequest dap_disconnect_request = 363; + DapTerminateThreadsRequest dap_terminate_threads_request = 364; + DapTerminateRequest dap_terminate_request = 365; + DapRestartRequest dap_restart_request = 366; + DapVariablesRequest dap_variables_request = 367; + DapVariablesResponse dap_variables_response = 368; + DapSetVariableValueRequest dap_set_variable_value_request = 369; + DapSetVariableValueResponse dap_set_variable_value_response = 370; + DapRestartStackFrameRequest dap_restart_stack_frame_request = 371; + DapModulesRequest dap_modules_request = 372; + DapModulesResponse dap_modules_response = 373; + DapLoadedSourcesRequest dap_loaded_sources_request = 374; + DapLoadedSourcesResponse dap_loaded_sources_response = 375; + DapStackTraceRequest dap_stack_trace_request = 376; + DapStackTraceResponse dap_stack_trace_response = 377; + DapScopesRequest dap_scopes_request = 378; + DapScopesResponse dap_scopes_response = 379; + DapCompletionRequest dap_completion_request = 380; + DapCompletionResponse dap_completion_response = 381; + DapEvaluateRequest dap_evaluate_request = 382; + DapEvaluateResponse dap_evaluate_response = 383; + DapThreadsRequest dap_threads_request = 384; + DapThreadsResponse dap_threads_response = 385; + DapLocationsRequest dap_locations_request = 386; + DapLocationsResponse dap_locations_response = 387; + DapSetExceptionBreakpointsRequest dap_set_exception_breakpoints_request = 388; + DapSetExceptionBreakpointsResponse dap_set_exception_breakpoints_response = 389; } reserved 87 to 88; diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index e3aeb557ab3f55..abd28eedf6c3f1 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -313,7 +313,38 @@ messages!( (LogToDebugConsole, Background), (GetDocumentDiagnostics, Background), (GetDocumentDiagnosticsResponse, Background), - (PullWorkspaceDiagnostics, Background) + (PullWorkspaceDiagnostics, Background), + (DapNextRequest, Background), + (DapStepInRequest, Background), + (DapStepOutRequest, Background), + (DapStepBackRequest, Background), + (DapContinueRequest, Background), + (DapPauseRequest, Background), + (DapDisconnectRequest, Background), + (DapTerminateRequest, Background), + (DapRestartRequest, Background), + (DapVariablesRequest, Background), + (DapSetVariableValueRequest, Background), + (DapSetVariableValueResponse, Background), + (DapRestartStackFrameRequest, Background), + (DapModulesRequest, Background), + (DapModulesResponse, Background), + (DapLoadedSourcesRequest, Background), + (DapLoadedSourcesResponse, Background), + (DapStackTraceRequest, Background), + (DapStackTraceResponse, Background), + (DapScopesRequest, Background), + (DapScopesResponse, Background), + (DapCompletionRequest, Background), + (DapCompletionResponse, Background), + (DapEvaluateRequest, Background), + (DapEvaluateResponse, Background), + (DapThreadsRequest, Background), + (DapThreadsResponse, Background), + (DapLocationsRequest, Background), + (DapLocationsResponse, Background), + (DapSetExceptionBreakpointsRequest, Background), + (DapSetExceptionBreakpointsResponse, Background), ); request_messages!( @@ -479,7 +510,32 @@ request_messages!( (GetDebugAdapterBinary, DebugAdapterBinary), (RunDebugLocators, DebugRequest), (GetDocumentDiagnostics, GetDocumentDiagnosticsResponse), - (PullWorkspaceDiagnostics, Ack) + (PullWorkspaceDiagnostics, Ack), + // debugger + (DapNextRequest, Ack), + (DapStepInRequest, Ack), + (DapStepOutRequest, Ack), + (DapStepBackRequest, Ack), + (DapContinueRequest, Ack), + (DapPauseRequest, Ack), + (DapDisconnectRequest, Ack), + (DapTerminateRequest, Ack), + (DapRestartRequest, Ack), + (VariablesRequest, DapVariables), // TODO: + (DapSetVariableValueRequest, DapSetVariableValueResponse), + (DapRestartStackFrameRequest, Ack), + (DapModulesRequest, DapModulesResponse), + (DapLoadedSourcesRequest, DapLoadedSourcesResponse), + (DapStackTraceRequest, DapStackTraceResponse), + (DapScopesRequest, DapScopesResponse), + (DapCompletionRequest, DapCompletionResponse), + (DapEvaluateRequest, DapEvaluateResponse), + (DapThreadsRequest, DapThreadsResponse), + (DapLocationsRequest, DapLocationsResponse), + ( + DapSetExceptionBreakpointsRequest, + DapSetExceptionBreakpointsResponse + ), ); entity_messages!( From 53d719e1b37db0d823a66885b5361f395d53e26a Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 23:16:30 +0200 Subject: [PATCH 03/13] More wip wip --- crates/dap/src/proto_conversions.rs | 164 +++++++++++++++++++++ crates/project/src/debugger/dap_command.rs | 102 +++++++------ crates/project/src/debugger/session.rs | 17 ++- crates/proto/proto/debugger.proto | 21 ++- crates/proto/src/proto.rs | 6 +- 5 files changed, 248 insertions(+), 62 deletions(-) diff --git a/crates/dap/src/proto_conversions.rs b/crates/dap/src/proto_conversions.rs index 7b7324644b3b91..f6d5a0c3b5d381 100644 --- a/crates/dap/src/proto_conversions.rs +++ b/crates/dap/src/proto_conversions.rs @@ -589,3 +589,167 @@ impl ProtoConversion for dap_types::Thread { } } } + +impl ProtoConversion for dap_types::ExceptionBreakMode { + type ProtoType = proto::ExceptionBreakMode; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + match self { + dap_types::ExceptionBreakMode::Never => proto::ExceptionBreakMode::Never, + dap_types::ExceptionBreakMode::Always => proto::ExceptionBreakMode::Always, + dap_types::ExceptionBreakMode::Unhandled => proto::ExceptionBreakMode::Unhandled, + dap_types::ExceptionBreakMode::UserUnhandled => { + proto::ExceptionBreakMode::AlwaysUnhandled + } + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + match payload { + proto::ExceptionBreakMode::Never => dap_types::ExceptionBreakMode::Never, + proto::ExceptionBreakMode::Always => dap_types::ExceptionBreakMode::Always, + proto::ExceptionBreakMode::Unhandled => dap_types::ExceptionBreakMode::Unhandled, + proto::ExceptionBreakMode::AlwaysUnhandled => { + dap_types::ExceptionBreakMode::UserUnhandled + } + } + } +} + +impl ProtoConversion for dap_types::ExceptionPathSegment { + type ProtoType = proto::ExceptionPathSegment; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + proto::ExceptionPathSegment { + negate: self.negate, + names: self.names.clone(), + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + Self { + negate: payload.negate, + names: payload.names, + } + } +} + +impl ProtoConversion for dap_types::ExceptionOptions { + type ProtoType = proto::ExceptionOptions; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + proto::ExceptionOptions { + path: self.path.as_ref().map(|p| p.to_proto()).unwrap_or_default(), + break_mode: self.break_mode.to_proto() as i32, + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + Self { + path: if payload.path.is_empty() { + None + } else { + Some( + payload + .path + .into_iter() + .map(|p| dap_types::ExceptionPathSegment::from_proto(p)) + .collect(), + ) + }, + break_mode: match payload.break_mode { + 0 => dap_types::ExceptionBreakMode::Never, + 1 => dap_types::ExceptionBreakMode::Always, + 2 => dap_types::ExceptionBreakMode::Unhandled, + 3 => dap_types::ExceptionBreakMode::UserUnhandled, + _ => dap_types::ExceptionBreakMode::Never, + }, + } + } +} + +impl ProtoConversion for dap_types::ExceptionFilterOptions { + type ProtoType = proto::ExceptionFilterOptions; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + proto::ExceptionFilterOptions { + filter_id: self.filter_id.clone(), + condition: self.condition.clone(), + mode: self.mode.clone(), + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + Self { + filter_id: payload.filter_id, + condition: payload.condition, + mode: payload.mode, + } + } +} + +impl ProtoConversion for dap_types::BreakpointReason { + type ProtoType = proto::DapBreakpointReason; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + match self { + dap_types::BreakpointReason::Pending => proto::DapBreakpointReason::Pending, + dap_types::BreakpointReason::Failed => proto::DapBreakpointReason::Failed, + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + match payload { + proto::DapBreakpointReason::Pending => dap_types::BreakpointReason::Pending, + proto::DapBreakpointReason::Failed => dap_types::BreakpointReason::Failed, + } + } +} + +impl ProtoConversion for dap_types::Breakpoint { + type ProtoType = proto::DapBreakpoint; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + proto::DapBreakpoint { + id: self.id.map(|id| id as i64), + verified: self.verified, + message: self.message.clone(), + source: self.source.as_ref().map(|source| source.to_proto()), + line: self.line.map(|line| line as u32), + column: self.column.map(|column| column as u32), + end_line: self.end_line.map(|line| line as u32), + end_column: self.end_column.map(|column| column as u32), + instruction_reference: self.instruction_reference.clone(), + offset: self.offset.map(|offset| offset as u32), + reason: self.reason.as_ref().map(|reason| reason.to_proto() as i32), + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + Self { + id: payload.id.map(|id| id as u64), + verified: payload.verified, + message: payload.message, + source: payload + .source + .map(|source| dap_types::Source::from_proto(source)), + line: payload.line.map(|line| line as u64), + column: payload.column.map(|column| column as u64), + end_line: payload.end_line.map(|line| line as u64), + end_column: payload.end_column.map(|column| column as u64), + instruction_reference: payload.instruction_reference, + offset: payload.offset.map(|offset| offset as u64), + reason: payload.reason.and_then(|reason| match reason { + 0 => Some(dap_types::BreakpointReason::Pending), + 1 => Some(dap_types::BreakpointReason::Failed), + _ => None, + }), + } + } +} diff --git a/crates/project/src/debugger/dap_command.rs b/crates/project/src/debugger/dap_command.rs index 5e4d81e6097d4d..c875674f1d0ad6 100644 --- a/crates/project/src/debugger/dap_command.rs +++ b/crates/project/src/debugger/dap_command.rs @@ -2,10 +2,10 @@ use std::sync::Arc; use anyhow::{Context as _, Ok, Result}; use dap::{ - Capabilities, ContinueArguments, ExceptionFilterOptions, InitializeRequestArguments, - InitializeRequestArgumentsPathFormat, NextArguments, SetVariableResponse, SourceBreakpoint, - StepInArguments, StepOutArguments, SteppingGranularity, ValueFormat, Variable, - VariablesArgumentsFilter, + Breakpoint, Capabilities, ContinueArguments, ExceptionFilterOptions, ExceptionOptions, + InitializeRequestArguments, InitializeRequestArgumentsPathFormat, NextArguments, + SetVariableResponse, SourceBreakpoint, StepInArguments, StepOutArguments, SteppingGranularity, + ValueFormat, Variable, VariablesArgumentsFilter, client::SessionId, proto_conversions::ProtoConversion, requests::{Continue, Next}, @@ -31,23 +31,19 @@ pub trait LocalDapCommand: 'static + Send + Sync + std::fmt::Debug { } pub trait DapCommand: LocalDapCommand { - type ProtoRequest: 'static + Send; + type ProtoRequest: 'static + Send + proto::RequestMessage; type ProtoResponse: 'static + Send; const CACHEABLE: bool = false; - #[allow(dead_code)] fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId; - #[allow(dead_code)] fn from_proto(request: &Self::ProtoRequest) -> Self; #[allow(unused)] fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest; - #[allow(dead_code)] fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse; - #[allow(unused)] fn response_from_proto(&self, message: Self::ProtoResponse) -> Result; } @@ -796,7 +792,7 @@ impl LocalDapCommand for VariablesCommand { impl DapCommand for VariablesCommand { type ProtoRequest = proto::DapVariablesRequest; - type ProtoResponse = proto::DapVariables; + type ProtoResponse = proto::DapVariablesResponse; const CACHEABLE: bool = true; fn session_id_from_proto(request: &Self::ProtoRequest) -> SessionId { @@ -826,7 +822,7 @@ impl DapCommand for VariablesCommand { } fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse { - proto::DapVariables { + proto::DapVariablesResponse { session_id: session_id.to_proto(), variables: message.to_proto(), } @@ -1587,14 +1583,12 @@ impl LocalDapCommand for SetBreakpoints { Ok(message.breakpoints) } } -#[derive(Clone, Debug, Hash, PartialEq)] -pub(super) enum SetExceptionBreakpoints { - Plain { - filters: Vec, - }, - WithOptions { - filters: Vec, - }, + +#[derive(Clone, Debug)] +pub(super) struct SetExceptionBreakpoints { + pub filters: Vec, + pub filter_options: Vec, + pub exception_filters: Vec, } impl LocalDapCommand for SetExceptionBreakpoints { @@ -1602,19 +1596,10 @@ impl LocalDapCommand for SetExceptionBreakpoints { type DapRequest = dap::requests::SetExceptionBreakpoints; fn to_dap(&self) -> ::Arguments { - match self { - SetExceptionBreakpoints::Plain { filters } => dap::SetExceptionBreakpointsArguments { - filters: filters.clone(), - exception_options: None, - filter_options: None, - }, - SetExceptionBreakpoints::WithOptions { filters } => { - dap::SetExceptionBreakpointsArguments { - filters: vec![], - filter_options: Some(filters.clone()), - exception_options: None, - } - } + dap::SetExceptionBreakpointsArguments { + filters: self.filters.clone(), + exception_options: Some(self.exception_filters.clone()), + filter_options: Some(self.filter_options.clone()), } } @@ -1637,40 +1622,53 @@ impl DapCommand for SetExceptionBreakpoints { fn from_proto(message: &Self::ProtoRequest) -> Self { Self { filters: message.filters.clone(), - filter_options: message.filter_options.clone(), - exception_options: message.exception_options.clone(), + filter_options: message + .filter_options + .clone() + .into_iter() + .map(ExceptionFilterOptions::from_proto) + .collect(), + exception_filters: message + .exception_options + .clone() + .into_iter() + .map(ExceptionOptions::from_proto) + .collect(), } } fn to_proto(&self, session_id: SessionId, project_id: u64) -> Self::ProtoRequest { - proto::DapLocationsRequest { + proto::DapSetExceptionBreakpointsRequest { project_id, session_id: session_id.to_proto(), - location_reference: self.reference, + filters: self.filters.clone(), + exception_options: self + .exception_filters + .clone() + .into_iter() + .map(|filter| filter.to_proto()) + .collect(), + filter_options: self + .filter_options + .clone() + .into_iter() + .map(|filter| filter.to_proto()) + .collect(), } } fn response_to_proto(_: SessionId, response: Self::Response) -> Self::ProtoResponse { - proto::DapLocationsResponse { - source: Some(response.source.to_proto()), - line: response.line, - column: response.column, - end_line: response.end_line, - end_column: response.end_column, + proto::DapSetExceptionBreakpointsResponse { + breakpoints: response.to_proto(), } } fn response_from_proto(&self, response: Self::ProtoResponse) -> Result { - Ok(dap::LocationsResponse { - source: response - .source - .map(::from_proto) - .context("Missing `source` field in Locations proto")?, - line: response.line, - column: response.column, - end_line: response.end_line, - end_column: response.end_column, - }) + Ok(response + .breakpoints + .into_iter() + .map(Breakpoint::from_proto) + .collect()) } } diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 6f5ead406f1453..3f8b5ab74875ca 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -305,9 +305,9 @@ impl RunningMode { filters: Vec, supports_filter_options: bool, ) -> Task>> { - let arg = if supports_filter_options { - SetExceptionBreakpoints::WithOptions { - filters: filters + self.request(if supports_filter_options { + SetExceptionBreakpoints { + filter_options: filters .into_iter() .map(|filter| ExceptionFilterOptions { filter_id: filter.filter, @@ -315,13 +315,16 @@ impl RunningMode { mode: None, }) .collect(), + filters: Vec::new(), + exception_filters: Vec::new(), } } else { - SetExceptionBreakpoints::Plain { + SetExceptionBreakpoints { filters: filters.into_iter().map(|filter| filter.filter).collect(), + filter_options: Vec::new(), + exception_filters: Vec::new(), } - }; - self.request(arg) + }) } fn send_source_breakpoints( @@ -563,7 +566,7 @@ impl RemoteMode { let client = self.client.clone(); let project_id = self.upstream_project_id; self.executor.spawn(async move { - let args = request_clone.to_proto(session_id, project_id); + let args = request_clone.(session_id, project_id); let response = client.request::(args).await?; request.response_from_proto(response) }) diff --git a/crates/proto/proto/debugger.proto b/crates/proto/proto/debugger.proto index 36b4805d9eed77..be0c7155d36ea1 100644 --- a/crates/proto/proto/debugger.proto +++ b/crates/proto/proto/debugger.proto @@ -343,7 +343,7 @@ message DapSetExceptionBreakpointsRequest { } message DapSetExceptionBreakpointsResponse { - repeated Breakpoint breakpoints = 1; + repeated DapBreakpoint breakpoints = 1; } message DebuggerLoadedSourceList { @@ -481,6 +481,25 @@ message ExceptionFilterOptions { optional string mode = 3; } +enum DapBreakpointReason { + Pending = 0; + Failed = 1; +} + +message DapBreakpoint { + optional int64 id = 1; + bool verified = 2; + optional string message = 3; + optional DapSource source = 4; + optional uint32 line = 5; + optional uint32 column = 6; + optional uint32 end_line = 7; + optional uint32 end_column = 8; + optional string instruction_reference = 9; + optional uint32 offset = 10; + optional DapBreakpointReason reason = 11; +} + message DapModule { DapModuleId id = 1; string name = 2; diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index abd28eedf6c3f1..33b6ac629da9c3 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -324,6 +324,7 @@ messages!( (DapTerminateRequest, Background), (DapRestartRequest, Background), (DapVariablesRequest, Background), + (DapVariablesResponse, Background), (DapSetVariableValueRequest, Background), (DapSetVariableValueResponse, Background), (DapRestartStackFrameRequest, Background), @@ -345,6 +346,7 @@ messages!( (DapLocationsResponse, Background), (DapSetExceptionBreakpointsRequest, Background), (DapSetExceptionBreakpointsResponse, Background), + (DapTerminateThreadsRequest, Background), ); request_messages!( @@ -511,7 +513,6 @@ request_messages!( (RunDebugLocators, DebugRequest), (GetDocumentDiagnostics, GetDocumentDiagnosticsResponse), (PullWorkspaceDiagnostics, Ack), - // debugger (DapNextRequest, Ack), (DapStepInRequest, Ack), (DapStepOutRequest, Ack), @@ -521,7 +522,7 @@ request_messages!( (DapDisconnectRequest, Ack), (DapTerminateRequest, Ack), (DapRestartRequest, Ack), - (VariablesRequest, DapVariables), // TODO: + (DapVariablesRequest, DapVariablesResponse), (DapSetVariableValueRequest, DapSetVariableValueResponse), (DapRestartStackFrameRequest, Ack), (DapModulesRequest, DapModulesResponse), @@ -536,6 +537,7 @@ request_messages!( DapSetExceptionBreakpointsRequest, DapSetExceptionBreakpointsResponse ), + (DapTerminateThreadsRequest, Ack), ); entity_messages!( From 547b83b7d99c0daa91e05dfe13f9a37abce09a82 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 23:17:00 +0200 Subject: [PATCH 04/13] ooops --- crates/project/src/debugger/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 3f8b5ab74875ca..6d048ef939ed61 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -566,7 +566,7 @@ impl RemoteMode { let client = self.client.clone(); let project_id = self.upstream_project_id; self.executor.spawn(async move { - let args = request_clone.(session_id, project_id); + let args = request_clone.to_proto(session_id, project_id); let response = client.request::(args).await?; request.response_from_proto(response) }) From 814bf1adaa27b9e4ba08824ef41f5a6f05939ba1 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 23:26:17 +0200 Subject: [PATCH 05/13] Add supports --- crates/project/src/debugger/dap_command.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/project/src/debugger/dap_command.rs b/crates/project/src/debugger/dap_command.rs index c875674f1d0ad6..5250f46f7fdf30 100644 --- a/crates/project/src/debugger/dap_command.rs +++ b/crates/project/src/debugger/dap_command.rs @@ -1595,6 +1595,16 @@ impl LocalDapCommand for SetExceptionBreakpoints { type Response = Vec; type DapRequest = dap::requests::SetExceptionBreakpoints; + fn is_supported(capabilities: &Capabilities) -> bool { + capabilities.exception_breakpoint_filters.is_some() + || capabilities + .supports_exception_filter_options + .is_some_and(|supported| supported) + || capabilities + .supports_exception_options + .is_some_and(|supported| supported) + } + fn to_dap(&self) -> ::Arguments { dap::SetExceptionBreakpointsArguments { filters: self.filters.clone(), From 07e76b90c22663f6cc5b6327a3b5fc72f97ea45a Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 23:36:05 +0200 Subject: [PATCH 06/13] Fix continue proto message --- crates/proto/src/proto.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index 33b6ac629da9c3..a562969f371ee8 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -319,6 +319,7 @@ messages!( (DapStepOutRequest, Background), (DapStepBackRequest, Background), (DapContinueRequest, Background), + (DapContinueResponse, Background), (DapPauseRequest, Background), (DapDisconnectRequest, Background), (DapTerminateRequest, Background), @@ -517,7 +518,7 @@ request_messages!( (DapStepInRequest, Ack), (DapStepOutRequest, Ack), (DapStepBackRequest, Ack), - (DapContinueRequest, Ack), + (DapContinueRequest, DapContinueResponse), (DapPauseRequest, Ack), (DapDisconnectRequest, Ack), (DapTerminateRequest, Ack), From fdd2ae1722506906ea579b39e34daa1e1719b6d8 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 23:38:04 +0200 Subject: [PATCH 07/13] oops --- crates/proto/proto/zed.proto | 57 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index 1582f466646432..eaa3d8be0a5b8b 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -403,34 +403,35 @@ message Envelope { DapStepOutRequest dap_step_out_request = 359; DapStepBackRequest dap_step_back_request = 360; DapContinueRequest dap_continue_request = 361; - DapPauseRequest dap_pause_request = 362; - DapDisconnectRequest dap_disconnect_request = 363; - DapTerminateThreadsRequest dap_terminate_threads_request = 364; - DapTerminateRequest dap_terminate_request = 365; - DapRestartRequest dap_restart_request = 366; - DapVariablesRequest dap_variables_request = 367; - DapVariablesResponse dap_variables_response = 368; - DapSetVariableValueRequest dap_set_variable_value_request = 369; - DapSetVariableValueResponse dap_set_variable_value_response = 370; - DapRestartStackFrameRequest dap_restart_stack_frame_request = 371; - DapModulesRequest dap_modules_request = 372; - DapModulesResponse dap_modules_response = 373; - DapLoadedSourcesRequest dap_loaded_sources_request = 374; - DapLoadedSourcesResponse dap_loaded_sources_response = 375; - DapStackTraceRequest dap_stack_trace_request = 376; - DapStackTraceResponse dap_stack_trace_response = 377; - DapScopesRequest dap_scopes_request = 378; - DapScopesResponse dap_scopes_response = 379; - DapCompletionRequest dap_completion_request = 380; - DapCompletionResponse dap_completion_response = 381; - DapEvaluateRequest dap_evaluate_request = 382; - DapEvaluateResponse dap_evaluate_response = 383; - DapThreadsRequest dap_threads_request = 384; - DapThreadsResponse dap_threads_response = 385; - DapLocationsRequest dap_locations_request = 386; - DapLocationsResponse dap_locations_response = 387; - DapSetExceptionBreakpointsRequest dap_set_exception_breakpoints_request = 388; - DapSetExceptionBreakpointsResponse dap_set_exception_breakpoints_response = 389; + DapContinueResponse dap_continue_response = 362; + DapPauseRequest dap_pause_request = 363; + DapDisconnectRequest dap_disconnect_request = 364; + DapTerminateThreadsRequest dap_terminate_threads_request = 365; + DapTerminateRequest dap_terminate_request = 366; + DapRestartRequest dap_restart_request = 367; + DapVariablesRequest dap_variables_request = 368; + DapVariablesResponse dap_variables_response = 369; + DapSetVariableValueRequest dap_set_variable_value_request = 370; + DapSetVariableValueResponse dap_set_variable_value_response = 371; + DapRestartStackFrameRequest dap_restart_stack_frame_request = 372; + DapModulesRequest dap_modules_request = 373; + DapModulesResponse dap_modules_response = 374; + DapLoadedSourcesRequest dap_loaded_sources_request = 375; + DapLoadedSourcesResponse dap_loaded_sources_response = 376; + DapStackTraceRequest dap_stack_trace_request = 377; + DapStackTraceResponse dap_stack_trace_response = 378; + DapScopesRequest dap_scopes_request = 379; + DapScopesResponse dap_scopes_response = 380; + DapCompletionRequest dap_completion_request = 381; + DapCompletionResponse dap_completion_response = 382; + DapEvaluateRequest dap_evaluate_request = 383; + DapEvaluateResponse dap_evaluate_response = 384; + DapThreadsRequest dap_threads_request = 385; + DapThreadsResponse dap_threads_response = 386; + DapLocationsRequest dap_locations_request = 387; + DapLocationsResponse dap_locations_response = 388; + DapSetExceptionBreakpointsRequest dap_set_exception_breakpoints_request = 389; + DapSetExceptionBreakpointsResponse dap_set_exception_breakpoints_response = 390; } reserved 87 to 88; From fe9f232a37b5a1275dc0ce95531f8c3d7e735bd7 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 1 Jul 2025 23:40:54 +0200 Subject: [PATCH 08/13] update comment --- crates/proto/proto/zed.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index eaa3d8be0a5b8b..6d5b07464fd316 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -396,7 +396,7 @@ message Envelope { GetDocumentColor get_document_color = 353; GetDocumentColorResponse get_document_color_response = 354; GetColorPresentation get_color_presentation = 355; - GetColorPresentationResponse get_color_presentation_response = 356; // current max + GetColorPresentationResponse get_color_presentation_response = 356; DapNextRequest dap_next_request = 357; DapStepInRequest dap_step_in_request = 358; @@ -431,7 +431,7 @@ message Envelope { DapLocationsRequest dap_locations_request = 387; DapLocationsResponse dap_locations_response = 388; DapSetExceptionBreakpointsRequest dap_set_exception_breakpoints_request = 389; - DapSetExceptionBreakpointsResponse dap_set_exception_breakpoints_response = 390; + DapSetExceptionBreakpointsResponse dap_set_exception_breakpoints_response = 390; // current max } reserved 87 to 88; From a31cd7be54d6eb7d1d46a603d923811448391615 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Wed, 2 Jul 2025 00:04:07 +0200 Subject: [PATCH 09/13] Make it compile --- crates/project/src/debugger/dap_command.rs | 121 ++++++++++++++++----- crates/project/src/debugger/session.rs | 14 +-- 2 files changed, 99 insertions(+), 36 deletions(-) diff --git a/crates/project/src/debugger/dap_command.rs b/crates/project/src/debugger/dap_command.rs index 5250f46f7fdf30..17391aeecd7894 100644 --- a/crates/project/src/debugger/dap_command.rs +++ b/crates/project/src/debugger/dap_command.rs @@ -39,12 +39,14 @@ pub trait DapCommand: LocalDapCommand { fn from_proto(request: &Self::ProtoRequest) -> Self; - #[allow(unused)] fn to_proto(&self, session_id: SessionId, upstream_project_id: u64) -> Self::ProtoRequest; fn response_to_proto(session_id: SessionId, message: Self::Response) -> Self::ProtoResponse; - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result; + fn response_from_proto( + &self, + message: ::Response, + ) -> Result; } impl LocalDapCommand for Arc { @@ -87,7 +89,10 @@ impl DapCommand for Arc { T::response_to_proto(session_id, message) } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { T::response_from_proto(self, message) } } @@ -170,7 +175,10 @@ impl DapCommand for NextCommand { } } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -236,7 +244,10 @@ impl DapCommand for StepInCommand { } } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -304,7 +315,10 @@ impl DapCommand for StepOutCommand { } } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -375,7 +389,10 @@ impl DapCommand for StepBackCommand { } } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -431,7 +448,10 @@ impl DapCommand for ContinueCommand { } } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(Self::Response { all_threads_continued: message.all_threads_continued, }) @@ -493,7 +513,10 @@ impl DapCommand for PauseCommand { proto::Ack {} } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -559,7 +582,10 @@ impl DapCommand for DisconnectCommand { proto::Ack {} } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -627,7 +653,10 @@ impl DapCommand for TerminateThreadsCommand { proto::Ack {} } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -688,7 +717,10 @@ impl DapCommand for TerminateCommand { proto::Ack {} } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -754,7 +786,10 @@ impl DapCommand for RestartCommand { proto::Ack {} } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -828,7 +863,10 @@ impl DapCommand for VariablesCommand { } } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(Vec::from_proto(message.variables)) } } @@ -899,7 +937,10 @@ impl DapCommand for SetVariableValueCommand { } } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(SetVariableResponse { value: message.value, type_: message.variable_type, @@ -969,7 +1010,10 @@ impl DapCommand for RestartStackFrameCommand { proto::Ack {} } - fn response_from_proto(&self, _message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + _message: ::Response, + ) -> Result { Ok(()) } } @@ -1034,7 +1078,10 @@ impl DapCommand for ModulesCommand { } } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(message .modules .into_iter() @@ -1101,7 +1148,10 @@ impl DapCommand for LoadedSourcesCommand { } } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(message .sources .into_iter() @@ -1165,7 +1215,10 @@ impl DapCommand for StackTraceCommand { SessionId::from_proto(request.session_id) } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(message .frames .into_iter() @@ -1226,7 +1279,10 @@ impl DapCommand for ScopesCommand { SessionId::from_proto(request.session_id) } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(Vec::from_proto(message.scopes)) } @@ -1293,7 +1349,10 @@ impl DapCommand for super::session::CompletionsQuery { } } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(dap::CompletionsResponse { targets: Vec::from_proto(message.completions), }) @@ -1367,7 +1426,10 @@ impl DapCommand for EvaluateCommand { } } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(dap::EvaluateResponse { result: message.result.clone(), type_: message.evaluate_type.clone(), @@ -1431,7 +1493,10 @@ impl DapCommand for ThreadsCommand { SessionId::from_proto(request.session_id) } - fn response_from_proto(&self, message: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + message: ::Response, + ) -> Result { Ok(Vec::from_proto(message.threads)) } @@ -1673,7 +1738,10 @@ impl DapCommand for SetExceptionBreakpoints { } } - fn response_from_proto(&self, response: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + response: ::Response, + ) -> Result { Ok(response .breakpoints .into_iter() @@ -1739,7 +1807,10 @@ impl DapCommand for LocationsCommand { } } - fn response_from_proto(&self, response: Self::ProtoResponse) -> Result { + fn response_from_proto( + &self, + response: ::Response, + ) -> Result { Ok(dap::LocationsResponse { source: response .source diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 6d048ef939ed61..f8dbf80f9cd0a0 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -555,11 +555,7 @@ impl RemoteMode { &self, session_id: SessionId, request: R, - ) -> Task> - where - ::Response: 'static, - ::Arguments: 'static + Send, - { + ) -> Task> { let request = Arc::new(request); let request_clone = request.clone(); @@ -567,7 +563,7 @@ impl RemoteMode { let project_id = self.upstream_project_id; self.executor.spawn(async move { let args = request_clone.to_proto(session_id, project_id); - let response = client.request::(args).await?; + let response = client.request(args).await?; request.response_from_proto(response) }) } @@ -578,11 +574,7 @@ impl Mode { &self, session_id: SessionId, request: R, - ) -> Task> - where - ::Response: 'static, - ::Arguments: 'static + Send, - { + ) -> Task> { match self { Mode::Running(debug_adapter_client) => debug_adapter_client.request(request), Mode::Building => Task::ready(Err(anyhow!( From 511624a56144df1524ec83de79123e61dd65c5ba Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Wed, 2 Jul 2025 11:08:26 +0200 Subject: [PATCH 10/13] Start adding more proto conversions --- crates/dap/src/proto_conversions.rs | 298 +++++++++++++++++++++++-- crates/debugger_ui/src/session.rs | 15 +- crates/project/src/debugger/session.rs | 22 +- crates/proto/proto/debugger.proto | 81 ++++++- crates/proto/proto/zed.proto | 4 +- crates/proto/src/proto.rs | 8 +- 6 files changed, 397 insertions(+), 31 deletions(-) diff --git a/crates/dap/src/proto_conversions.rs b/crates/dap/src/proto_conversions.rs index f6d5a0c3b5d381..383c54ec58b8c6 100644 --- a/crates/dap/src/proto_conversions.rs +++ b/crates/dap/src/proto_conversions.rs @@ -1,7 +1,8 @@ use anyhow::{Context as _, Result}; use client::proto::{ - self, DapChecksum, DapChecksumAlgorithm, DapEvaluateContext, DapModule, DapScope, - DapScopePresentationHint, DapSource, DapSourcePresentationHint, DapStackFrame, DapVariable, + self, BreakpointMode, BreakpointModeApplicability, Capabilities, DapChecksum, + DapChecksumAlgorithm, DapEvaluateContext, DapModule, DapScope, DapScopePresentationHint, + DapSource, DapSourcePresentationHint, DapStackFrame, DapVariable, ExceptionBreakpointsFilter, }; use dap_types::{OutputEventCategory, OutputEventGroup, ScopePresentationHint, Source}; @@ -120,7 +121,7 @@ impl ProtoConversion for dap_types::ScopePresentationHint { dap_types::ScopePresentationHint::Registers => DapScopePresentationHint::Registers, dap_types::ScopePresentationHint::ReturnValue => DapScopePresentationHint::ReturnValue, dap_types::ScopePresentationHint::Unknown => DapScopePresentationHint::ScopeUnknown, - &_ => unreachable!(), + _ => unreachable!(), } } @@ -361,11 +362,13 @@ impl ProtoConversion for dap_types::OutputEventCategory { fn to_proto(&self) -> Self::ProtoType { match self { - Self::Console => proto::DapOutputCategory::ConsoleOutput, - Self::Important => proto::DapOutputCategory::Important, - Self::Stdout => proto::DapOutputCategory::Stdout, - Self::Stderr => proto::DapOutputCategory::Stderr, - _ => proto::DapOutputCategory::Unknown, + OutputEventCategory::Console => proto::DapOutputCategory::ConsoleOutput, + OutputEventCategory::Important => proto::DapOutputCategory::Important, + OutputEventCategory::Stdout => proto::DapOutputCategory::Stdout, + OutputEventCategory::Stderr => proto::DapOutputCategory::Stderr, + OutputEventCategory::Unknown => proto::DapOutputCategory::Unknown, + OutputEventCategory::Telemetry => proto::DapOutputCategory::Telemetry, + _ => unreachable!(), } } @@ -376,6 +379,7 @@ impl ProtoConversion for dap_types::OutputEventCategory { proto::DapOutputCategory::Stdout => Self::Stdout, proto::DapOutputCategory::Stderr => Self::Stderr, proto::DapOutputCategory::Unknown => Self::Unknown, + proto::DapOutputCategory::Telemetry => Self::Telemetry, } } } @@ -498,7 +502,7 @@ impl ProtoConversion for dap_types::EvaluateArgumentsContext { dap_types::EvaluateArgumentsContext::Unknown => { proto::DapEvaluateContext::EvaluateUnknown } - _ => proto::DapEvaluateContext::EvaluateUnknown, + _ => unreachable!(), } } @@ -656,7 +660,7 @@ impl ProtoConversion for dap_types::ExceptionOptions { payload .path .into_iter() - .map(|p| dap_types::ExceptionPathSegment::from_proto(p)) + .map(dap_types::ExceptionPathSegment::from_proto) .collect(), ) }, @@ -736,9 +740,7 @@ impl ProtoConversion for dap_types::Breakpoint { id: payload.id.map(|id| id as u64), verified: payload.verified, message: payload.message, - source: payload - .source - .map(|source| dap_types::Source::from_proto(source)), + source: payload.source.map(dap_types::Source::from_proto), line: payload.line.map(|line| line as u64), column: payload.column.map(|column| column as u64), end_line: payload.end_line.map(|line| line as u64), @@ -753,3 +755,273 @@ impl ProtoConversion for dap_types::Breakpoint { } } } + +impl ProtoConversion for dap_types::BreakpointModeApplicability { + type ProtoType = BreakpointModeApplicability; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + match self { + dap_types::BreakpointModeApplicability::Source => BreakpointModeApplicability::Source, + dap_types::BreakpointModeApplicability::Exception => { + BreakpointModeApplicability::Exception + } + dap_types::BreakpointModeApplicability::Data => BreakpointModeApplicability::Data, + dap_types::BreakpointModeApplicability::Instruction => { + BreakpointModeApplicability::InstructionBreakpoint + } + dap_types::BreakpointModeApplicability::Unknown => { + BreakpointModeApplicability::BreakpointModeUnknown + } + _ => unreachable!(), + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + match payload { + BreakpointModeApplicability::Source => dap_types::BreakpointModeApplicability::Source, + BreakpointModeApplicability::Exception => { + dap_types::BreakpointModeApplicability::Exception + } + BreakpointModeApplicability::Data => dap_types::BreakpointModeApplicability::Data, + BreakpointModeApplicability::InstructionBreakpoint => { + dap_types::BreakpointModeApplicability::Instruction + } + BreakpointModeApplicability::BreakpointModeUnknown => { + dap_types::BreakpointModeApplicability::Unknown + } + } + } +} + +impl ProtoConversion for dap_types::BreakpointMode { + type ProtoType = BreakpointMode; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + BreakpointMode { + mode: self.mode.clone(), + label: self.label.clone(), + description: self.description.clone(), + applies_to: self + .applies_to + .iter() + .map(|a| a.to_proto() as i32) + .collect(), + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + Self { + mode: payload.mode, + label: payload.label, + description: payload.description, + applies_to: payload + .applies_to + .into_iter() + .filter_map(BreakpointModeApplicability::from_i32) + .map(dap_types::BreakpointModeApplicability::from_proto) + .collect(), + } + } +} + +impl ProtoConversion for dap_types::ExceptionBreakpointsFilter { + type ProtoType = ExceptionBreakpointsFilter; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + ExceptionBreakpointsFilter { + filter: self.filter.clone(), + label: self.label.clone(), + description: self.description.clone(), + default_value: self.default, + supports_condition: self.supports_condition, + condition_description: self.condition_description.clone(), + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + Self { + filter: payload.filter, + label: payload.label, + description: payload.description, + default: payload.default_value, + supports_condition: payload.supports_condition, + condition_description: payload.condition_description, + } + } +} + +impl ProtoConversion for dap_types::Capabilities { + type ProtoType = Capabilities; + type Output = Self; + + fn to_proto(&self) -> Self::ProtoType { + Capabilities { + supports_configuration_done_request: self.supports_configuration_done_request, + supports_function_breakpoints: self.supports_function_breakpoints, + supports_conditional_breakpoints: self.supports_conditional_breakpoints, + supports_hit_conditional_breakpoints: self.supports_hit_conditional_breakpoints, + supports_evaluate_for_hovers: self.supports_evaluate_for_hovers, + exception_breakpoint_filters: self + .exception_breakpoint_filters + .as_ref() + .map(|filters| filters.to_proto()) + .unwrap_or_default(), + supports_step_back: self.supports_step_back, + supports_set_variable: self.supports_set_variable, + supports_restart_frame: self.supports_restart_frame, + supports_goto_targets_request: self.supports_goto_targets_request, + supports_step_in_targets_request: self.supports_step_in_targets_request, + supports_completions_request: self.supports_completions_request, + completion_trigger_characters: self + .completion_trigger_characters + .clone() + .unwrap_or_default(), + supports_modules_request: self.supports_modules_request, + additional_module_columns: self + .additional_module_columns + .as_ref() + .map(|columns| { + columns + .iter() + .map(|col| col.attribute_name.clone()) + .collect() + }) + .unwrap_or_default(), + supported_checksum_algorithms: self + .supported_checksum_algorithms + .as_ref() + .map(|algorithms| algorithms.iter().map(|alg| format!("{:?}", alg)).collect()) + .unwrap_or_default(), + supports_restart_request: self.supports_restart_request, + supports_exception_options: self.supports_exception_options, + supports_value_formatting_options: self.supports_value_formatting_options, + supports_exception_info_request: self.supports_exception_info_request, + support_terminate_debuggee: self.support_terminate_debuggee, + support_suspend_debuggee: self.support_suspend_debuggee, + supports_delayed_stack_trace_loading: self.supports_delayed_stack_trace_loading, + supports_loaded_sources_request: self.supports_loaded_sources_request, + supports_log_points: self.supports_log_points, + supports_terminate_threads_request: self.supports_terminate_threads_request, + supports_set_expression: self.supports_set_expression, + supports_terminate_request: self.supports_terminate_request, + supports_data_breakpoints: self.supports_data_breakpoints, + supports_read_memory_request: self.supports_read_memory_request, + supports_write_memory_request: self.supports_write_memory_request, + supports_disassemble_request: self.supports_disassemble_request, + supports_cancel_request: self.supports_cancel_request, + supports_breakpoint_locations_request: self.supports_breakpoint_locations_request, + supports_clipboard_context: self.supports_clipboard_context, + supports_stepping_granularity: self.supports_stepping_granularity, + supports_instruction_breakpoints: self.supports_instruction_breakpoints, + supports_exception_filter_options: self.supports_exception_filter_options, + supports_single_thread_execution_requests: self + .supports_single_thread_execution_requests, + supports_data_breakpoint_bytes: self.supports_data_breakpoint_bytes, + breakpoint_modes: self + .breakpoint_modes + .as_ref() + .map(|modes| modes.to_proto()) + .unwrap_or_default(), + supports_ansistyling: self.supports_ansistyling, + } + } + + fn from_proto(payload: Self::ProtoType) -> Self { + Self { + supports_configuration_done_request: payload.supports_configuration_done_request, + supports_function_breakpoints: payload.supports_function_breakpoints, + supports_conditional_breakpoints: payload.supports_conditional_breakpoints, + supports_hit_conditional_breakpoints: payload.supports_hit_conditional_breakpoints, + supports_evaluate_for_hovers: payload.supports_evaluate_for_hovers, + exception_breakpoint_filters: if payload.exception_breakpoint_filters.is_empty() { + None + } else { + Some(Vec::::from_proto( + payload.exception_breakpoint_filters, + )) + }, + supports_step_back: payload.supports_step_back, + supports_set_variable: payload.supports_set_variable, + supports_restart_frame: payload.supports_restart_frame, + supports_goto_targets_request: payload.supports_goto_targets_request, + supports_step_in_targets_request: payload.supports_step_in_targets_request, + supports_completions_request: payload.supports_completions_request, + completion_trigger_characters: if payload.completion_trigger_characters.is_empty() { + None + } else { + Some(payload.completion_trigger_characters) + }, + supports_modules_request: payload.supports_modules_request, + additional_module_columns: if payload.additional_module_columns.is_empty() { + None + } else { + Some( + payload + .additional_module_columns + .into_iter() + .map(|name| dap_types::ColumnDescriptor { + attribute_name: name, + label: String::new(), + format: None, + type_: None, + width: None, + }) + .collect(), + ) + }, + supported_checksum_algorithms: if payload.supported_checksum_algorithms.is_empty() { + None + } else { + Some( + payload + .supported_checksum_algorithms + .into_iter() + .filter_map(|alg| match alg.as_str() { + "Md5" => Some(dap_types::ChecksumAlgorithm::Md5), + "Sha1" => Some(dap_types::ChecksumAlgorithm::Sha1), + "Sha256" => Some(dap_types::ChecksumAlgorithm::Sha256), + "Timestamp" => Some(dap_types::ChecksumAlgorithm::Timestamp), + _ => None, + }) + .collect(), + ) + }, + supports_restart_request: payload.supports_restart_request, + supports_exception_options: payload.supports_exception_options, + supports_value_formatting_options: payload.supports_value_formatting_options, + supports_exception_info_request: payload.supports_exception_info_request, + support_terminate_debuggee: payload.support_terminate_debuggee, + support_suspend_debuggee: payload.support_suspend_debuggee, + supports_delayed_stack_trace_loading: payload.supports_delayed_stack_trace_loading, + supports_loaded_sources_request: payload.supports_loaded_sources_request, + supports_log_points: payload.supports_log_points, + supports_terminate_threads_request: payload.supports_terminate_threads_request, + supports_set_expression: payload.supports_set_expression, + supports_terminate_request: payload.supports_terminate_request, + supports_data_breakpoints: payload.supports_data_breakpoints, + supports_read_memory_request: payload.supports_read_memory_request, + supports_write_memory_request: payload.supports_write_memory_request, + supports_disassemble_request: payload.supports_disassemble_request, + supports_cancel_request: payload.supports_cancel_request, + supports_breakpoint_locations_request: payload.supports_breakpoint_locations_request, + supports_clipboard_context: payload.supports_clipboard_context, + supports_stepping_granularity: payload.supports_stepping_granularity, + supports_instruction_breakpoints: payload.supports_instruction_breakpoints, + supports_exception_filter_options: payload.supports_exception_filter_options, + supports_single_thread_execution_requests: payload + .supports_single_thread_execution_requests, + supports_data_breakpoint_bytes: payload.supports_data_breakpoint_bytes, + breakpoint_modes: if payload.breakpoint_modes.is_empty() { + None + } else { + Some(Vec::::from_proto( + payload.breakpoint_modes, + )) + }, + supports_ansistyling: payload.supports_ansistyling, + } + } +} diff --git a/crates/debugger_ui/src/session.rs b/crates/debugger_ui/src/session.rs index 710738db25f3f9..4a371e8cd4db2c 100644 --- a/crates/debugger_ui/src/session.rs +++ b/crates/debugger_ui/src/session.rs @@ -197,23 +197,20 @@ impl FollowableItem for DebugSession { } fn from_state_proto( - workspace: Entity, - remote_id: ViewId, + _workspace: Entity, + _remote_id: ViewId, state: &mut Option, - window: &mut Window, - cx: &mut App, + _window: &mut Window, + _cx: &mut App, ) -> Option>>> { let proto::view::Variant::DebugSession(_) = state.as_ref()? else { return None; }; - let Some(proto::view::Variant::DebugSession(state)) = state.take() else { + let Some(proto::view::Variant::DebugSession(_state)) = state.take() else { unreachable!() }; - let session_id = state.session_id; - - dbg!("here"); - None + todo!() } fn add_event_to_update_proto( diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index f8dbf80f9cd0a0..9640178e41ed4b 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -156,7 +156,8 @@ pub struct RemoteMode { has_ever_stopped: bool, upstream_project_id: u64, executor: BackgroundExecutor, - building: bool, + is_building: bool, + is_started: bool, } fn client_source(abs_path: &Path) -> dap::Source { @@ -547,7 +548,8 @@ impl RemoteMode { executor, upstream_project_id, has_ever_stopped: false, - building: true, + is_building: true, + is_started: false, } } @@ -1045,16 +1047,24 @@ impl Session { match &self.mode { Mode::Building => false, Mode::Running(running) => running.is_started, - Mode::Remote(_) => true, + Mode::Remote(remote) => remote.is_started, } } pub fn is_building(&self) -> bool { - matches!(self.mode, Mode::Building) + match &self.mode { + Mode::Building => true, + Mode::Running(_) => false, + Mode::Remote(remote_mode) => remote_mode.is_building, + } } pub fn is_running(&self) -> bool { - matches!(self.mode, Mode::Running(_)) + match &self.mode { + Mode::Building => false, + Mode::Running(_) => true, + Mode::Remote(remote_mode) => !remote_mode.is_building, + } } pub fn as_running_mut(&mut self) -> Option<&mut RunningMode> { @@ -1615,7 +1625,7 @@ impl Session { cx: &mut Context, ) -> Task> { Self::request_inner( - self.id.clone(), + self.id, &self.capabilities, &self.mode, request, diff --git a/crates/proto/proto/debugger.proto b/crates/proto/proto/debugger.proto index be0c7155d36ea1..da9ad533dd6723 100644 --- a/crates/proto/proto/debugger.proto +++ b/crates/proto/proto/debugger.proto @@ -405,6 +405,7 @@ enum DapOutputCategory { Stdout = 2; Stderr = 3; Unknown = 4; + Telemetry = 5; } enum DapOutputEventGroup { @@ -602,11 +603,89 @@ message LogToDebugConsole { string message = 3; } -message SessionStarted { +message DapNewSession { uint64 project_id = 1; uint64 session_id = 2; } +message DapSessionUpdated { + uint64 project_id = 1; + uint64 session_id = 2; + Capabilities capabilities = 3; + bool building = 4; + bool has_ever_stopped = 5; + bool is_started = 6; +} + +message Capabilities { + optional bool supports_configuration_done_request = 1; + optional bool supports_function_breakpoints = 2; + optional bool supports_conditional_breakpoints = 3; + optional bool supports_hit_conditional_breakpoints = 4; + optional bool supports_evaluate_for_hovers = 5; + repeated ExceptionBreakpointsFilter exception_breakpoint_filters = 6; + optional bool supports_step_back = 7; + optional bool supports_set_variable = 8; + optional bool supports_restart_frame = 9; + optional bool supports_goto_targets_request = 10; + optional bool supports_step_in_targets_request = 11; + optional bool supports_completions_request = 12; + repeated string completion_trigger_characters = 13; + optional bool supports_modules_request = 14; + repeated string additional_module_columns = 15; + repeated string supported_checksum_algorithms = 16; + optional bool supports_restart_request = 17; + optional bool supports_exception_options = 18; + optional bool supports_value_formatting_options = 19; + optional bool supports_exception_info_request = 20; + optional bool support_terminate_debuggee = 21; + optional bool support_suspend_debuggee = 22; + optional bool supports_delayed_stack_trace_loading = 23; + optional bool supports_loaded_sources_request = 24; + optional bool supports_log_points = 25; + optional bool supports_terminate_threads_request = 26; + optional bool supports_set_expression = 27; + optional bool supports_terminate_request = 28; + optional bool supports_data_breakpoints = 29; + optional bool supports_read_memory_request = 30; + optional bool supports_write_memory_request = 31; + optional bool supports_disassemble_request = 32; + optional bool supports_cancel_request = 33; + optional bool supports_breakpoint_locations_request = 34; + optional bool supports_clipboard_context = 35; + optional bool supports_stepping_granularity = 36; + optional bool supports_instruction_breakpoints = 37; + optional bool supports_exception_filter_options = 38; + optional bool supports_single_thread_execution_requests = 39; + optional bool supports_data_breakpoint_bytes = 40; + repeated BreakpointMode breakpoint_modes = 41; + optional bool supports_ansistyling = 42; +} + +message ExceptionBreakpointsFilter { + string filter = 1; + string label = 2; + optional string description = 3; + optional bool default_value = 4; + optional bool supports_condition = 5; + optional string condition_description = 6; +} + +enum BreakpointModeApplicability { + Source = 0; + Exception = 1; + Data = 2; + InstructionBreakpoint = 3; + BreakpointModeUnknown = 4; +} + +message BreakpointMode { + string mode = 1; + string label = 2; + optional string description = 3; + repeated BreakpointModeApplicability applies_to = 4; +} + message InvalidateSessionRequest { uint64 project_id = 1; uint64 session_id = 2; diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index 6d5b07464fd316..fa5882cc96f6b9 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -431,7 +431,9 @@ message Envelope { DapLocationsRequest dap_locations_request = 387; DapLocationsResponse dap_locations_response = 388; DapSetExceptionBreakpointsRequest dap_set_exception_breakpoints_request = 389; - DapSetExceptionBreakpointsResponse dap_set_exception_breakpoints_response = 390; // current max + DapSetExceptionBreakpointsResponse dap_set_exception_breakpoints_response = 390; + DapNewSession dap_new_session = 391; + DapSessionUpdated dap_session_updated = 392; // current max } reserved 87 to 88; diff --git a/crates/proto/src/proto.rs b/crates/proto/src/proto.rs index a562969f371ee8..604c74b5c0fddc 100644 --- a/crates/proto/src/proto.rs +++ b/crates/proto/src/proto.rs @@ -348,6 +348,8 @@ messages!( (DapSetExceptionBreakpointsRequest, Background), (DapSetExceptionBreakpointsResponse, Background), (DapTerminateThreadsRequest, Background), + (DapNewSession, Background), + (DapSessionUpdated, Background), ); request_messages!( @@ -539,6 +541,8 @@ request_messages!( DapSetExceptionBreakpointsResponse ), (DapTerminateThreadsRequest, Ack), + (DapNewSession, Ack), + (DapSessionUpdated, Ack), ); entity_messages!( @@ -668,7 +672,9 @@ entity_messages!( GetDebugAdapterBinary, LogToDebugConsole, GetDocumentDiagnostics, - PullWorkspaceDiagnostics + PullWorkspaceDiagnostics, + DapNewSession, + DapSessionUpdated, ); entity_messages!( From 50fdc852994722bfd49b992a271d2f16daa8ef86 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Wed, 2 Jul 2025 11:37:42 +0200 Subject: [PATCH 11/13] WIP handle NewSession message --- crates/collab/src/rpc.rs | 8 ++-- crates/project/src/debugger/dap_store.rs | 54 ++++++++++++++++++++++-- crates/project/src/debugger/session.rs | 50 ++++++++++++++++++++-- crates/proto/proto/debugger.proto | 3 ++ 4 files changed, 105 insertions(+), 10 deletions(-) diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 6b84ca998ec4b8..8500a0708a584b 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -441,15 +441,17 @@ impl Server { .add_request_handler(forward_read_only_project_request::) .add_request_handler(forward_read_only_project_request::) .add_request_handler(forward_mutating_project_request::) - .add_request_handler(forward_mutating_project_request::) - .add_message_handler(broadcast_project_message_from_host::) .add_request_handler(forward_mutating_project_request::) .add_request_handler(forward_mutating_project_request::) .add_request_handler(forward_mutating_project_request::) .add_request_handler(forward_mutating_project_request::) .add_request_handler(forward_mutating_project_request::) .add_message_handler(broadcast_project_message_from_host::) - .add_message_handler(update_context); + .add_message_handler(update_context) + .add_request_handler(forward_mutating_project_request::) + .add_message_handler(broadcast_project_message_from_host::) + .add_message_handler(broadcast_project_message_from_host::) + .add_message_handler(broadcast_project_message_from_host::); Arc::new(server) } diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index d01c89151510ba..c3cc52babba5e8 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -115,6 +115,7 @@ impl DapStore { client.add_entity_request_handler(Self::handle_run_debug_locator); client.add_entity_request_handler(Self::handle_get_debug_adapter_binary); client.add_entity_message_handler(Self::handle_log_to_debug_console); + client.add_entity_message_handler(Self::handle_new_session); } #[expect(clippy::too_many_arguments)] @@ -385,6 +386,13 @@ impl DapStore { } } + fn as_collab(&self) -> Option<&CollabDapStore> { + match &self.mode { + DapStoreMode::Collab(collab_dap_store) => Some(collab_dap_store), + _ => None, + } + } + pub fn new_session( &mut self, label: SharedString, @@ -468,11 +476,9 @@ impl DapStore { &self, session_id: impl Borrow, ) -> Option> { - let session_id = session_id.borrow(); - let client = self.sessions.get(session_id).cloned(); - - client + self.sessions.get(session_id.borrow()).cloned() } + pub fn sessions(&self) -> impl Iterator> { self.sessions.values() } @@ -861,6 +867,46 @@ impl DapStore { }) }) } + + async fn handle_new_session( + this: Entity, + envelope: TypedEnvelope, + mut cx: AsyncApp, + ) -> Result<()> { + let session_id = SessionId::from_proto(envelope.payload.session_id); + let parent_session_id = envelope + .payload + .parent_session_id + .map(SessionId::from_proto); + + this.update(&mut cx, |this, cx| { + let Some(collab) = this.as_collab() else { + anyhow::bail!("expected that dap store is in collab mode"); + }; + + let parent_session = parent_session_id.and_then(|id| this.session_by_id(id)); + + let session = Session::new_remote( + session_id, + parent_session, + DebugAdapterName(envelope.payload.adapter_name.into()), + envelope.payload.label.into(), + this.breakpoint_store.clone(), + collab.upstream_client.clone(), + collab.project_id, + cx.background_executor().clone(), + cx, + ); + + this.sessions.insert(session_id, session); + + // TODO(debugger): update the parent session to have the child session id + + cx.notify(); + + Ok(()) + })? + } } #[derive(Clone)] diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 9640178e41ed4b..214796f0670b34 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -840,7 +840,7 @@ impl Session { .detach(); cx.on_app_quit(Self::on_app_quit).detach(); - let this = Self { + Self { mode: Mode::Building, id: session_id, child_session_ids: HashSet::default(), @@ -865,9 +865,53 @@ impl Session { label, adapter, task_context, - }; + } + }) + } - this + pub(crate) fn new_remote( + session_id: SessionId, + parent_session: Option>, + adapter: DebugAdapterName, + label: SharedString, + breakpoint_store: Entity, + client: AnyProtoClient, + upstream_project_id: u64, + executor: BackgroundExecutor, + cx: &mut App, + ) -> Entity { + cx.new(|_| Self { + mode: Mode::Remote(RemoteMode { + client, + has_ever_stopped: false, + upstream_project_id, + executor, + is_building: true, + is_started: false, + }), + id: session_id, + child_session_ids: HashSet::default(), + parent_session, + capabilities: Capabilities::default(), + watchers: HashMap::default(), + variables: Default::default(), + stack_frames: Default::default(), + thread_states: ThreadStates::default(), + output_token: OutputToken(0), + output: circular_buffer::CircularBuffer::boxed(), + requests: HashMap::default(), + modules: Vec::default(), + loaded_sources: Vec::default(), + threads: IndexMap::default(), + background_tasks: Vec::default(), + locations: Default::default(), + is_session_terminated: false, + ignore_breakpoints: false, + breakpoint_store, + exception_breakpoints: Default::default(), + label, + adapter, + task_context: Default::default(), // TODO(debugger): fix this }) } diff --git a/crates/proto/proto/debugger.proto b/crates/proto/proto/debugger.proto index da9ad533dd6723..7dcf97b8311b57 100644 --- a/crates/proto/proto/debugger.proto +++ b/crates/proto/proto/debugger.proto @@ -606,6 +606,9 @@ message LogToDebugConsole { message DapNewSession { uint64 project_id = 1; uint64 session_id = 2; + optional uint64 parent_session_id = 3; + string label = 4; + string adapter_name = 5; } message DapSessionUpdated { From 96d1df033ca163e3214b03595d0228a8aae58e47 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Wed, 2 Jul 2025 17:41:42 +0200 Subject: [PATCH 12/13] Add child session id to parent session --- crates/project/src/debugger/dap_store.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index c3cc52babba5e8..53962e513e42f0 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -886,6 +886,12 @@ impl DapStore { let parent_session = parent_session_id.and_then(|id| this.session_by_id(id)); + if let Some(parent_session) = &parent_session { + parent_session.update(cx, |session, _| { + session.add_child_session_id(session_id); + }); + } + let session = Session::new_remote( session_id, parent_session, @@ -899,9 +905,6 @@ impl DapStore { ); this.sessions.insert(session_id, session); - - // TODO(debugger): update the parent session to have the child session id - cx.notify(); Ok(()) From a164142abb17ac9d7074b76847c00d2a5d86f662 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Wed, 2 Jul 2025 21:33:34 +0200 Subject: [PATCH 13/13] wip --- crates/debugger_ui/src/debugger_panel.rs | 46 +++++++++++++++++++----- crates/project/src/debugger/dap_store.rs | 1 + crates/project/src/debugger/session.rs | 43 +++++++++++++++++++--- 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index d03e8c5225f04f..839785f99c5e17 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -71,7 +71,7 @@ pub struct DebugPanel { pub(crate) session_picker_menu_handle: PopoverMenuHandle, fs: Arc, is_zoomed: bool, - _subscriptions: [Subscription; 1], + _subscriptions: Vec, breakpoint_list: Entity, } @@ -87,13 +87,41 @@ impl DebugPanel { let thread_picker_menu_handle = PopoverMenuHandle::default(); let session_picker_menu_handle = PopoverMenuHandle::default(); - let focus_subscription = cx.on_focus( - &focus_handle, - window, - |this: &mut DebugPanel, window, cx| { - this.focus_active_item(window, cx); - }, - ); + let _subscriptions = vec![ + cx.on_focus( + &focus_handle, + window, + |this: &mut DebugPanel, window, cx| { + this.focus_active_item(window, cx); + }, + ), + cx.subscribe_in( + &project.read(cx).dap_store(), + window, + |debug_panel, dap_store, event, window, cx| match event { + project::debugger::dap_store::DapStoreEvent::DebugClientStarted( + session_id, + ) => { + cx.notify(); + let has_session = debug_panel + .sessions + .iter() + .any(|session| session.read(cx).session_id(cx) == *session_id); + dbg!(has_session, debug_panel.sessions.len()); + if let Some(session) = dap_store.read(cx).session_by_id(session_id) { + cx.spawn_in(window, async move |this, cx| { + Self::register_session(this.clone(), session.clone(), true, cx) + .await?; + + anyhow::Ok(()) + }) + .detach(); + } + } + _ => {} + }, + ), + ]; Self { size: px(300.), @@ -114,7 +142,7 @@ impl DebugPanel { thread_picker_menu_handle, session_picker_menu_handle, is_zoomed: false, - _subscriptions: [focus_subscription], + _subscriptions, debug_scenario_scheduled_last: true, } }) diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index fdd36deab1b23e..b3f909bb3fb5b7 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -417,6 +417,7 @@ impl DapStore { let session = Session::new( self.breakpoint_store.clone(), + self.downstream_client.clone(), session_id, parent_session, label, diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 38c614da339db1..b271756a781530 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -15,6 +15,7 @@ use anyhow::{Context as _, Result, anyhow}; use collections::{HashMap, HashSet, IndexMap}; use dap::adapters::{DebugAdapterBinary, DebugAdapterName}; use dap::messages::Response; +use dap::proto_conversions::ProtoConversion; use dap::requests::{Request, RunInTerminal, StartDebugging}; use dap::{ Capabilities, ContinueArguments, EvaluateArgumentsContext, Module, Source, StackFrameId, @@ -35,7 +36,7 @@ use gpui::{ App, AppContext, AsyncApp, BackgroundExecutor, Context, Entity, EventEmitter, SharedString, Task, WeakEntity, }; -use rpc::{AnyProtoClient, ErrorExt}; +use rpc::{AnyProtoClient, ErrorExt, proto}; use serde_json::Value; use smol::stream::StreamExt; use std::any::TypeId; @@ -705,6 +706,7 @@ pub struct Session { is_session_terminated: bool, requests: HashMap>>>>, pub(crate) breakpoint_store: Entity, + upstream_client: Option<(AnyProtoClient, u64)>, ignore_breakpoints: bool, exception_breakpoints: BTreeMap, background_tasks: Vec>, @@ -820,6 +822,7 @@ impl EventEmitter for Session {} impl Session { pub(crate) fn new( breakpoint_store: Entity, + upstream_client: Option<(AnyProtoClient, u64)>, session_id: SessionId, parent_session: Option>, label: SharedString, @@ -873,6 +876,7 @@ impl Session { is_session_terminated: false, ignore_breakpoints: false, breakpoint_store, + upstream_client, exception_breakpoints: Default::default(), label, adapter, @@ -920,6 +924,7 @@ impl Session { is_session_terminated: false, ignore_breakpoints: false, breakpoint_store, + upstream_client: None, exception_breakpoints: Default::default(), label, adapter, @@ -948,7 +953,7 @@ impl Session { let (message_tx, mut message_rx) = futures::channel::mpsc::unbounded(); let (initialized_tx, initialized_rx) = futures::channel::oneshot::channel(); - let background_tasks = vec![cx.spawn(async move |this: WeakEntity, cx| { + self.background_tasks = vec![cx.spawn(async move |this: WeakEntity, cx| { let mut initialized_tx = Some(initialized_tx); while let Some(message) = message_rx.next().await { if let Message::Event(event) = message { @@ -978,13 +983,29 @@ impl Session { } } })]; - self.background_tasks = background_tasks; - let id = self.id; + + let session_id = self.id; let parent_session = self.parent_session.clone(); cx.spawn(async move |this, cx| { + let upstream_client = this.update(cx, |this, _| this.upstream_client.clone())?; + + if let Some((client, project_id)) = &upstream_client { + let _ = client.send(proto::DapNewSession { + project_id: *project_id, + session_id: session_id.to_proto(), + parent_session_id: parent_session.as_ref().and_then(|session| { + session + .update(cx, |session, _| session.session_id().to_proto()) + .ok() + }), + label: "python main".to_string(), + adapter_name: "Python".to_string(), + }); + } + let mode = RunningMode::new( - id, + session_id, parent_session, worktree.downgrade(), binary.clone(), @@ -992,11 +1013,23 @@ impl Session { cx, ) .await?; + this.update(cx, |this, cx| { this.mode = Mode::Running(mode); cx.emit(SessionStateEvent::Running); })?; + if let Some((client, project_id)) = upstream_client { + let _ = client.send(proto::DapSessionUpdated { + project_id, + session_id: session_id.to_proto(), + capabilities: Some(Capabilities::default().to_proto()), + building: false, + has_ever_stopped: false, + is_started: false, + }); + } + this.update(cx, |session, cx| session.request_initialize(cx))? .await?;