diff options
Diffstat (limited to 'helix-term/src/commands.rs')
-rw-r--r-- | helix-term/src/commands.rs | 130 |
1 files changed, 109 insertions, 21 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ded5a0e4..677943e8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1,3 +1,7 @@ +pub(crate) mod dap; + +pub use dap::*; + use helix_core::{ comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, history::UndoKind, @@ -45,8 +49,8 @@ use crate::{ use crate::job::{self, Job, Jobs}; use futures_util::{FutureExt, StreamExt}; +use std::{collections::HashMap, fmt, future::Future}; use std::{collections::HashSet, num::NonZeroUsize}; -use std::{fmt, future::Future}; use std::{ borrow::Cow, @@ -115,13 +119,13 @@ impl<'a> Context<'a> { } } -pub(crate) enum Align { +pub enum Align { Top, Center, Bottom, } -pub(crate) fn align_view(doc: &Document, view: &mut View, align: Align) { +pub fn align_view(doc: &Document, view: &mut View, align: Align) { let pos = doc .selection(view.id) .primary() @@ -394,6 +398,21 @@ impl MappableCommand { surround_delete, "Surround delete", select_textobject_around, "Select around object", select_textobject_inner, "Select inside object", + dap_launch, "Launch debug target", + dap_toggle_breakpoint, "Toggle breakpoint", + dap_continue, "Continue program execution", + dap_pause, "Pause program execution", + dap_step_in, "Step in", + dap_step_out, "Step out", + dap_next, "Step to next", + dap_variables, "List variables", + dap_terminate, "End debug session", + dap_edit_condition, "Edit condition of the breakpoint on the current line", + dap_edit_log, "Edit log message of the breakpoint on the current line", + dap_switch_thread, "Switch current thread", + dap_switch_stack_frame, "Switch stack frame", + dap_enable_exceptions, "Enable exception breakpoints", + dap_disable_exceptions, "Disable exception breakpoints", shell_pipe, "Pipe selections through shell command", shell_pipe_to, "Pipe selections into shell command, ignoring command output", shell_insert_output, "Insert output of shell command before each selection", @@ -1550,7 +1569,6 @@ fn search_completions(cx: &mut Context, reg: Option<char>) -> Vec<String> { items.into_iter().cloned().collect() } -// TODO: use one function for search vs extend fn search(cx: &mut Context) { searcher(cx, Direction::Forward) } @@ -1558,7 +1576,7 @@ fn search(cx: &mut Context) { fn rsearch(cx: &mut Context) { searcher(cx, Direction::Backward) } -// TODO: use one function for search vs extend + fn searcher(cx: &mut Context, direction: Direction) { let reg = cx.register.unwrap_or('/'); let scrolloff = cx.editor.config.scrolloff; @@ -1783,11 +1801,11 @@ fn global_search(cx: &mut Context) { relative_path.into() } }, - move |editor: &mut Editor, (line_num, path), action| { - match editor.open(path.into(), action) { + move |cx, (line_num, path), action| { + match cx.editor.open(path.into(), action) { Ok(_) => {} Err(e) => { - editor.set_error(format!( + cx.editor.set_error(format!( "Failed to open file '{}': {}", path.display(), e @@ -1797,7 +1815,7 @@ fn global_search(cx: &mut Context) { } let line_num = *line_num; - let (view, doc) = current!(editor); + let (view, doc) = current!(cx.editor); let text = doc.text(); let start = text.line_to_char(line_num); let end = text.line_to_char((line_num + 1).min(text.len_lines())); @@ -2000,7 +2018,6 @@ fn append_mode(cx: &mut Context) { pub mod cmd { use super::*; - use std::collections::HashMap; use helix_view::editor::Action; use ui::completers::{self, Completer}; @@ -2680,6 +2697,58 @@ pub mod cmd { Ok(()) } + fn debug_eval( + cx: &mut compositor::Context, + args: &[Cow<str>], + _event: PromptEvent, + ) -> anyhow::Result<()> { + if let Some(debugger) = cx.editor.debugger.as_mut() { + let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) { + (Some(frame), Some(thread_id)) => (frame, thread_id), + _ => { + bail!("Cannot find current stack frame to access variables") + } + }; + + // TODO: support no frame_id + + let frame_id = debugger.stack_frames[&thread_id][frame].id; + let response = block_on(debugger.eval(args.join(" "), Some(frame_id)))?; + cx.editor.set_status(response.result); + } + Ok(()) + } + + fn debug_start( + cx: &mut compositor::Context, + args: &[Cow<str>], + _event: PromptEvent, + ) -> anyhow::Result<()> { + let mut args = args.to_owned(); + let name = match args.len() { + 0 => None, + _ => Some(args.remove(0)), + }; + dap_start_impl(cx, name.as_deref(), None, Some(args)) + } + + fn debug_remote( + cx: &mut compositor::Context, + args: &[Cow<str>], + _event: PromptEvent, + ) -> anyhow::Result<()> { + let mut args = args.to_owned(); + let address = match args.len() { + 0 => None, + _ => Some(args.remove(0).parse()?), + }; + let name = match args.len() { + 0 => None, + _ => Some(args.remove(0)), + }; + dap_start_impl(cx, name.as_deref(), address, Some(args)) + } + fn tutor( cx: &mut compositor::Context, _args: &[Cow<str>], @@ -3095,6 +3164,27 @@ pub mod cmd { completer: None, }, TypableCommand { + name: "debug-start", + aliases: &["dbg"], + doc: "Start a debug session from a given template with given parameters.", + fun: debug_start, + completer: None, + }, + TypableCommand { + name: "debug-remote", + aliases: &["dbg-tcp"], + doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.", + fun: debug_remote, + completer: None, + }, + TypableCommand { + name: "debug-eval", + aliases: &[], + doc: "Evaluate expression in current debug context.", + fun: debug_eval, + completer: None, + }, + TypableCommand { name: "vsplit", aliases: &["vs"], doc: "Open the file in a vertical split.", @@ -3325,8 +3415,8 @@ fn buffer_picker(cx: &mut Context) { .map(|(_, doc)| new_meta(doc)) .collect(), BufferMeta::format, - |editor: &mut Editor, meta, action| { - editor.switch(meta.id, action); + |cx, meta, action| { + cx.editor.switch(meta.id, action); }, |editor, meta| { let doc = &editor.documents.get(&meta.id)?; @@ -3393,9 +3483,9 @@ fn symbol_picker(cx: &mut Context) { let mut picker = FilePicker::new( symbols, |symbol| (&symbol.name).into(), - move |editor: &mut Editor, symbol, _action| { - push_jump(editor); - let (view, doc) = current!(editor); + move |cx, symbol, _action| { + push_jump(cx.editor); + let (view, doc) = current!(cx.editor); if let Some(range) = lsp_range_to_range(doc.text(), symbol.location.range, offset_encoding) @@ -3452,10 +3542,10 @@ fn workspace_symbol_picker(cx: &mut Context) { format!("{} ({})", &symbol.name, relative_path).into() } }, - move |editor: &mut Editor, symbol, action| { + move |cx, symbol, action| { let path = symbol.location.uri.to_file_path().unwrap(); - editor.open(path, action).expect("editor.open failed"); - let (view, doc) = current!(editor); + cx.editor.open(path, action).expect("editor.open failed"); + let (view, doc) = current!(cx.editor); if let Some(range) = lsp_range_to_range(doc.text(), symbol.location.range, offset_encoding) @@ -4127,9 +4217,7 @@ fn goto_impl( let line = location.range.start.line; format!("{}:{}", file, line).into() }, - move |editor: &mut Editor, location, action| { - jump_to(editor, location, offset_encoding, action) - }, + move |cx, location, action| jump_to(cx.editor, location, offset_encoding, action), |_editor, location| { let path = location.uri.to_file_path().unwrap(); let line = Some(( |