on master help sign in
refactor: handle DAP events in editor main loop
commita938f5a87a2b67dd8667337cd569cc6627d0f666 authorDmitry Sharshakov <d3dx12.xx@gmail.com> dateSat 21 Aug 2021, 17:21 (5 years ago) parent3fc501c
7 files changed+65−98
Cargo.lock+1 helix-dap/src/client.rs+24−50 helix-term/Cargo.toml+1−1 helix-term/src/application.rs+24 helix-term/src/commands.rs+6−30 helix-term/src/ui/editor.rs+6−13 helix-view/src/editor.rs+3−4
Cargo.lock+1
@@ -389,6 +389,7 @@ dependencies = [
389389 "signal-hook",
390390 "signal-hook-tokio",
391391 "tokio",
392+ "tokio-stream",
392393 "toml",
393394]
394395
helix-dap/src/client.rs+24−50
@@ -1,5 +1,5 @@
11use crate::{
2− transport::{Event, Payload, Request, Transport},
2+ transport::{Payload, Request, Transport},
33 types::*,
44 Result,
55};
@@ -9,19 +9,13 @@ use std::{
99 net::{IpAddr, Ipv4Addr, SocketAddr},
1010 path::PathBuf,
1111 process::Stdio,
12− sync::{
13− atomic::{AtomicU64, Ordering},
14− Arc,
15− },
12+ sync::atomic::{AtomicU64, Ordering},
1613};
1714use tokio::{
1815 io::{AsyncBufRead, AsyncWrite, BufReader, BufWriter},
1916 net::TcpStream,
2017 process::{Child, Command},
21− sync::{
22− mpsc::{channel, Receiver, Sender, UnboundedReceiver, UnboundedSender},
23− Mutex,
24− },
18+ sync::mpsc::{channel, unbounded_channel, UnboundedReceiver, UnboundedSender},
2519 time,
2620};
2721
@@ -32,8 +26,6 @@ pub struct Client {
3226 server_tx: UnboundedSender<Request>,
3327 request_counter: AtomicU64,
3428 capabilities: Option<DebuggerCapabilities>,
35− awaited_events: Arc<Mutex<HashMap<String, Sender<Event>>>>,
36−
3729 //
3830 pub breakpoints: HashMap<PathBuf, Vec<SourceBreakpoint>>,
3931 // TODO: multiple threads support
@@ -46,8 +38,9 @@ impl Client {
4638 tx: Box<dyn AsyncWrite + Unpin + Send>,
4739 id: usize,
4840 process: Option<Child>,
49− ) -> Result<Self> {
41+ ) -> Result<(Self, UnboundedReceiver<Payload>)> {
5042 let (server_rx, server_tx) = Transport::start(rx, tx, id);
43+ let (client_rx, client_tx) = unbounded_channel();
5144
5245 let client = Self {
5346 id,
@@ -55,24 +48,30 @@ impl Client {
5548 server_tx,
5649 request_counter: AtomicU64::new(0),
5750 capabilities: None,
58− awaited_events: Arc::new(Mutex::new(HashMap::default())),
5951 //
6052 breakpoints: HashMap::new(),
6153 stack_pointer: None,
6254 };
6355
64− tokio::spawn(Self::recv(Arc::clone(&client.awaited_events), server_rx));
56+ tokio::spawn(Self::recv(server_rx, client_rx));
6557
66− Ok(client)
58+ Ok((client, client_tx))
6759 }
6860
69− pub async fn tcp(addr: std::net::SocketAddr, id: usize) -> Result<Self> {
61+ pub async fn tcp(
62+ addr: std::net::SocketAddr,
63+ id: usize,
64+ ) -> Result<(Self, UnboundedReceiver<Payload>)> {
7065 let stream = TcpStream::connect(addr).await?;
7166 let (rx, tx) = stream.into_split();
7267 Self::streams(Box::new(BufReader::new(rx)), Box::new(tx), id, None)
7368 }
7469
75− pub fn stdio(cmd: &str, args: Vec<&str>, id: usize) -> Result<Self> {
70+ pub fn stdio(
71+ cmd: &str,
72+ args: Vec<&str>,
73+ id: usize,
74+ ) -> Result<(Self, UnboundedReceiver<Payload>)> {
7675 let process = Command::new(cmd)
7776 .args(args)
7877 .stdin(Stdio::piped())
@@ -114,7 +113,7 @@ impl Client {
114113 args: Vec<&str>,
115114 port_format: &str,
116115 id: usize,
117− ) -> Result<Self> {
116+ ) -> Result<(Self, UnboundedReceiver<Payload>)> {
118117 let port = Self::get_port().await.unwrap();
119118
120119 let process = Command::new(cmd)
@@ -145,43 +144,22 @@ impl Client {
145144 )
146145 }
147146
148− async fn recv(
149− awaited_events: Arc<Mutex<HashMap<String, Sender<Event>>>>,
150− mut server_rx: UnboundedReceiver<Payload>,
151− ) {
147+ async fn recv(mut server_rx: UnboundedReceiver<Payload>, client_tx: UnboundedSender<Payload>) {
152148 while let Some(msg) = server_rx.recv().await {
153149 match msg {
154150 Payload::Event(ev) => {
155− let name = ev.event.clone();
156− let hashmap = awaited_events.lock().await;
157− let tx = hashmap.get(&name);
158−
159− match tx {
160− Some(tx) => match tx.send(ev).await {
161− Ok(_) => (),
162− Err(_) => error!(
163− "Tried sending event into a closed channel (name={:?})",
164− name
165− ),
166− },
167− None => {
168− info!("unhandled event {}", name);
169− // client_tx.send(Payload::Event(ev)).expect("Failed to send");
170− }
171− }
151+ client_tx.send(Payload::Event(ev)).expect("Failed to send");
172152 }
173153 Payload::Response(_) => unreachable!(),
174− Payload::Request(_) => todo!(),
154+ Payload::Request(req) => {
155+ client_tx
156+ .send(Payload::Request(req))
157+ .expect("Failed to send");
158+ }
175159 }
176160 }
177161 }
178162
179− pub async fn listen_for_event(&self, name: String) -> Receiver<Event> {
180− let (rx, tx) = channel(1);
181− self.awaited_events.lock().await.insert(name.clone(), rx);
182− tx
183− }
184−
185163 pub fn id(&self) -> usize {
186164 self.id
187165 }
@@ -248,8 +226,6 @@ impl Client {
248226 }
249227
250228 pub async fn launch(&mut self, args: serde_json::Value) -> Result<()> {
251− // TODO: buffer these until initialized arrives
252−
253229 let response = self.request::<requests::Launch>(args).await?;
254230 log::error!("launch response {}", response);
255231
@@ -257,8 +233,6 @@ impl Client {
257233 }
258234
259235 pub async fn attach(&mut self, args: serde_json::Value) -> Result<()> {
260− // TODO: buffer these until initialized arrives
261−
262236 let response = self.request::<requests::Attach>(args).await?;
263237 log::error!("attach response {}", response);
264238
helix-term/Cargo.toml+1−1
@@ -34,7 +34,7 @@ num_cpus = "1"
3434tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] }
3535crossterm = { version = "0.20", features = ["event-stream"] }
3636signal-hook = "0.3"
37−
37+tokio-stream = "0.1"
3838futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
3939
4040# Logging
helix-term/src/application.rs+24
@@ -1,4 +1,5 @@
11use helix_core::syntax;
2+use helix_dap::Payload;
23use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
34use helix_view::{theme, Editor};
45
@@ -184,6 +185,29 @@ impl Application {
184185 last_render = Instant::now();
185186 }
186187 }
188+ Some(payload) = self.editor.debugger_events.next() => {
189+ let mut debugger = self.editor.debugger.as_mut().unwrap();
190+ match payload {
191+ Payload::Event(ev) => {
192+ match &ev.event[..] {
193+ "stopped" => {
194+ let main = debugger
195+ .threads()
196+ .await
197+ .ok()
198+ .and_then(|threads| threads.get(0).cloned());
199+ if let Some(main) = main {
200+ let (bt, _) = debugger.stack_trace(main.id).await.unwrap();
201+ debugger.stack_pointer = bt.get(0).cloned();
202+ }
203+ }
204+ _ => {}
205+ }
206+ },
207+ Payload::Response(_) => unreachable!(),
208+ Payload::Request(_) => todo!(),
209+ }
210+ }
187211 Some(callback) = self.jobs.futures.next() => {
188212 self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback);
189213 self.render();
helix-term/src/commands.rs+6−30
@@ -24,17 +24,17 @@ use helix_lsp::{
2424};
2525use insert::*;
2626use movement::Movement;
27−use tokio::sync::{mpsc::Receiver, Mutex};
2827
2928use crate::{
3029 compositor::{self, Component, Compositor},
3130 ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent},
3231};
32+use tokio_stream::wrappers::UnboundedReceiverStream;
3333
3434use crate::job::{self, Job, Jobs};
3535use futures_util::FutureExt;
36+use std::num::NonZeroUsize;
3637use std::{collections::HashMap, fmt, future::Future};
37−use std::{num::NonZeroUsize, sync::Arc};
3838
3939use std::{
4040 borrow::Cow,
@@ -4255,8 +4255,8 @@ fn dap_start(cx: &mut Context) {
42554255 // look up config for filetype
42564256 // if multiple available, open picker
42574257
4258− let debugger = Client::tcp_process("dlv", vec!["dap"], "-l 127.0.0.1:{}", 0);
4259− let mut debugger = block_on(debugger).unwrap();
4258+ let started = Client::tcp_process("dlv", vec!["dap"], "-l 127.0.0.1:{}", 0);
4259+ let (mut debugger, events) = block_on(started).unwrap();
42604260
42614261 let request = debugger.initialize("go".to_owned());
42624262 let _ = block_on(request).unwrap();
@@ -4268,32 +4268,10 @@ fn dap_start(cx: &mut Context) {
42684268 let request = debugger.launch(to_value(args).unwrap());
42694269 let _ = block_on(request).unwrap();
42704270
4271− let stopped = block_on(debugger.listen_for_event("stopped".to_owned()));
4272− let debugger = Arc::new(Mutex::new(debugger));
4273− tokio::spawn(dap_listen_stopped(stopped, Arc::clone(&debugger)));
4274−
42754271 // TODO: either await "initialized" or buffer commands until event is received
42764272 cx.editor.debugger = Some(debugger);
4277−}
4278−
4279−async fn dap_listen_stopped(
4280− mut stopped: Receiver<helix_dap::Event>,
4281− debugger: Arc<Mutex<helix_dap::Client>>,
4282−) {
4283− loop {
4284− stopped.recv().await;
4285−
4286− let mut dbg = debugger.lock().await;
4287− let main = dbg
4288− .threads()
4289− .await
4290− .ok()
4291− .and_then(|threads| threads.get(0).cloned());
4292− if let Some(main) = main {
4293− let (a, _) = dbg.stack_trace(main.id).await.unwrap();
4294− dbg.stack_pointer = a.get(0).cloned();
4295− }
4296− }
4273+ let stream = UnboundedReceiverStream::new(events);
4274+ cx.editor.debugger_events.push(stream);
42974275}
42984276
42994277fn dap_toggle_breakpoint(cx: &mut Context) {
@@ -4321,7 +4299,6 @@ fn dap_toggle_breakpoint(cx: &mut Context) {
43214299 // we shouldn't really allow editing while debug is running though
43224300
43234301 if let Some(debugger) = &mut cx.editor.debugger {
4324− let mut debugger = block_on(debugger.lock());
43254302 let breakpoints = debugger.breakpoints.entry(path.clone()).or_default();
43264303 if let Some(pos) = breakpoints.iter().position(|b| b.line == breakpoint.line) {
43274304 breakpoints.remove(pos);
@@ -4340,7 +4317,6 @@ fn dap_run(cx: &mut Context) {
43404317 use helix_lsp::block_on;
43414318
43424319 if let Some(debugger) = &mut cx.editor.debugger {
4343− let mut debugger = block_on(debugger.lock());
43444320 let request = debugger.configuration_done();
43454321 let _ = block_on(request).unwrap();
43464322 }
helix-term/src/ui/editor.rs+6−13
@@ -25,8 +25,7 @@ use helix_view::{
2525 keyboard::{KeyCode, KeyModifiers},
2626 Document, Editor, Theme, View,
2727};
28−use std::{borrow::Cow, sync::Arc};
29−use tokio::sync::Mutex;
28+use std::borrow::Cow;
3029
3130use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind};
3231use tui::buffer::Buffer as Surface;
@@ -73,7 +72,7 @@ impl EditorView {
7372 is_focused: bool,
7473 loader: &syntax::Loader,
7574 config: &helix_view::editor::Config,
76− debugger: Option<Arc<Mutex<helix_dap::Client>>>,
75+ debugger: &Option<helix_dap::Client>,
7776 ) {
7877 let inner = view.inner_area();
7978 let area = view.area;
@@ -414,9 +413,8 @@ impl EditorView {
414413 theme: &Theme,
415414 is_focused: bool,
416415 config: &helix_view::editor::Config,
417− debugger: Option<Arc<Mutex<helix_dap::Client>>>,
416+ debugger: &Option<helix_dap::Client>,
418417 ) {
419− use helix_lsp::block_on;
420418 let text = doc.text().slice(..);
421419 let last_line = view.last_line(doc);
422420
@@ -449,9 +447,8 @@ impl EditorView {
449447 let mut stack_pointer: Option<StackFrame> = None;
450448 if let Some(debugger) = debugger {
451449 if let Some(path) = doc.path() {
452− let dbg = block_on(debugger.lock());
453− breakpoints = dbg.breakpoints.get(path).cloned();
454− stack_pointer = dbg.stack_pointer.clone()
450+ breakpoints = debugger.breakpoints.get(path).cloned();
451+ stack_pointer = debugger.stack_pointer.clone()
455452 }
456453 }
457454
@@ -1047,10 +1044,6 @@ impl Component for EditorView {
10471044 for (view, is_focused) in cx.editor.tree.views() {
10481045 let doc = cx.editor.document(view.doc).unwrap();
10491046 let loader = &cx.editor.syn_loader;
1050− let mut dbg: Option<Arc<Mutex<helix_dap::Client>>> = None;
1051− if let Some(debugger) = &cx.editor.debugger {
1052− dbg = Some(Arc::clone(debugger));
1053− }
10541047 self.render_view(
10551048 doc,
10561049 view,
@@ -1060,7 +1053,7 @@ impl Component for EditorView {
10601053 is_focused,
10611054 loader,
10621055 &cx.editor.config,
1063− dbg,
1056+ &cx.editor.debugger,
10641057 );
10651058 }
10661059
helix-view/src/editor.rs+3−4
@@ -8,7 +8,6 @@ use crate::{
88
99use futures_util::future;
1010use futures_util::stream::select_all::SelectAll;
11−use tokio::sync::Mutex;
1211use tokio_stream::wrappers::UnboundedReceiverStream;
1312
1413use std::{
@@ -75,8 +74,8 @@ pub struct Editor {
7574 pub theme: Theme,
7675 pub language_servers: helix_lsp::Registry,
7776
78− pub debugger: Option<Arc<Mutex<helix_dap::Client>>>,
79− pub debuggers: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>,
77+ pub debugger: Option<helix_dap::Client>,
78+ pub debugger_events: SelectAll<UnboundedReceiverStream<helix_dap::Payload>>,
8079
8180 pub clipboard_provider: Box<dyn ClipboardProvider>,
8281
@@ -116,7 +115,7 @@ impl Editor {
116115 theme: themes.default(),
117116 language_servers,
118117 debugger: None,
119− debuggers: SelectAll::new(),
118+ debugger_events: SelectAll::new(),
120119 syn_loader: config_loader,
121120 theme_loader: themes,
122121 registers: Registers::default(),