Tidy up DAP initialization (#28730)

To make DAP work over SSH we want to create the binary
at the project level (so we can wrap it in an `ssh` invocation
transparently).

This means not pushing the adapter down into the session, and resolving
more information ahead-of-time.

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Piotr <piotr@zed.dev>

Release Notes:

- N/A

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Piotr <piotr@zed.dev>
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
Conrad Irwin 2025-04-15 09:11:29 -06:00 committed by GitHub
parent 6f0951ff77
commit aef78dcffd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1319 additions and 1738 deletions

View file

@ -15,9 +15,8 @@ use dap::{
};
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
use menu::{SelectFirst, SelectNext, SelectPrevious};
use project::{FakeFs, Project};
use project::{FakeFs, Project, debugger};
use serde_json::json;
use task::LaunchConfig;
use unindent::Unindent as _;
use util::path;
@ -55,29 +54,19 @@ async fn test_basic_fetch_initial_scope_and_variables(
})
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
let stack_frames = vec![StackFrame {
id: 1,
@ -102,19 +91,17 @@ async fn test_basic_fetch_initial_scope_and_variables(
presentation_hint: None,
}];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let scopes = vec![Scope {
name: "Scope 1".into(),
@ -130,18 +117,16 @@ async fn test_basic_fetch_initial_scope_and_variables(
end_column: None,
}];
client
.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
client.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
});
let variables = vec![
Variable {
@ -172,18 +157,16 @@ async fn test_basic_fetch_initial_scope_and_variables(
},
];
client
.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
client.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*variables).clone(),
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -283,39 +266,28 @@ async fn test_fetch_variables_for_multiple_scopes(
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![StackFrame {
id: 1,
@ -340,19 +312,17 @@ async fn test_fetch_variables_for_multiple_scopes(
presentation_hint: None,
}];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let scopes = vec![
Scope {
@ -383,18 +353,16 @@ async fn test_fetch_variables_for_multiple_scopes(
},
];
client
.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
client.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
});
let mut variables = HashMap::default();
variables.insert(
@ -445,16 +413,14 @@ async fn test_fetch_variables_for_multiple_scopes(
}],
);
client
.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
Ok(dap::VariablesResponse {
variables: variables.get(&args.variables_reference).unwrap().clone(),
})
}
})
.await;
client.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
Ok(dap::VariablesResponse {
variables: variables.get(&args.variables_reference).unwrap().clone(),
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -562,40 +528,28 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
})
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![StackFrame {
id: 1,
@ -620,19 +574,17 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
presentation_hint: None,
}];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let scopes = vec![
Scope {
@ -663,18 +615,16 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
},
];
client
.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
client.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
});
let scope1_variables = vec![
Variable {
@ -748,25 +698,23 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
value_location_reference: None,
}];
client
.on_request::<Variables, _>({
let scope1_variables = Arc::new(scope1_variables.clone());
let nested_variables = Arc::new(nested_variables.clone());
let scope2_variables = Arc::new(scope2_variables.clone());
move |_, args| match args.variables_reference {
4 => Ok(dap::VariablesResponse {
variables: (*scope2_variables).clone(),
}),
3 => Ok(dap::VariablesResponse {
variables: (*nested_variables).clone(),
}),
2 => Ok(dap::VariablesResponse {
variables: (*scope1_variables).clone(),
}),
id => unreachable!("unexpected variables reference {id}"),
}
})
.await;
client.on_request::<Variables, _>({
let scope1_variables = Arc::new(scope1_variables.clone());
let nested_variables = Arc::new(nested_variables.clone());
let scope2_variables = Arc::new(scope2_variables.clone());
move |_, args| match args.variables_reference {
4 => Ok(dap::VariablesResponse {
variables: (*scope2_variables).clone(),
}),
3 => Ok(dap::VariablesResponse {
variables: (*nested_variables).clone(),
}),
2 => Ok(dap::VariablesResponse {
variables: (*scope1_variables).clone(),
}),
id => unreachable!("unexpected variables reference {id}"),
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -1365,39 +1313,28 @@ async fn test_variable_list_only_sends_requests_when_rendering(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![
StackFrame {
@ -1446,19 +1383,17 @@ async fn test_variable_list_only_sends_requests_when_rendering(
},
];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let frame_1_scopes = vec![Scope {
name: "Frame 1 Scope 1".into(),
@ -1476,25 +1411,23 @@ async fn test_variable_list_only_sends_requests_when_rendering(
let made_scopes_request = Arc::new(AtomicBool::new(false));
client
.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let made_scopes_request = made_scopes_request.clone();
move |_, args| {
assert_eq!(1, args.frame_id);
assert!(
!made_scopes_request.load(Ordering::SeqCst),
"We should be caching the scope request"
);
client.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let made_scopes_request = made_scopes_request.clone();
move |_, args| {
assert_eq!(1, args.frame_id);
assert!(
!made_scopes_request.load(Ordering::SeqCst),
"We should be caching the scope request"
);
made_scopes_request.store(true, Ordering::SeqCst);
made_scopes_request.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
});
let frame_1_variables = vec![
Variable {
@ -1525,18 +1458,16 @@ async fn test_variable_list_only_sends_requests_when_rendering(
},
];
client
.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
client.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
});
cx.run_until_parked();
@ -1629,39 +1560,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![
StackFrame {
@ -1710,19 +1630,17 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
},
];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let frame_1_scopes = vec![Scope {
name: "Frame 1 Scope 1".into(),
@ -1757,30 +1675,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
let called_second_stack_frame = Arc::new(AtomicBool::new(false));
let called_first_stack_frame = Arc::new(AtomicBool::new(false));
client
.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let frame_2_scopes = Arc::new(frame_2_scopes.clone());
let called_first_stack_frame = called_first_stack_frame.clone();
let called_second_stack_frame = called_second_stack_frame.clone();
move |_, args| match args.frame_id {
1 => {
called_first_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
2 => {
called_second_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_2_scopes).clone(),
})
}
_ => panic!("Made a scopes request with an invalid frame id"),
client.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let frame_2_scopes = Arc::new(frame_2_scopes.clone());
let called_first_stack_frame = called_first_stack_frame.clone();
let called_second_stack_frame = called_second_stack_frame.clone();
move |_, args| match args.frame_id {
1 => {
called_first_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
})
.await;
2 => {
called_second_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_2_scopes).clone(),
})
}
_ => panic!("Made a scopes request with an invalid frame id"),
}
});
let frame_1_variables = vec![
Variable {
@ -1840,18 +1756,16 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
},
];
client
.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
client.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -1907,18 +1821,16 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
assert_eq!(frame_1_variables, variables);
});
client
.on_request::<Variables, _>({
let frame_2_variables = Arc::new(frame_2_variables.clone());
move |_, args| {
assert_eq!(3, args.variables_reference);
client.on_request::<Variables, _>({
let frame_2_variables = Arc::new(frame_2_variables.clone());
move |_, args| {
assert_eq!(3, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*frame_2_variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*frame_2_variables).clone(),
})
}
});
running_state
.update_in(cx, |running_state, window, cx| {