@@ -1,3 +1,7 @@
1+mod dap;
2+
3+pub use dap::*;
4+
15use helix_core::{
26 comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, indent,
37 indent::IndentStyle,
@@ -24,13 +28,11 @@ use helix_lsp::{
2428};
2529use insert::*;
2630use movement::Movement;
27−use serde_json::Value;
2831
2932use crate::{
3033 compositor::{self, Component, Compositor},
3134 ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent},
3235};
33−use tokio_stream::wrappers::UnboundedReceiverStream;
3436
3537use crate::job::{self, Job, Jobs};
3638use futures_util::FutureExt;
@@ -4490,366 +4492,3 @@ fn suspend(_cx: &mut Context) {
44904492 #[cfg(not(windows))]
44914493 signal_hook::low_level::raise(signal_hook::consts::signal::SIGTSTP).unwrap();
44924494}
4493−
4494−// DAP
4495−pub fn dap_start_impl(
4496− editor: &mut Editor,
4497− name: Option<&str>,
4498− socket: Option<std::net::SocketAddr>,
4499− params: Option<Vec<&str>>,
4500−) {
4501− use helix_dap::Client;
4502− use helix_lsp::block_on;
4503− use serde_json::to_value;
4504−
4505− let (_, doc) = current!(editor);
4506−
4507− let path = match doc.path() {
4508− Some(path) => path.to_path_buf(),
4509− None => {
4510− editor.set_error("Can't start debug: document has no path".to_string());
4511− return;
4512− }
4513− };
4514−
4515− let config = editor
4516− .syn_loader
4517− .language_config_for_file_name(&path)
4518− .and_then(|x| x.debugger.clone());
4519− let config = match config {
4520− Some(c) => c,
4521− None => {
4522− editor.set_error(
4523− "Can't start debug: no debug adapter available for language".to_string(),
4524− );
4525− return;
4526− }
4527− };
4528−
4529− let result = match socket {
4530− Some(socket) => block_on(Client::tcp(socket, 0)),
4531− None => block_on(Client::process(
4532− config.transport.clone(),
4533− config.command.clone(),
4534− config.args.clone(),
4535− config.port_arg.clone(),
4536− 0,
4537− )),
4538− };
4539−
4540− let (mut debugger, events) = match result {
4541− Ok(r) => r,
4542− Err(e) => {
4543− editor.set_error(format!("Failed to start debug session: {:?}", e));
4544− return;
4545− }
4546− };
4547−
4548− let request = debugger.initialize(config.name.clone());
4549− if let Err(e) = block_on(request) {
4550− editor.set_error(format!("Failed to initialize debug adapter: {:?}", e));
4551− return;
4552− }
4553−
4554− let start_config = match name {
4555− Some(name) => config.templates.iter().find(|t| t.name == name),
4556− None => config.templates.get(0),
4557− };
4558− let start_config = match start_config {
4559− Some(c) => c,
4560− None => {
4561− editor.set_error("Can't start debug: no debug config with given name".to_string());
4562− return;
4563− }
4564− };
4565−
4566− let template = start_config.args.clone();
4567− let mut args: HashMap<String, Value> = HashMap::new();
4568−
4569− if let Some(params) = params {
4570− for (k, t) in template {
4571− let mut value = t;
4572− for (i, x) in params.iter().enumerate() {
4573− // For param #0 replace {0} in args
4574− value = value.replace(format!("{{{}}}", i).as_str(), x);
4575− }
4576−
4577− if let Ok(integer) = value.parse::<usize>() {
4578− args.insert(k, Value::Number(serde_json::Number::from(integer)));
4579− } else {
4580− args.insert(k, Value::String(value));
4581− }
4582− }
4583− }
4584−
4585− let args = to_value(args).unwrap();
4586−
4587− let result = match &start_config.request[..] {
4588− "launch" => block_on(debugger.launch(args)),
4589− "attach" => block_on(debugger.attach(args)),
4590− _ => {
4591− editor.set_error("Unsupported request".to_string());
4592− return;
4593− }
4594− };
4595− if let Err(e) = result {
4596− editor.set_error(format!("Failed {} target: {:?}", start_config.request, e));
4597− return;
4598− }
4599−
4600− // TODO: either await "initialized" or buffer commands until event is received
4601− editor.debugger = Some(debugger);
4602− let stream = UnboundedReceiverStream::new(events);
4603− editor.debugger_events.push(stream);
4604−}
4605−
4606−fn dap_launch(cx: &mut Context) {
4607− if cx.editor.debugger.is_some() {
4608− cx.editor
4609− .set_error("Can't start debug: debugger is running".to_string());
4610− return;
4611− }
4612−
4613− let (_, doc) = current!(cx.editor);
4614− let path = match doc.path() {
4615− Some(path) => path.to_path_buf(),
4616− None => {
4617− cx.editor
4618− .set_error("Can't start debug: document has no path".to_string());
4619− return;
4620− }
4621− };
4622−
4623− let config = cx
4624− .editor
4625− .syn_loader
4626− .language_config_for_file_name(&path)
4627− .and_then(|x| x.debugger.clone());
4628− let config = match config {
4629− Some(c) => c,
4630− None => {
4631− cx.editor.set_error(
4632− "Can't start debug: no debug adapter available for language".to_string(),
4633− );
4634− return;
4635− }
4636− };
4637−
4638− cx.editor.debug_config_picker = Some(config.templates.iter().map(|t| t.name.clone()).collect());
4639− cx.editor.debug_config_completions = Some(
4640− config
4641− .templates
4642− .iter()
4643− .map(|t| t.completion.clone())
4644− .collect(),
4645− );
4646−}
4647−
4648−fn dap_toggle_breakpoint(cx: &mut Context) {
4649− use helix_lsp::block_on;
4650−
4651− let (view, doc) = current!(cx.editor);
4652− let text = doc.text().slice(..);
4653− let pos = doc.selection(view.id).primary().cursor(text);
4654−
4655− let breakpoint = helix_dap::SourceBreakpoint {
4656− line: text.char_to_line(pos) + 1, // convert from 0-indexing to 1-indexing (TODO: could set debugger to 0-indexing on init)
4657− ..Default::default()
4658− };
4659−
4660− let path = match doc.path() {
4661− Some(path) => path.to_path_buf(),
4662− None => {
4663− cx.editor
4664− .set_error("Can't set breakpoint: document has no path".to_string());
4665− return;
4666− }
4667− };
4668−
4669− // TODO: need to map breakpoints over edits and update them?
4670− // we shouldn't really allow editing while debug is running though
4671−
4672− if let Some(debugger) = &mut cx.editor.debugger {
4673− let breakpoints = debugger.breakpoints.entry(path.clone()).or_default();
4674− if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) {
4675− breakpoints.remove(pos);
4676− } else {
4677− breakpoints.push(breakpoint);
4678− }
4679−
4680− let breakpoints = breakpoints.clone();
4681−
4682− let request = debugger.set_breakpoints(path, breakpoints);
4683− if let Err(e) = block_on(request) {
4684− cx.editor
4685− .set_error(format!("Failed to set breakpoints: {:?}", e));
4686− }
4687− }
4688−}
4689−
4690−fn dap_run(cx: &mut Context) {
4691− use helix_lsp::block_on;
4692−
4693− if let Some(debugger) = &mut cx.editor.debugger {
4694− if debugger.is_running {
4695− cx.editor
4696− .set_status("Debuggee is already running".to_owned());
4697− return;
4698− }
4699− let request = debugger.configuration_done();
4700− if let Err(e) = block_on(request) {
4701− cx.editor.set_error(format!("Failed to run: {:?}", e));
4702− return;
4703− }
4704− debugger.is_running = true;
4705− }
4706−}
4707−
4708−fn dap_continue(cx: &mut Context) {
4709− use helix_lsp::block_on;
4710−
4711− if let Some(debugger) = &mut cx.editor.debugger {
4712− if debugger.is_running {
4713− cx.editor
4714− .set_status("Debuggee is already running".to_owned());
4715− return;
4716− }
4717−
4718− let request = debugger.continue_thread(debugger.stopped_thread.unwrap());
4719− if let Err(e) = block_on(request) {
4720− cx.editor.set_error(format!("Failed to continue: {:?}", e));
4721− return;
4722− }
4723− debugger.is_running = true;
4724− debugger.stack_pointer = None;
4725− }
4726−}
4727−
4728−fn dap_pause(cx: &mut Context) {
4729− use helix_lsp::block_on;
4730−
4731− if let Some(debugger) = &mut cx.editor.debugger {
4732− if !debugger.is_running {
4733− cx.editor.set_status("Debuggee is not running".to_owned());
4734− return;
4735− }
4736−
4737− // FIXME: correct number here
4738− let request = debugger.pause(0);
4739− if let Err(e) = block_on(request) {
4740− cx.editor.set_error(format!("Failed to pause: {:?}", e));
4741− }
4742− }
4743−}
4744−
4745−fn dap_step_in(cx: &mut Context) {
4746− use helix_lsp::block_on;
4747−
4748− if let Some(debugger) = &mut cx.editor.debugger {
4749− if debugger.is_running {
4750− cx.editor
4751− .set_status("Debuggee is already running".to_owned());
4752− return;
4753− }
4754−
4755− let request = debugger.step_in(debugger.stopped_thread.unwrap());
4756− if let Err(e) = block_on(request) {
4757− cx.editor.set_error(format!("Failed to step: {:?}", e));
4758− }
4759− }
4760−}
4761−
4762−fn dap_step_out(cx: &mut Context) {
4763− use helix_lsp::block_on;
4764−
4765− if let Some(debugger) = &mut cx.editor.debugger {
4766− if debugger.is_running {
4767− cx.editor
4768− .set_status("Debuggee is already running".to_owned());
4769− return;
4770− }
4771−
4772− let request = debugger.step_out(debugger.stopped_thread.unwrap());
4773− if let Err(e) = block_on(request) {
4774− cx.editor.set_error(format!("Failed to step: {:?}", e));
4775− }
4776− }
4777−}
4778−
4779−fn dap_next(cx: &mut Context) {
4780− use helix_lsp::block_on;
4781−
4782− if let Some(debugger) = &mut cx.editor.debugger {
4783− if debugger.is_running {
4784− cx.editor
4785− .set_status("Debuggee is already running".to_owned());
4786− return;
4787− }
4788−
4789− let request = debugger.next(debugger.stopped_thread.unwrap());
4790− if let Err(e) = block_on(request) {
4791− cx.editor.set_error(format!("Failed to step: {:?}", e));
4792− }
4793− }
4794−}
4795−
4796−fn dap_variables(cx: &mut Context) {
4797− use helix_lsp::block_on;
4798−
4799− if let Some(debugger) = &mut cx.editor.debugger {
4800− if debugger.is_running {
4801− cx.editor
4802− .set_status("Cannot access variables while target is running".to_owned());
4803− return;
4804− }
4805− if debugger.stack_pointer.is_none() {
4806− cx.editor
4807− .set_status("Cannot find current stack pointer to access variables".to_owned());
4808− return;
4809− }
4810−
4811− let frame_id = debugger.stack_pointer.clone().unwrap().id;
4812− let scopes = match block_on(debugger.scopes(frame_id)) {
4813− Ok(s) => s,
4814− Err(e) => {
4815− cx.editor
4816− .set_error(format!("Failed to get scopes: {:?}", e));
4817− return;
4818− }
4819− };
4820− let mut variables = Vec::new();
4821−
4822− for scope in scopes.iter() {
4823− let response = block_on(debugger.variables(scope.variables_reference));
4824−
4825− if let Ok(vars) = response {
4826− for var in vars {
4827− let prefix = match var.data_type {
4828− Some(data_type) => format!("{} ", data_type),
4829− None => "".to_owned(),
4830− };
4831− variables.push(format!("{}{} = {}\n", prefix, var.name, var.value));
4832− }
4833− }
4834− }
4835−
4836− if !variables.is_empty() {
4837− cx.editor.variables = Some(variables);
4838− cx.editor.variables_page = 0;
4839− }
4840− }
4841−}
4842−
4843−fn dap_terminate(cx: &mut Context) {
4844− use helix_lsp::block_on;
4845−
4846− if let Some(debugger) = &mut cx.editor.debugger {
4847− let request = debugger.disconnect();
4848− if let Err(e) = block_on(request) {
4849− cx.editor
4850− .set_error(format!("Failed to disconnect: {:?}", e));
4851− return;
4852− }
4853− cx.editor.debugger = None;
4854− }
4855−}