on master help sign in
Start integrating into the editor's event loop
d39baa3Blaž Hrastnik
Cargo.lock+4−1
@@ -324,7 +324,7 @@ dependencies = [
324
324
325[[package]]
325[[package]]
326name = "helix-dap"
326name = "helix-dap"
327−version = "0.3.0"
327+version = "0.4.0"
328dependencies = [
328dependencies = [
329 "anyhow",
329 "anyhow",
330 "fern",
330 "fern",
@@ -375,6 +375,7 @@ dependencies = [
375 "futures-util",
375 "futures-util",
376 "fuzzy-matcher",
376 "fuzzy-matcher",
377 "helix-core",
377 "helix-core",
378+ "helix-dap",
378 "helix-lsp",
379 "helix-lsp",
379 "helix-tui",
380 "helix-tui",
380 "helix-view",
381 "helix-view",
@@ -416,6 +417,7 @@ dependencies = [
416 "encoding_rs",
417 "encoding_rs",
417 "futures-util",
418 "futures-util",
418 "helix-core",
419 "helix-core",
420+ "helix-dap",
419 "helix-lsp",
421 "helix-lsp",
420 "helix-tui",
422 "helix-tui",
421 "log",
423 "log",
@@ -423,6 +425,7 @@ dependencies = [
423 "serde",
425 "serde",
424 "slotmap",
426 "slotmap",
425 "tokio",
427 "tokio",
428+ "tokio-stream",
426 "toml",
429 "toml",
427 "url",
430 "url",
428 "which",
431 "which",
helix-dap/Cargo.toml+1−1
@@ -1,6 +1,6 @@
1[package]
1[package]
2name = "helix-dap"
2name = "helix-dap"
3−version = "0.3.0"
3+version = "0.4.0"
4authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
4authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5edition = "2018"
5edition = "2018"
6license = "MPL-2.0"
6license = "MPL-2.0"
helix-dap/src/client.rs+10−12
@@ -186,12 +186,12 @@ impl Client {
186 &self,
186 &self,
187 arguments: R::Arguments,
187 arguments: R::Arguments,
188 ) -> Result<R::Result> {
188 ) -> Result<R::Result> {
189− let (callback_rx, mut callback_tx) = channel(1);
189+ let (callback_tx, mut callback_rx) = channel(1);
190
190
191 let arguments = Some(serde_json::to_value(arguments)?);
191 let arguments = Some(serde_json::to_value(arguments)?);
192
192
193 let req = Request {
193 let req = Request {
194− back_ch: Some(callback_rx),
194+ back_ch: Some(callback_tx),
195 seq: self.next_request_id(),
195 seq: self.next_request_id(),
196 command: R::COMMAND.to_string(),
196 command: R::COMMAND.to_string(),
197 arguments,
197 arguments,
@@ -201,7 +201,7 @@ impl Client {
201 .send(req)
201 .send(req)
202 .expect("Failed to send request to debugger");
202 .expect("Failed to send request to debugger");
203
203
204− let response = callback_tx.recv().await.unwrap()?;
204+ let response = callback_rx.recv().await.unwrap()?;
205 let response = serde_json::from_value(response.body.unwrap_or_default())?;
205 let response = serde_json::from_value(response.body.unwrap_or_default())?;
206 Ok(response)
206 Ok(response)
207 }
207 }
@@ -209,7 +209,7 @@ impl Client {
209 pub fn capabilities(&self) -> &DebuggerCapabilities {
209 pub fn capabilities(&self) -> &DebuggerCapabilities {
210 self.capabilities
210 self.capabilities
211 .as_ref()
211 .as_ref()
212− .expect("language server not yet initialized!")
212+ .expect("debugger not yet initialized!")
213 }
213 }
214
214
215 pub async fn initialize(&mut self, adapter_id: String) -> Result<()> {
215 pub async fn initialize(&mut self, adapter_id: String) -> Result<()> {
@@ -240,21 +240,19 @@ impl Client {
240 }
240 }
241
241
242 pub async fn launch(&mut self, args: serde_json::Value) -> Result<()> {
242 pub async fn launch(&mut self, args: serde_json::Value) -> Result<()> {
243− let mut initialized = self.listen_for_event("initialized".to_owned()).await;
243+ // TODO: buffer these until initialized arrives
244
244
245− let res = self.request::<requests::Launch>(args);
245+ let response = self.request::<requests::Launch>(args).await?;
246− let ev = initialized.recv();
246+ log::error!("launch response {}", response);
247− join!(res, ev).0?;
248
247
249 Ok(())
248 Ok(())
250 }
249 }
251
250
252 pub async fn attach(&mut self, args: serde_json::Value) -> Result<()> {
251 pub async fn attach(&mut self, args: serde_json::Value) -> Result<()> {
253− let mut initialized = self.listen_for_event("initialized".to_owned()).await;
252+ // TODO: buffer these until initialized arrives
254
253
255− let res = self.request::<requests::Attach>(args);
254+ let response = self.request::<requests::Attach>(args).await?;
256− let ev = initialized.recv();
255+ log::error!("attach response {}", response);
257− join!(res, ev).0?;
258
256
259 Ok(())
257 Ok(())
260 }
258 }
helix-dap/src/transport.rs+9−12
@@ -159,20 +159,17 @@ impl Transport {
159 }
159 }
160
160
161 fn process_response(res: Response) -> Result<Response> {
161 fn process_response(res: Response) -> Result<Response> {
162− match res.success {
162+ if res.success {
163− true => {
164− info!("<- DAP success in response to {}", res.request_seq);
163+ info!("<- DAP success in response to {}", res.request_seq);
165
164
166− Ok(res)
165+ Ok(res)
167− }
166+ } else {
168− false => {
169− error!(
167+ error!(
170− "<- DAP error {:?} ({:?}) for command #{} {}",
168+ "<- DAP error {:?} ({:?}) for command #{} {}",
171− res.message, res.body, res.request_seq, res.command
169+ res.message, res.body, res.request_seq, res.command
172− );
170+ );
173
171
174− Err(Error::Other(anyhow::format_err!("{:?}", res.body)))
172+ Err(Error::Other(anyhow::format_err!("{:?}", res.body)))
175− }
176 }
173 }
177 }
174 }
178
175
helix-lsp/Cargo.toml+1−1
@@ -24,4 +24,4 @@ serde = { version = "1.0", features = ["derive"] }
24serde_json = "1.0"
24serde_json = "1.0"
25thiserror = "1.0"
25thiserror = "1.0"
26tokio = { version = "1.9", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
26tokio = { version = "1.9", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
27−tokio-stream = "0.1.7"
27+tokio-stream = "0.1"
helix-term/Cargo.toml+1
@@ -24,6 +24,7 @@ path = "src/main.rs"
24helix-core = { version = "0.4", path = "../helix-core" }
24helix-core = { version = "0.4", path = "../helix-core" }
25helix-view = { version = "0.4", path = "../helix-view" }
25helix-view = { version = "0.4", path = "../helix-view" }
26helix-lsp = { version = "0.4", path = "../helix-lsp" }
26helix-lsp = { version = "0.4", path = "../helix-lsp" }
27+helix-dap = { version = "0.4", path = "../helix-dap" }
27
28
28anyhow = "1"
29anyhow = "1"
29once_cell = "1.8"
30once_cell = "1.8"
helix-term/src/application.rs+9
@@ -245,6 +245,15 @@ impl Application {
245 }
245 }
246 }
246 }
247
247
248+ pub async fn handle_debugger_message(
249+ &mut self,
250+ call: (),
251+ server_id: usize,
252+ ) {
253+
254+ //
255+ }
256+
248 pub async fn handle_language_server_message(
257 pub async fn handle_language_server_message(
249 &mut self,
258 &mut self,
250 call: helix_lsp::Call,
259 call: helix_lsp::Call,
helix-term/src/commands.rs+42
@@ -1900,6 +1900,41 @@ mod cmd {
1900 Ok(())
1900 Ok(())
1901 }
1901 }
1902
1902
1903+ fn debug(
1904+ cx: &mut compositor::Context,
1905+ _args: &[&str],
1906+ _event: PromptEvent,
1907+ ) -> anyhow::Result<()> {
1908+ use helix_dap::Client;
1909+ use helix_lsp::block_on;
1910+ use serde_json::to_value;
1911+ let (_, doc) = current!(cx.editor);
1912+
1913+ // look up config for filetype
1914+ // if multiple available, open picker
1915+
1916+ log::error!("1");
1917+
1918+ let client = Client::tcp_process("dlv", vec!["dap"], "-l 127.0.0.1:{}", 0);
1919+ let mut client = block_on(client)?;
1920+ log::error!("2");
1921+
1922+ let request = client.initialize("go".to_owned());
1923+ let _ = block_on(request)?;
1924+ log::error!("3");
1925+
1926+ let mut args = HashMap::new();
1927+ args.insert("mode", "debug");
1928+ // args.insert("program", "path/to/program");
1929+
1930+ let request = client.launch(to_value(args)?);
1931+ let _ = block_on(request)?;
1932+
1933+ log::error!("4");
1934+ doc.debugger = Some(client);
1935+ Ok(())
1936+ }
1937+
1903 pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
1938 pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
1904 TypableCommand {
1939 TypableCommand {
1905 name: "quit",
1940 name: "quit",
@@ -2138,6 +2173,13 @@ mod cmd {
2138 doc: "Display tree sitter scopes, primarily for theming and development.",
2173 doc: "Display tree sitter scopes, primarily for theming and development.",
2139 fun: tree_sitter_scopes,
2174 fun: tree_sitter_scopes,
2140 completer: None,
2175 completer: None,
2176+ },
2177+ TypableCommand {
2178+ name: "debug",
2179+ alias: None,
2180+ doc: "Start a debug session.",
2181+ fun: debug,
2182+ completer: None,
2141 }
2183 }
2142 ];
2184 ];
2143
2185
helix-view/Cargo.toml+2
@@ -18,6 +18,7 @@ bitflags = "1.3"
18anyhow = "1"
18anyhow = "1"
19helix-core = { version = "0.4", path = "../helix-core" }
19helix-core = { version = "0.4", path = "../helix-core" }
20helix-lsp = { version = "0.4", path = "../helix-lsp"}
20helix-lsp = { version = "0.4", path = "../helix-lsp"}
21+helix-dap = { version = "0.4", path = "../helix-dap"}
21crossterm = { version = "0.20", optional = true }
22crossterm = { version = "0.20", optional = true }
22
23
23# Conversion traits
24# Conversion traits
@@ -25,6 +26,7 @@ once_cell = "1.8"
25url = "2"
26url = "2"
26
27
27tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
28tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
29+tokio-stream = "0.1"
28futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
30futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
29
31
30slotmap = "1"
32slotmap = "1"
helix-view/src/document.rs+2
@@ -100,6 +100,7 @@ pub struct Document {
100
100
101 diagnostics: Vec<Diagnostic>,
101 diagnostics: Vec<Diagnostic>,
102 language_server: Option<Arc<helix_lsp::Client>>,
102 language_server: Option<Arc<helix_lsp::Client>>,
103+ pub debugger: Option<helix_dap::Client>,
103}
104}
104
105
105use std::fmt;
106use std::fmt;
@@ -425,6 +426,7 @@ impl Document {
425 history: Cell::new(History::default()),
426 history: Cell::new(History::default()),
426 last_saved_revision: 0,
427 last_saved_revision: 0,
427 language_server: None,
428 language_server: None,
429+ debugger: None,
428 line_ending: DEFAULT_LINE_ENDING,
430 line_ending: DEFAULT_LINE_ENDING,
429 }
431 }
430 }
432 }
helix-view/src/editor.rs+5
@@ -7,6 +7,9 @@ use crate::{
7};
7};
8
8
9use futures_util::future;
9use futures_util::future;
10+use futures_util::stream::select_all::SelectAll;
11+use tokio_stream::wrappers::UnboundedReceiverStream;
12+
10use std::{
13use std::{
11 path::{Path, PathBuf},
14 path::{Path, PathBuf},
12 sync::Arc,
15 sync::Arc,
@@ -70,6 +73,7 @@ pub struct Editor {
70 pub registers: Registers,
73 pub registers: Registers,
71 pub theme: Theme,
74 pub theme: Theme,
72 pub language_servers: helix_lsp::Registry,
75 pub language_servers: helix_lsp::Registry,
76+ pub debuggers: SelectAll<UnboundedReceiverStream<(usize, helix_dap::Payload)>>,
73 pub clipboard_provider: Box<dyn ClipboardProvider>,
77 pub clipboard_provider: Box<dyn ClipboardProvider>,
74
78
75 pub syn_loader: Arc<syntax::Loader>,
79 pub syn_loader: Arc<syntax::Loader>,
@@ -107,6 +111,7 @@ impl Editor {
107 selected_register: RegisterSelection::default(),
111 selected_register: RegisterSelection::default(),
108 theme: themes.default(),
112 theme: themes.default(),
109 language_servers,
113 language_servers,
114+ debuggers: SelectAll::new(),
110 syn_loader: config_loader,
115 syn_loader: config_loader,
111 theme_loader: themes,
116 theme_loader: themes,
112 registers: Registers::default(),
117 registers: Registers::default(),