on master help sign in
dap: Start working on runInTerminal support
commit2dbf966293c7a92bd5eb6062c7033a20a207609f authorBlaž Hrastnik <blaz@mxxn.io> dateFri 3 Dec 2021, 11:59 (5 years ago) parent0d73a4d
5 files changed+155−129
helix-core/src/syntax.rs+1 helix-dap/src/client.rs+1−1 helix-term/src/application.rs+128−121 helix-term/src/commands/dap.rs+19−7 languages.toml+6
helix-core/src/syntax.rs+1
@@ -114,6 +114,7 @@ pub enum DebugConfigCompletion {
114114pub enum DebugArgumentValue {
115115 String(String),
116116 Array(Vec<String>),
117+ Boolean(bool),
117118}
118119
119120#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
helix-dap/src/client.rs+1−1
@@ -244,7 +244,7 @@ impl Client {
244244 path_format: Some("path".to_owned()),
245245 supports_variable_type: Some(true),
246246 supports_variable_paging: Some(false),
247− supports_run_in_terminal_request: Some(false),
247+ supports_run_in_terminal_request: Some(true),
248248 supports_memory_references: Some(false),
249249 supports_progress_reporting: Some(false),
250250 supports_invalidated_event: Some(false),
helix-term/src/application.rs+128−121
@@ -321,147 +321,154 @@ impl Application {
321321 pub async fn handle_debugger_message(&mut self, payload: helix_dap::Payload) {
322322 use crate::commands::dap::{breakpoints_changed, resume_application, select_thread_id};
323323 use helix_dap::{events, Event};
324− let debugger = match self.editor.debugger.as_mut() {
325− Some(debugger) => debugger,
326− None => return,
327− };
328324
329325 match payload {
330− Payload::Event(ev) => match ev {
331− Event::Stopped(events::Stopped {
332− thread_id,
333− description,
334− text,
335− reason,
336− all_threads_stopped,
337− ..
338− }) => {
339− let all_threads_stopped = all_threads_stopped.unwrap_or_default();
340−
341− if all_threads_stopped {
342− if let Ok(threads) = debugger.threads().await {
343− for thread in threads {
344− fetch_stack_trace(debugger, thread.id).await;
326+ Payload::Event(ev) => {
327+ let debugger = match self.editor.debugger.as_mut() {
328+ Some(debugger) => debugger,
329+ None => return,
330+ };
331+ match ev {
332+ Event::Stopped(events::Stopped {
333+ thread_id,
334+ description,
335+ text,
336+ reason,
337+ all_threads_stopped,
338+ ..
339+ }) => {
340+ let all_threads_stopped = all_threads_stopped.unwrap_or_default();
341+
342+ if all_threads_stopped {
343+ if let Ok(threads) = debugger.threads().await {
344+ for thread in threads {
345+ fetch_stack_trace(debugger, thread.id).await;
346+ }
347+ select_thread_id(
348+ &mut self.editor,
349+ thread_id.unwrap_or_default(),
350+ false,
351+ )
352+ .await;
345353 }
346− select_thread_id(
347− &mut self.editor,
348− thread_id.unwrap_or_default(),
349− false,
350− )
351− .await;
352− }
353− } else if let Some(thread_id) = thread_id {
354− debugger.thread_states.insert(thread_id, reason.clone()); // TODO: dap uses "type" || "reason" here
354+ } else if let Some(thread_id) = thread_id {
355+ debugger.thread_states.insert(thread_id, reason.clone()); // TODO: dap uses "type" || "reason" here
355356
356− // whichever thread stops is made "current" (if no previously selected thread).
357− select_thread_id(&mut self.editor, thread_id, false).await;
358− }
357+ // whichever thread stops is made "current" (if no previously selected thread).
358+ select_thread_id(&mut self.editor, thread_id, false).await;
359+ }
359360
360− let scope = match thread_id {
361− Some(id) => format!("Thread {}", id),
362− None => "Target".to_owned(),
363− };
361+ let scope = match thread_id {
362+ Some(id) => format!("Thread {}", id),
363+ None => "Target".to_owned(),
364+ };
364365
365− let mut status = format!("{} stopped because of {}", scope, reason);
366− if let Some(desc) = description {
367− status.push_str(&format!(" {}", desc));
368− }
369− if let Some(text) = text {
370− status.push_str(&format!(" {}", text));
371− }
372− if all_threads_stopped {
373− status.push_str(" (all threads stopped)");
374− }
366+ let mut status = format!("{} stopped because of {}", scope, reason);
367+ if let Some(desc) = description {
368+ status.push_str(&format!(" {}", desc));
369+ }
370+ if let Some(text) = text {
371+ status.push_str(&format!(" {}", text));
372+ }
373+ if all_threads_stopped {
374+ status.push_str(" (all threads stopped)");
375+ }
375376
376− self.editor.set_status(status);
377− }
378− Event::Continued(events::Continued { thread_id, .. }) => {
379− debugger
380− .thread_states
381− .insert(thread_id, "running".to_owned());
382− if debugger.thread_id == Some(thread_id) {
383− resume_application(debugger)
377+ self.editor.set_status(status);
384378 }
385− }
386− Event::Thread(_) => {
387− // TODO: update thread_states, make threads request
388− }
389− Event::Breakpoint(events::Breakpoint { reason, breakpoint }) => match &reason[..] {
390− "new" => {
391− if let Some(source) = breakpoint.source {
392− self.editor
393− .breakpoints
394− .entry(source.path.unwrap()) // TODO: no unwraps
395− .or_default()
396− .push(Breakpoint {
397− id: breakpoint.id,
398− verified: breakpoint.verified,
399− message: breakpoint.message,
400− line: breakpoint.line.unwrap().saturating_sub(1), // TODO: no unwrap
401− column: breakpoint.column,
402− ..Default::default()
403− });
379+ Event::Continued(events::Continued { thread_id, .. }) => {
380+ debugger
381+ .thread_states
382+ .insert(thread_id, "running".to_owned());
383+ if debugger.thread_id == Some(thread_id) {
384+ resume_application(debugger)
404385 }
405386 }
406− "changed" => {
407− for breakpoints in self.editor.breakpoints.values_mut() {
408− if let Some(i) = breakpoints.iter().position(|b| b.id == breakpoint.id)
409− {
410− breakpoints[i].verified = breakpoint.verified;
411− breakpoints[i].message = breakpoint.message.clone();
412− breakpoints[i].line = breakpoint.line.unwrap().saturating_sub(1); // TODO: no unwrap
413− breakpoints[i].column = breakpoint.column;
414− }
415− }
387+ Event::Thread(_) => {
388+ // TODO: update thread_states, make threads request
416389 }
417− "removed" => {
418− for breakpoints in self.editor.breakpoints.values_mut() {
419− if let Some(i) = breakpoints.iter().position(|b| b.id == breakpoint.id)
420− {
421− breakpoints.remove(i);
390+ Event::Breakpoint(events::Breakpoint { reason, breakpoint }) => {
391+ match &reason[..] {
392+ "new" => {
393+ if let Some(source) = breakpoint.source {
394+ self.editor
395+ .breakpoints
396+ .entry(source.path.unwrap()) // TODO: no unwraps
397+ .or_default()
398+ .push(Breakpoint {
399+ id: breakpoint.id,
400+ verified: breakpoint.verified,
401+ message: breakpoint.message,
402+ line: breakpoint.line.unwrap().saturating_sub(1), // TODO: no unwrap
403+ column: breakpoint.column,
404+ ..Default::default()
405+ });
406+ }
407+ }
408+ "changed" => {
409+ for breakpoints in self.editor.breakpoints.values_mut() {
410+ if let Some(i) =
411+ breakpoints.iter().position(|b| b.id == breakpoint.id)
412+ {
413+ breakpoints[i].verified = breakpoint.verified;
414+ breakpoints[i].message = breakpoint.message.clone();
415+ breakpoints[i].line =
416+ breakpoint.line.unwrap().saturating_sub(1); // TODO: no unwrap
417+ breakpoints[i].column = breakpoint.column;
418+ }
419+ }
420+ }
421+ "removed" => {
422+ for breakpoints in self.editor.breakpoints.values_mut() {
423+ if let Some(i) =
424+ breakpoints.iter().position(|b| b.id == breakpoint.id)
425+ {
426+ breakpoints.remove(i);
427+ }
428+ }
429+ }
430+ reason => {
431+ warn!("Unknown breakpoint event: {}", reason);
422432 }
423433 }
424434 }
425− reason => {
426− warn!("Unknown breakpoint event: {}", reason);
427− }
428− },
429− Event::Output(events::Output {
430− category, output, ..
431− }) => {
432− let prefix = match category {
433− Some(category) => {
434− if &category == "telemetry" {
435− return;
435+ Event::Output(events::Output {
436+ category, output, ..
437+ }) => {
438+ let prefix = match category {
439+ Some(category) => {
440+ if &category == "telemetry" {
441+ return;
442+ }
443+ format!("Debug ({}):", category)
436444 }
437− format!("Debug ({}):", category)
438− }
439− None => "Debug:".to_owned(),
440− };
445+ None => "Debug:".to_owned(),
446+ };
441447
442− log::info!("{}", output);
443− self.editor.set_status(format!("{} {}", prefix, output));
444− }
445− Event::Initialized => {
446− // send existing breakpoints
447− for (path, breakpoints) in &mut self.editor.breakpoints {
448− // TODO: call futures in parallel, await all
449− let _ = breakpoints_changed(debugger, path.clone(), breakpoints);
448+ log::info!("{}", output);
449+ self.editor.set_status(format!("{} {}", prefix, output));
450450 }
451− // TODO: fetch breakpoints (in case we're attaching)
451+ Event::Initialized => {
452+ // send existing breakpoints
453+ for (path, breakpoints) in &mut self.editor.breakpoints {
454+ // TODO: call futures in parallel, await all
455+ let _ = breakpoints_changed(debugger, path.clone(), breakpoints);
456+ }
457+ // TODO: fetch breakpoints (in case we're attaching)
452458
453− if debugger.configuration_done().await.is_ok() {
454− self.editor
455− .set_status("Debugged application started".to_owned());
456− }; // TODO: do we need to handle error?
457− }
458− ev => {
459− log::warn!("Unhandled event {:?}", ev);
460− return; // return early to skip render
459+ if debugger.configuration_done().await.is_ok() {
460+ self.editor
461+ .set_status("Debugged application started".to_owned());
462+ }; // TODO: do we need to handle error?
463+ }
464+ ev => {
465+ log::warn!("Unhandled event {:?}", ev);
466+ return; // return early to skip render
467+ }
461468 }
462− },
469+ }
463470 Payload::Response(_) => unreachable!(),
464− Payload::Request(_) => todo!(),
471+ Payload::Request(request) => unimplemented!("{:?}", request),
465472 }
466473 self.render();
467474 }
helix-term/src/commands/dap.rs+19−7
@@ -251,29 +251,40 @@ pub fn dap_start_impl(
251251 // For param #0 replace {0} in args
252252 let pattern = format!("{{{}}}", i);
253253 value = match value {
254+ // TODO: just use toml::Value -> json::Value
254255 DebugArgumentValue::String(v) => {
255256 DebugArgumentValue::String(v.replace(&pattern, &param))
256257 }
257258 DebugArgumentValue::Array(arr) => DebugArgumentValue::Array(
258259 arr.iter().map(|v| v.replace(&pattern, &param)).collect(),
259260 ),
261+ DebugArgumentValue::Boolean(_) => value,
260262 };
261263 }
262264
263− if let DebugArgumentValue::String(string) = value {
264− if let Ok(integer) = string.parse::<usize>() {
265− args.insert(k, to_value(integer).unwrap());
266− } else {
267− args.insert(k, to_value(string).unwrap());
265+ match value {
266+ DebugArgumentValue::String(string) => {
267+ if let Ok(integer) = string.parse::<usize>() {
268+ args.insert(k, to_value(integer).unwrap());
269+ } else {
270+ args.insert(k, to_value(string).unwrap());
271+ }
272+ }
273+ DebugArgumentValue::Array(arr) => {
274+ args.insert(k, to_value(arr).unwrap());
275+ }
276+ DebugArgumentValue::Boolean(bool) => {
277+ args.insert(k, to_value(bool).unwrap());
268278 }
269− } else if let DebugArgumentValue::Array(arr) = value {
270− args.insert(k, to_value(arr).unwrap());
271279 }
272280 }
273281 }
274282
275283 let args = to_value(args).unwrap();
276284
285+ // problem: this blocks for too long while we get back the startInTerminal REQ
286+
287+ log::error!("pre start");
277288 let result = match &template.request[..] {
278289 "launch" => block_on(debugger.launch(args)),
279290 "attach" => block_on(debugger.attach(args)),
@@ -282,6 +293,7 @@ pub fn dap_start_impl(
282293 return;
283294 }
284295 };
296+ log::error!("post start");
285297 if let Err(e) = result {
286298 let msg = format!("Failed {} target: {}", template.request, e);
287299 editor.set_error(msg);
languages.toml+6
@@ -23,6 +23,12 @@ request = "launch"
2323completion = [ { name = "binary", completion = "filename" } ]
2424args = { program = "{0}" }
2525
26+[[language.debugger.templates]]
27+name = "binary (terminal)"
28+request = "launch"
29+completion = [ { name = "binary", completion = "filename" } ]
30+args = { program = "{0}", runInTerminal = true }
31+
2632[[language.debugger.templates]]
2733name = "attach"
2834request = "attach"