@@ -320,161 +320,177 @@ impl Application {
320320
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};
323+ use dap::requests::RunInTerminal;
323324 use helix_dap::{events, Event};
324325
326+ let debugger = match self.editor.debugger.as_mut() {
327+ Some(debugger) => debugger,
328+ None => return,
329+ };
325330 match payload {
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;
331+ Payload::Event(ev) => 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;
353346 }
354− } else if let Some(thread_id) = thread_id {
355− debugger.thread_states.insert(thread_id, reason.clone()); // TODO: dap uses "type" || "reason" here
356−
357− // whichever thread stops is made "current" (if no previously selected thread).
358− select_thread_id(&mut self.editor, thread_id, false).await;
347+ select_thread_id(
348+ &mut self.editor,
349+ thread_id.unwrap_or_default(),
350+ false,
351+ )
352+ .await;
359353 }
354+ } else if let Some(thread_id) = thread_id {
355+ debugger.thread_states.insert(thread_id, reason.clone()); // TODO: dap uses "type" || "reason" here
360356
361− let scope = match thread_id {
362− Some(id) => format!("Thread {}", id),
363− None => "Target".to_owned(),
364− };
357+ // whichever thread stops is made "current" (if no previously selected thread).
358+ select_thread_id(&mut self.editor, thread_id, false).await;
359+ }
365360
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− }
361+ let scope = match thread_id {
362+ Some(id) => format!("Thread {}", id),
363+ None => "Target".to_owned(),
364+ };
376365
377− self.editor.set_status(status);
366+ let mut status = format!("{} stopped because of {}", scope, reason);
367+ if let Some(desc) = description {
368+ status.push_str(&format!(" {}", desc));
378369 }
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)
385− }
370+ if let Some(text) = text {
371+ status.push_str(&format!(" {}", text));
386372 }
387− Event::Thread(_) => {
388− // TODO: update thread_states, make threads request
373+ if all_threads_stopped {
374+ status.push_str(" (all threads stopped)");
389375 }
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− }
376+
377+ self.editor.set_status(status);
378+ }
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)
385+ }
386+ }
387+ Event::Thread(_) => {
388+ // TODO: update thread_states, make threads request
389+ }
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+ });
407406 }
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− }
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;
419418 }
420419 }
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− }
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);
428427 }
429428 }
430− reason => {
431− warn!("Unknown breakpoint event: {}", reason);
432− }
429+ }
430+ reason => {
431+ warn!("Unknown breakpoint event: {}", reason);
433432 }
434433 }
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)
434+ }
435+ Event::Output(events::Output {
436+ category, output, ..
437+ }) => {
438+ let prefix = match category {
439+ Some(category) => {
440+ if &category == "telemetry" {
441+ return;
444442 }
445− None => "Debug:".to_owned(),
446− };
447−
448− log::info!("{}", output);
449− self.editor.set_status(format!("{} {}", prefix, output));
450− }
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);
443+ format!("Debug ({}):", category)
456444 }
457− // TODO: fetch breakpoints (in case we're attaching)
445+ None => "Debug:".to_owned(),
446+ };
458447
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
448+ log::info!("{}", output);
449+ self.editor.set_status(format!("{} {}", prefix, output));
450+ }
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);
467456 }
457+ // TODO: fetch breakpoints (in case we're attaching)
458+
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?
468463 }
469− }
464+ ev => {
465+ log::warn!("Unhandled event {:?}", ev);
466+ return; // return early to skip render
467+ }
468+ },
470469 Payload::Response(_) => unreachable!(),
471470 Payload::Request(request) => match request.command.as_str() {
472− dap::requests::RunInTerminal::COMMAND => {
471+ RunInTerminal::COMMAND => {
473472 let arguments: dap::requests::RunInTerminalArguments =
474473 serde_json::from_value(request.arguments.unwrap_or_default()).unwrap();
475474 // TODO: no unwrap
476475
477− // TODO: dap reply
476+ // TODO: handle cwd
477+ let process = std::process::Command::new("tmux")
478+ .arg("split-window")
479+ .arg(arguments.args.join(" ")) // TODO: first arg is wrong, it uses current dir
480+ .spawn()
481+ .unwrap();
482+
483+ let _ = debugger
484+ .reply(
485+ request.seq,
486+ dap::requests::RunInTerminal::COMMAND,
487+ serde_json::to_value(dap::requests::RunInTerminalResponse {
488+ process_id: Some(process.id()),
489+ shell_process_id: None,
490+ })
491+ .map_err(|e| e.into()),
492+ )
493+ .await;
478494 }
479495 _ => log::error!("DAP reverse request not implemented: {:?}", request),
480496 },