From 73414962b156c5cf008d450a6fb5282e8693364c Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Tue, 31 Oct 2023 21:04:35 +0000 Subject: [PATCH] pty read should retry until it's empty --- lapce-app/src/db.rs | 4 ++ lapce-app/src/file_explorer/data.rs | 5 +- lapce-proxy/src/dispatch.rs | 16 ++--- lapce-proxy/src/terminal.rs | 92 +++++++++++++++++++---------- 4 files changed, 78 insertions(+), 39 deletions(-) diff --git a/lapce-app/src/db.rs b/lapce-app/src/db.rs index 2bb288f8..f5be2b20 100644 --- a/lapce-app/src/db.rs +++ b/lapce-app/src/db.rs @@ -275,6 +275,10 @@ pub fn insert_app_info(&self, info: AppInfo) -> Result<()> { pub fn insert_app(&self, data: AppData) -> Result<()> { let windows = data.windows.get_untracked(); + if windows.is_empty() { + // insert_app is called after window is closed, so we don't want to store it + return Ok(()); + } for (_, window) in &windows { let _ = self.insert_window(window.clone()); } diff --git a/lapce-app/src/file_explorer/data.rs b/lapce-app/src/file_explorer/data.rs index 5acf2f23..9f43fad7 100644 --- a/lapce-app/src/file_explorer/data.rs +++ b/lapce-app/src/file_explorer/data.rs @@ -35,7 +35,10 @@ pub fn new(cx: Scope, common: Rc) -> Self { root, common, }; - data.toggle_expand(&path); + if data.common.workspace.path.is_some() { + // only fill in the child files if there is open folder + data.toggle_expand(&path); + } data } diff --git a/lapce-proxy/src/dispatch.rs b/lapce-proxy/src/dispatch.rs index 8461343a..1c27d7c9 100644 --- a/lapce-proxy/src/dispatch.rs +++ b/lapce-proxy/src/dispatch.rs @@ -37,7 +37,7 @@ use crate::{ buffer::{get_mod_time, load_file, Buffer}, plugin::{catalog::PluginCatalog, remove_volt, PluginCatalogRpcHandler}, - terminal::Terminal, + terminal::{Terminal, TerminalSender}, watcher::{FileWatcher, Notify, WatchToken}, }; @@ -50,7 +50,7 @@ pub struct Dispatcher { core_rpc: CoreRpcHandler, catalog_rpc: PluginCatalogRpcHandler, buffers: HashMap, - terminals: HashMap>, + terminals: HashMap, file_watcher: FileWatcher, window_id: usize, tab_id: usize, @@ -135,7 +135,7 @@ fn handle_notification(&mut self, rpc: ProxyNotification) { Shutdown {} => { self.catalog_rpc.shutdown(); for (_, sender) in self.terminals.iter() { - let _ = sender.send(Msg::Shutdown); + sender.send(Msg::Shutdown); } self.proxy_rpc.shutdown(); } @@ -177,7 +177,9 @@ fn handle_notification(&mut self, rpc: ProxyNotification) { self.core_rpc.terminal_process_id(term_id, child_id); let tx = terminal.tx.clone(); - self.terminals.insert(term_id, tx); + let poller = terminal.poller.clone(); + let sender = TerminalSender::new(tx, poller); + self.terminals.insert(term_id, sender); let rpc = self.core_rpc.clone(); thread::spawn(move || { terminal.run(rpc); @@ -185,7 +187,7 @@ fn handle_notification(&mut self, rpc: ProxyNotification) { } TerminalWrite { term_id, content } => { if let Some(tx) = self.terminals.get(&term_id) { - let _ = tx.send(Msg::Input(content.into_bytes().into())); + tx.send(Msg::Input(content.into_bytes().into())); } } TerminalResize { @@ -201,12 +203,12 @@ fn handle_notification(&mut self, rpc: ProxyNotification) { cell_height: 1, }; - let _ = tx.send(Msg::Resize(size)); + tx.send(Msg::Resize(size)); } } TerminalClose { term_id } => { if let Some(tx) = self.terminals.remove(&term_id) { - let _ = tx.send(Msg::Shutdown); + tx.send(Msg::Shutdown); } } DapStart { diff --git a/lapce-proxy/src/terminal.rs b/lapce-proxy/src/terminal.rs index f96e1095..12a2d165 100644 --- a/lapce-proxy/src/terminal.rs +++ b/lapce-proxy/src/terminal.rs @@ -36,9 +36,25 @@ pub type TermConfig = alacritty_terminal::config::Config; +pub struct TerminalSender { + tx: Sender, + poller: Arc, +} + +impl TerminalSender { + pub fn new(tx: Sender, poller: Arc) -> Self { + Self { tx, poller } + } + + pub fn send(&self, msg: Msg) { + let _ = self.tx.send(msg); + let _ = self.poller.notify(); + } +} + pub struct Terminal { term_id: TermId, - poll: Arc, + pub(crate) poller: Arc, pub(crate) pty: alacritty_terminal::tty::Pty, rx: Receiver, pub tx: Sender, @@ -78,7 +94,7 @@ pub fn new( Ok(Terminal { term_id, - poll, + poller: poll, pty, tx, rx, @@ -94,7 +110,9 @@ pub fn run(&mut self, core_rpc: CoreRpcHandler) { // Register TTY through EventedRW interface. unsafe { - self.pty.register(&self.poll, interest, poll_opts).unwrap(); + self.pty + .register(&self.poller, interest, poll_opts) + .unwrap(); } let mut events = @@ -102,10 +120,7 @@ pub fn run(&mut self, core_rpc: CoreRpcHandler) { 'event_loop: loop { events.clear(); - if let Err(err) = self - .poll - .wait(&mut events, Some(std::time::Duration::from_millis(16))) - { + if let Err(err) = self.poller.wait(&mut events, None) { match err.kind() { ErrorKind::Interrupted => continue, _ => panic!("EventLoop polling error: {err:?}"), @@ -134,30 +149,22 @@ pub fn run(&mut self, core_rpc: CoreRpcHandler) { } if event.readable { - match self.pty.reader().read(&mut buf) { - Ok(n) => { - core_rpc.update_terminal( - self.term_id, - buf[..n].to_vec(), - ); + if let Err(err) = self.pty_read(&core_rpc, &mut buf) { + // On Linux, a `read` on the master side of a PTY can fail + // with `EIO` if the client side hangs up. In that case, + // just loop back round for the inevitable `Exited` event. + // This sucks, but checking the process is either racy or + // blocking. + #[cfg(target_os = "linux")] + if err.raw_os_error() == Some(libc::EIO) { + continue; } - Err(err) => { - // On Linux, a `read` on the master side of a PTY can fail - // with `EIO` if the client side hangs up. In that case, - // just loop back round for the inevitable `Exited` event. - // This sucks, but checking the process is either racy or - // blocking. - #[cfg(target_os = "linux")] - if err.raw_os_error() == Some(libc::EIO) { - continue; - } - tracing::error!( - "Error reading from PTY in event loop: {}", - err - ); - break 'event_loop; - } + tracing::error!( + "Error reading from PTY in event loop: {}", + err + ); + break 'event_loop; } } @@ -182,12 +189,12 @@ pub fn run(&mut self, core_rpc: CoreRpcHandler) { // Re-register with new interest. self.pty - .reregister(&self.poll, interest, poll_opts) + .reregister(&self.poller, interest, poll_opts) .unwrap(); } } core_rpc.terminal_process_stopped(self.term_id); - let _ = self.pty.deregister(&self.poll); + let _ = self.pty.deregister(&self.poller); } /// Drain the channel. @@ -205,6 +212,29 @@ fn drain_recv_channel(&mut self, state: &mut State) -> bool { true } + #[inline] + fn pty_read( + &mut self, + core_rpc: &CoreRpcHandler, + buf: &mut [u8], + ) -> io::Result<()> { + loop { + match self.pty.reader().read(buf) { + Ok(0) => break, + Ok(n) => { + core_rpc.update_terminal(self.term_id, buf[..n].to_vec()); + } + Err(err) => match err.kind() { + ErrorKind::Interrupted | ErrorKind::WouldBlock => { + break; + } + _ => return Err(err), + }, + } + } + Ok(()) + } + #[inline] fn pty_write(&mut self, state: &mut State) -> io::Result<()> { state.ensure_next();