Show sleeping proc queue as threads in VSC

This commit is contained in:
Tad Hardesty 2020-09-23 21:20:45 -07:00
parent 1da4eb3246
commit 1fc5056b40
4 changed files with 107 additions and 3 deletions

View file

@ -113,6 +113,28 @@ pub struct ErrorResponseBody {
// ----------------------------------------------------------------------------
// Events
/// The event indicates that the execution of the debuggee has continued.
///
/// Please note: a debug adapter is not expected to send this event in response to a request that implies that execution continues, e.g. launch or continue.
///
/// It is only necessary to send a continued event if there was no previous request that implied this.
#[derive(Serialize, Deserialize, Debug)]
pub struct ContinuedEvent {
/**
* The thread which was continued.
*/
pub threadId: i64,
/**
* If 'allThreadsContinued' is true, a debug adapter can announce that all threads have continued.
*/
pub allThreadsContinued: Option<bool>,
}
impl Event for ContinuedEvent {
const EVENT: &'static str = "continued";
}
/// The event indicates that the debuggee has exited and returns its exit code.
#[derive(Serialize, Deserialize, Debug)]
pub struct ExitedEvent {
@ -141,6 +163,30 @@ impl Event for TerminatedEvent {
const EVENT: &'static str = "terminated";
}
/// The event indicates that a thread has started or exited.
#[derive(Serialize, Deserialize, Debug)]
pub struct ThreadEvent {
/**
* The reason for the event.
* Values: 'started', 'exited', etc.
*/
pub reason: String,
/**
* The identifier of the thread.
*/
pub threadId: i64,
}
impl ThreadEvent {
pub const REASON_STARTED: &'static str = "started";
pub const REASON_EXITED: &'static str = "exited";
}
impl Event for ThreadEvent {
const EVENT: &'static str = "thread";
}
/// The event indicates that the target has produced some output.
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct OutputEvent {

View file

@ -480,7 +480,11 @@ handle_extools! {
on CallStack(&mut self, stack) {
let mut map = self.threads.lock().unwrap();
map.entry(0).or_default().call_stack = stack.0;
map.clear();
map.entry(0).or_default().call_stack = stack.current;
for (i, list) in stack.suspended.into_iter().enumerate() {
map.entry((i + 1) as i64).or_default().call_stack = list;
}
}
on DisassembledProc(&mut self, disasm) {

View file

@ -436,7 +436,10 @@ impl Response for BreakpointHit {
// #define MESSAGE_CALL_STACK "call stack" //Content is a vector of proc paths
#[derive(Deserialize, Debug)]
pub struct CallStack(pub Vec<StackFrame>);
pub struct CallStack {
pub current: Vec<StackFrame>,
pub suspended: Vec<Vec<StackFrame>>,
}
impl Response for CallStack {
const TYPE: &'static str = "call stack";

View file

@ -274,6 +274,36 @@ impl Debugger {
fn issue_event<E: Event>(&mut self, event: E) {
self.seq.issue_event(event);
}
fn notify_continue(&mut self) {
// Called when a Step occurs so we can tell VSC that actually you can't
// do that on a per-thread basis in DM.
self.cull_thread_list();
self.issue_event(dap_types::ContinuedEvent {
threadId: 0,
allThreadsContinued: Some(true),
});
}
fn cull_thread_list(&mut self) {
// Cull threads other than the main thread so that VSC goes back to
// acting like the application is single-threaded, rather than showing
// the last-known sleeping stacks every time.
// An alternative would be to send these in real-time when sleeping
// threads enter or exit existence.
let keys: Vec<_> = {
guard!(let Ok(extools) = self.extools.get() else { return });
extools.get_all_threads().keys().cloned().filter(|&k| k != 0).collect()
};
for k in keys {
self.issue_event(dap_types::ThreadEvent {
reason: dap_types::ThreadEvent::REASON_EXITED.to_owned(),
threadId: k,
});
}
}
}
const EXCEPTION_FILTER_RUNTIMES: &str = "runtimes";
@ -373,8 +403,25 @@ handle_request! {
}
on Threads(&mut self, ()) {
let mut threads = Vec::new();
let extools = self.extools.get()?;
for (&k, v) in extools.get_all_threads().iter() {
threads.push(Thread {
id: k,
name: v.call_stack.last().unwrap().proc.clone(),
});
}
if threads.is_empty() {
threads.push(Thread {
id: 0,
name: "Main".to_owned(),
});
}
ThreadsResponse {
threads: vec![Thread { id: 0, name: "Main".to_owned() }]
threads,
}
}
@ -757,6 +804,7 @@ handle_request! {
}
on Continue(&mut self, _params) {
self.cull_thread_list();
let extools = self.extools.get()?;
extools.continue_execution();
ContinueResponse {
@ -765,16 +813,19 @@ handle_request! {
}
on StepIn(&mut self, params) {
self.notify_continue();
let extools = self.extools.get()?;
extools.step_in(params.threadId);
}
on Next(&mut self, params) {
self.notify_continue();
let extools = self.extools.get()?;
extools.step_over(params.threadId);
}
on StepOut(&mut self, params) {
self.notify_continue();
let extools = self.extools.get()?;
extools.step_out(params.threadId);
}