diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index 1b4e204b1efa54f9ae305b1e4bccf02eb42db942..1597bf294d408faf4e21ff07c9f651fa0892d0fe 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -273,7 +273,7 @@ impl DebugPanel { let session = session.clone(); async move |this, cx| { let debug_session = - Self::register_session(this.clone(), session.clone(), cx).await?; + Self::register_session(this.clone(), session.clone(), true, cx).await?; let definition = debug_session .update_in(cx, |debug_session, window, cx| { debug_session.running_state().update(cx, |running, cx| { @@ -318,69 +318,21 @@ impl DebugPanel { pub(crate) async fn register_session( this: WeakEntity, session: Entity, + focus: bool, cx: &mut AsyncWindowContext, ) -> Result> { - let adapter_name = session.update(cx, |session, _| session.adapter())?; - this.update_in(cx, |_, window, cx| { - cx.subscribe_in( - &session, - window, - move |this, session, event: &SessionStateEvent, window, cx| match event { - SessionStateEvent::Restart => { - this.handle_restart_request(session.clone(), window, cx); - } - SessionStateEvent::SpawnChildSession { request } => { - this.handle_start_debugging_request(request, session.clone(), window, cx); - } - _ => {} - }, - ) - .detach(); - }) - .ok(); - - let serialized_layout = persistence::get_serialized_layout(adapter_name).await; - - let (debug_session, workspace) = this.update_in(cx, |this, window, cx| { - this.sessions.retain(|session| { - !session - .read(cx) - .running_state() - .read(cx) - .session() - .read(cx) - .is_terminated() - }); + let debug_session = register_session_inner(&this, session, cx).await?; - let debug_session = DebugSession::running( - this.project.clone(), - this.workspace.clone(), - session, - cx.weak_entity(), - serialized_layout, - this.position(window, cx).axis(), - window, - cx, - ); - - // We might want to make this an event subscription and only notify when a new thread is selected - // This is used to filter the command menu correctly - cx.observe( - &debug_session.read(cx).running_state().clone(), - |_, _, cx| cx.notify(), - ) - .detach(); - - this.sessions.push(debug_session.clone()); - this.activate_session(debug_session.clone(), window, cx); + let workspace = this.update_in(cx, |this, window, cx| { + if focus { + this.activate_session(debug_session.clone(), window, cx); + } - (debug_session, this.workspace.clone()) + this.workspace.clone() })?; - workspace.update_in(cx, |workspace, window, cx| { workspace.focus_panel::(window, cx); })?; - Ok(debug_session) } @@ -418,7 +370,7 @@ impl DebugPanel { }); (session, task) })?; - Self::register_session(this, session, cx).await?; + Self::register_session(this.clone(), session, true, cx).await?; task.await }) .detach_and_log_err(cx); @@ -441,7 +393,6 @@ impl DebugPanel { let adapter = parent_session.read(cx).adapter().clone(); let mut binary = parent_session.read(cx).binary().clone(); binary.request_args = request.clone(); - cx.spawn_in(window, async move |this, cx| { let (session, task) = dap_store_handle.update(cx, |dap_store, cx| { let session = @@ -452,7 +403,7 @@ impl DebugPanel { }); (session, task) })?; - Self::register_session(this, session, cx).await?; + Self::register_session(this, session, false, cx).await?; task.await }) .detach_and_log_err(cx); @@ -910,6 +861,21 @@ impl DebugPanel { } } + pub(crate) fn activate_session_by_id( + &mut self, + session_id: SessionId, + window: &mut Window, + cx: &mut Context, + ) { + if let Some(session) = self + .sessions + .iter() + .find(|session| session.read(cx).session_id(cx) == session_id) + { + self.activate_session(session.clone(), window, cx); + } + } + pub(crate) fn activate_session( &mut self, session_item: Entity, @@ -923,7 +889,7 @@ impl DebugPanel { this.go_to_selected_stack_frame(window, cx); }); }); - self.active_session = Some(session_item.clone()); + self.active_session = Some(session_item); cx.notify(); } @@ -999,6 +965,67 @@ impl DebugPanel { } } +async fn register_session_inner( + this: &WeakEntity, + session: Entity, + cx: &mut AsyncWindowContext, +) -> Result> { + let adapter_name = session.update(cx, |session, _| session.adapter())?; + this.update_in(cx, |_, window, cx| { + cx.subscribe_in( + &session, + window, + move |this, session, event: &SessionStateEvent, window, cx| match event { + SessionStateEvent::Restart => { + this.handle_restart_request(session.clone(), window, cx); + } + SessionStateEvent::SpawnChildSession { request } => { + this.handle_start_debugging_request(request, session.clone(), window, cx); + } + _ => {} + }, + ) + .detach(); + }) + .ok(); + let serialized_layout = persistence::get_serialized_layout(adapter_name).await; + let debug_session = this.update_in(cx, |this, window, cx| { + this.sessions.retain(|session| { + !session + .read(cx) + .running_state() + .read(cx) + .session() + .read(cx) + .is_terminated() + }); + + let debug_session = DebugSession::running( + this.project.clone(), + this.workspace.clone(), + session, + cx.weak_entity(), + serialized_layout, + this.position(window, cx).axis(), + window, + cx, + ); + + // We might want to make this an event subscription and only notify when a new thread is selected + // This is used to filter the command menu correctly + cx.observe( + &debug_session.read(cx).running_state().clone(), + |_, _, cx| cx.notify(), + ) + .detach(); + + this.sessions.push(debug_session.clone()); + + debug_session + })?; + Ok(debug_session) +} + impl EventEmitter for DebugPanel {} impl EventEmitter for DebugPanel {} diff --git a/crates/debugger_ui/src/session/running.rs b/crates/debugger_ui/src/session/running.rs index 6eac41d6d49f86b74281e461f22cf7d1920d16dc..d1bcd2317492b0a06c27c957ed4293cbc915b6a9 100644 --- a/crates/debugger_ui/src/session/running.rs +++ b/crates/debugger_ui/src/session/running.rs @@ -585,15 +585,26 @@ impl RunningState { cx.subscribe_in(&session, window, |this, _, event, window, cx| { match event { SessionEvent::Stopped(thread_id) => { - this.workspace + let panel = this + .workspace .update(cx, |workspace, cx| { workspace.open_panel::(window, cx); + workspace.panel::(cx) }) - .log_err(); + .log_err() + .flatten(); if let Some(thread_id) = thread_id { this.select_thread(*thread_id, window, cx); } + if let Some(panel) = panel { + let id = this.session_id; + window.defer(cx, move |window, cx| { + panel.update(cx, |this, cx| { + this.activate_session_by_id(id, window, cx); + }) + }) + } } SessionEvent::Threads => { let threads = this.session.update(cx, |this, cx| this.threads(cx)); diff --git a/crates/debugger_ui/src/tests/debugger_panel.rs b/crates/debugger_ui/src/tests/debugger_panel.rs index 111995500e343d59522d814afaa6294f89bf1fa9..9edfd240c4687c3ce907182224e0230a23f92708 100644 --- a/crates/debugger_ui/src/tests/debugger_panel.rs +++ b/crates/debugger_ui/src/tests/debugger_panel.rs @@ -423,6 +423,13 @@ async fn test_handle_start_debugging_request( } }); + let sessions = workspace + .update(cx, |workspace, _window, cx| { + let debug_panel = workspace.panel::(cx).unwrap(); + debug_panel.read(cx).sessions() + }) + .unwrap(); + assert_eq!(sessions.len(), 1); client .fake_reverse_request::(StartDebuggingRequestArguments { request: StartDebuggingRequestArgumentsRequest::Launch, @@ -435,20 +442,42 @@ async fn test_handle_start_debugging_request( workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::(cx).unwrap(); + + // Active session does not change on spawn. let active_session = debug_panel .read(cx) .active_session() .unwrap() .read(cx) .session(cx); - let parent_session = active_session.read(cx).parent_session().unwrap(); + + assert_eq!(active_session, sessions[0].read(cx).session(cx)); + assert!(active_session.read(cx).parent_session().is_none()); + + let current_sessions = debug_panel.read(cx).sessions(); + assert_eq!(current_sessions.len(), 2); + assert_eq!(current_sessions[0], sessions[0]); + + let parent_session = current_sessions[1] + .read(cx) + .session(cx) + .read(cx) + .parent_session() + .unwrap(); + assert_eq!(parent_session, &sessions[0].read(cx).session(cx)); + + // We should preserve the original binary (params to spawn process etc.) except for launch params + // (as they come from reverse spawn request). let mut original_binary = parent_session.read(cx).binary().clone(); original_binary.request_args = StartDebuggingRequestArguments { request: StartDebuggingRequestArgumentsRequest::Launch, configuration: fake_config.clone(), }; - assert_eq!(active_session.read(cx).binary(), &original_binary); + assert_eq!( + current_sessions[1].read(cx).session(cx).read(cx).binary(), + &original_binary + ); }) .unwrap();