Debug console tweaks (#29586)

Closes #ISSUE

Release Notes:

- N/A

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Cole Miller <m@cole-miller.net>
This commit is contained in:
Conrad Irwin 2025-04-28 21:53:57 -06:00 committed by GitHub
parent 2beefc8158
commit ab180855de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 135 additions and 149 deletions

View file

@ -20,9 +20,7 @@ use dap::{
client::{DebugAdapterClient, SessionId},
messages::{Events, Message},
};
use dap::{
EvaluateResponse, ExceptionBreakpointsFilter, ExceptionFilterOptions, OutputEventCategory,
};
use dap::{ExceptionBreakpointsFilter, ExceptionFilterOptions, OutputEventCategory};
use futures::channel::oneshot;
use futures::{FutureExt, future::Shared};
use gpui::{
@ -115,7 +113,7 @@ impl From<dap::Thread> for Thread {
}
}
enum Mode {
pub enum Mode {
Building,
Running(LocalMode),
}
@ -127,6 +125,7 @@ pub struct LocalMode {
pub(crate) breakpoint_store: Entity<BreakpointStore>,
tmp_breakpoint: Option<SourceBreakpoint>,
worktree: WeakEntity<Worktree>,
executor: BackgroundExecutor,
}
fn client_source(abs_path: &Path) -> dap::Source {
@ -179,6 +178,7 @@ impl LocalMode {
worktree,
tmp_breakpoint: None,
binary,
executor: cx.background_executor().clone(),
})
}
@ -190,14 +190,11 @@ impl LocalMode {
let tasks: Vec<_> = paths
.into_iter()
.map(|path| {
self.request(
dap_command::SetBreakpoints {
source: client_source(path),
source_modified: None,
breakpoints: vec![],
},
cx.background_executor().clone(),
)
self.request(dap_command::SetBreakpoints {
source: client_source(path),
source_modified: None,
breakpoints: vec![],
})
})
.collect();
@ -229,14 +226,11 @@ impl LocalMode {
.map(Into::into)
.collect();
let task = self.request(
dap_command::SetBreakpoints {
source: client_source(&abs_path),
source_modified: Some(matches!(reason, BreakpointUpdatedReason::FileSaved)),
breakpoints,
},
cx.background_executor().clone(),
);
let task = self.request(dap_command::SetBreakpoints {
source: client_source(&abs_path),
source_modified: Some(matches!(reason, BreakpointUpdatedReason::FileSaved)),
breakpoints,
});
cx.background_spawn(async move {
match task.await {
@ -250,7 +244,6 @@ impl LocalMode {
&self,
filters: Vec<ExceptionBreakpointsFilter>,
supports_filter_options: bool,
cx: &App,
) -> Task<Result<Vec<dap::Breakpoint>>> {
let arg = if supports_filter_options {
SetExceptionBreakpoints::WithOptions {
@ -268,7 +261,7 @@ impl LocalMode {
filters: filters.into_iter().map(|filter| filter.filter).collect(),
}
};
self.request(arg, cx.background_executor().clone())
self.request(arg)
}
fn send_source_breakpoints(
@ -293,14 +286,11 @@ impl LocalMode {
};
breakpoint_tasks.push(
self.request(
dap_command::SetBreakpoints {
source: client_source(&path),
source_modified: Some(false),
breakpoints,
},
cx.background_executor().clone(),
)
self.request(dap_command::SetBreakpoints {
source: client_source(&path),
source_modified: Some(false),
breakpoints,
})
.map(|result| result.map_err(|e| (path, e))),
);
}
@ -331,18 +321,12 @@ impl LocalMode {
// Of relevance: https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522
let launch = match raw.request {
dap::StartDebuggingRequestArgumentsRequest::Launch => self.request(
Launch {
raw: raw.configuration,
},
cx.background_executor().clone(),
),
dap::StartDebuggingRequestArgumentsRequest::Attach => self.request(
Attach {
raw: raw.configuration,
},
cx.background_executor().clone(),
),
dap::StartDebuggingRequestArgumentsRequest::Launch => self.request(Launch {
raw: raw.configuration,
}),
dap::StartDebuggingRequestArgumentsRequest::Attach => self.request(Attach {
raw: raw.configuration,
}),
};
let configuration_done_supported = ConfigurationDone::is_supported(capabilities);
@ -396,17 +380,11 @@ impl LocalMode {
}
})?;
cx.update(|cx| {
this.send_exception_breakpoints(
exception_filters,
supports_exception_filters,
cx,
)
})?
.await
.ok();
this.send_exception_breakpoints(exception_filters, supports_exception_filters)
.await
.ok();
let ret = if configuration_done_supported {
this.request(ConfigurationDone {}, cx.background_executor().clone())
this.request(ConfigurationDone {})
} else {
Task::ready(Ok(()))
}
@ -421,11 +399,7 @@ impl LocalMode {
})
}
fn request<R: LocalDapCommand>(
&self,
request: R,
executor: BackgroundExecutor,
) -> Task<Result<R::Response>>
fn request<R: LocalDapCommand>(&self, request: R) -> Task<Result<R::Response>>
where
<R::DapRequest as dap::requests::Request>::Response: 'static,
<R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
@ -434,32 +408,22 @@ impl LocalMode {
let request_clone = request.clone();
let connection = self.client.clone();
let request_task = executor.spawn(async move {
self.executor.spawn(async move {
let args = request_clone.to_dap();
connection.request::<R::DapRequest>(args).await
});
executor.spawn(async move {
let response = request.response_from_dap(request_task.await?);
response
let response = connection.request::<R::DapRequest>(args).await?;
request.response_from_dap(response)
})
}
}
impl Mode {
fn request_dap<R: DapCommand>(
&self,
request: R,
cx: &mut Context<Session>,
) -> Task<Result<R::Response>>
pub(super) fn request_dap<R: DapCommand>(&self, request: R) -> Task<Result<R::Response>>
where
<R::DapRequest as dap::requests::Request>::Response: 'static,
<R::DapRequest as dap::requests::Request>::Arguments: 'static + Send,
{
match self {
Mode::Running(debug_adapter_client) => {
debug_adapter_client.request(request, cx.background_executor().clone())
}
Mode::Running(debug_adapter_client) => debug_adapter_client.request(request),
Mode::Building => Task::ready(Err(anyhow!(
"no adapter running to send request: {:?}",
request
@ -539,7 +503,7 @@ type IsEnabled = bool;
pub struct OutputToken(pub usize);
/// Represents a current state of a single debug adapter and provides ways to mutate it.
pub struct Session {
mode: Mode,
pub mode: Mode,
definition: DebugTaskDefinition,
pub(super) capabilities: Capabilities,
id: SessionId,
@ -871,7 +835,7 @@ impl Session {
let request = Initialize { adapter_id };
match &self.mode {
Mode::Running(local_mode) => {
let capabilities = local_mode.request(request, cx.background_executor().clone());
let capabilities = local_mode.request(request);
cx.spawn(async move |this, cx| {
let capabilities = capabilities.await?;
@ -1196,6 +1160,17 @@ impl Session {
}
}
pub async fn request2<T: DapCommand + PartialEq + Eq + Hash>(
&self,
request: T,
) -> Result<T::Response> {
if !T::is_supported(&self.capabilities) {
anyhow::bail!("DAP request {:?} is not supported", request);
}
self.mode.request_dap(request).await
}
fn request_inner<T: DapCommand + PartialEq + Eq + Hash>(
capabilities: &Capabilities,
mode: &Mode,
@ -1223,7 +1198,7 @@ impl Session {
});
}
let request = mode.request_dap(request, cx);
let request = mode.request_dap(request);
cx.spawn(async move |this, cx| {
let result = request.await;
this.update(cx, |this, cx| process_result(this, result, cx))
@ -1377,7 +1352,7 @@ impl Session {
.supports_exception_filter_options
.unwrap_or_default();
local
.send_exception_breakpoints(exception_filters, supports_exception_filters, cx)
.send_exception_breakpoints(exception_filters, supports_exception_filters)
.detach_and_log_err(cx);
} else {
debug_assert!(false, "Not implemented");
@ -1878,35 +1853,51 @@ impl Session {
frame_id: Option<u64>,
source: Option<Source>,
cx: &mut Context<Self>,
) -> Task<Option<EvaluateResponse>> {
self.request(
EvaluateCommand {
expression,
context,
frame_id,
source,
},
|this, response, cx| {
let response = response.log_err()?;
this.output_token.0 += 1;
this.output.push_back(dap::OutputEvent {
category: None,
output: response.result.clone(),
group: None,
variables_reference: Some(response.variables_reference),
source: None,
line: None,
column: None,
data: None,
location_reference: None,
});
) -> Task<()> {
let request = self.mode.request_dap(EvaluateCommand {
expression,
context,
frame_id,
source,
});
cx.spawn(async move |this, cx| {
let response = request.await;
this.update(cx, |this, cx| {
match response {
Ok(response) => {
this.output_token.0 += 1;
this.output.push_back(dap::OutputEvent {
category: None,
output: format!("< {}", &response.result),
group: None,
variables_reference: Some(response.variables_reference),
source: None,
line: None,
column: None,
data: None,
location_reference: None,
});
}
Err(e) => {
this.output_token.0 += 1;
this.output.push_back(dap::OutputEvent {
category: None,
output: format!("{}", e),
group: None,
variables_reference: None,
source: None,
line: None,
column: None,
data: None,
location_reference: None,
});
}
};
this.invalidate_command_type::<ScopesCommand>();
cx.notify();
Some(response)
},
cx,
)
})
.ok();
})
}
pub fn location(