From cc96a6197b936666f9ffb4c65324cf2674ba7d09 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Mon, 7 Dec 2020 13:06:43 +0530 Subject: [PATCH 01/10] Implement ErrorContext for tracking errors across threads --- src/errors.rs | 43 ++++++++++++--- src/input.rs | 80 ++++++++++++++++----------- src/main.rs | 82 ++++++++++++++++++++++------ src/pty_bus.rs | 88 ++++++++++++++++++------------ src/screen.rs | 30 ++++++---- src/terminal_pane/terminal_pane.rs | 2 +- src/utils/logging.rs | 2 +- 7 files changed, 220 insertions(+), 107 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 437db0dd79..5d6dc730c8 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,10 +1,13 @@ -use crate::AppInstruction; +use crate::{AppInstruction, OPENCALLS}; use backtrace::Backtrace; use std::panic::PanicInfo; use std::sync::mpsc::SyncSender; use std::{process, thread}; -pub fn handle_panic(info: &PanicInfo<'_>, send_app_instructions: &SyncSender) { +pub fn handle_panic( + info: &PanicInfo<'_>, + send_app_instructions: &SyncSender<(ErrorContext, AppInstruction)>, +) { let backtrace = Backtrace::new(); let thread = thread::current(); let thread = thread.name().unwrap_or("unnamed"); @@ -14,35 +17,59 @@ pub fn handle_panic(info: &PanicInfo<'_>, send_app_instructions: &SyncSender info.payload().downcast_ref::().map(|s| &**s), }; + let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let backtrace = match (info.location(), msg) { (Some(location), Some(msg)) => format!( - "\nthread '{}' panicked at '{}': {}:{}\n{:?}", + "thread '{}' panicked at '{}': {}:{}\n{:#?}\n{:?}", thread, msg, location.file(), location.line(), + err_ctx, backtrace ), (Some(location), None) => format!( - "\nthread '{}' panicked: {}:{}\n{:?}", + "thread '{}' panicked: {}:{}\n{:#?}\n{:?}", thread, location.file(), location.line(), + err_ctx, backtrace ), (None, Some(msg)) => format!( - "\nthread '{}' panicked at '{}'\n{:?}", - thread, msg, backtrace + "thread '{}' panicked at '{}'\n{:#?}\n{:?}", + thread, msg, err_ctx, backtrace + ), + (None, None) => format!( + "thread '{}' panicked\n{:#?}\n{:?}", + thread, err_ctx, backtrace ), - (None, None) => format!("\nthread '{}' panicked\n{:?}", thread, backtrace), }; if thread == "main" { println!("{}", backtrace); process::exit(1); } else { + err_ctx.add_call("panic_hook(handle_panic)"); send_app_instructions - .send(AppInstruction::Error(backtrace)) + .send((err_ctx, AppInstruction::Error(backtrace))) .unwrap(); } } + +#[derive(Clone, Debug)] +pub struct ErrorContext { + calls: Vec, +} + +impl ErrorContext { + pub fn new() -> Self { + Self { calls: Vec::new() } + } + + pub fn add_call(&mut self, call: &str) { + self.calls.push(call.into()); + OPENCALLS.with(|ctx| *ctx.borrow_mut() = self.clone()); + } +} diff --git a/src/input.rs b/src/input.rs index ea2c4d41ac..5f8f25ef63 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,28 +1,29 @@ /// Module for handling input use std::sync::mpsc::{Sender, SyncSender}; +use crate::errors::ErrorContext; use crate::os_input_output::OsApi; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; -use crate::AppInstruction; use crate::CommandIsExecuting; +use crate::{AppInstruction, OPENCALLS}; struct InputHandler { mode: InputMode, os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender, - send_pty_instructions: Sender, - send_app_instructions: SyncSender, + send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, + send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, + send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, } impl InputHandler { fn new( os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender, - send_pty_instructions: Sender, - send_app_instructions: SyncSender, + send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, + send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, + send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, ) -> Self { InputHandler { mode: InputMode::Normal, @@ -36,6 +37,8 @@ impl InputHandler { /// Main event loop fn get_input(&mut self) { + let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + err_ctx.add_call("stdin_handler(AcceptInput)"); loop { match self.mode { InputMode::Normal => self.read_normal_mode(), @@ -52,6 +55,7 @@ impl InputHandler { /// Read input to the terminal (or switch to command mode) fn read_normal_mode(&mut self) { assert_eq!(self.mode, InputMode::Normal); + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); loop { let stdin_buffer = self.os_input.read_from_stdin(); @@ -63,10 +67,13 @@ impl InputHandler { } _ => { self.send_screen_instructions - .send(ScreenInstruction::ClearScroll) + .send((err_ctx.clone(), ScreenInstruction::ClearScroll)) .unwrap(); self.send_screen_instructions - .send(ScreenInstruction::WriteCharacter(stdin_buffer)) + .send(( + err_ctx.clone(), + ScreenInstruction::WriteCharacter(stdin_buffer), + )) .unwrap(); } } @@ -81,6 +88,7 @@ impl InputHandler { } else { assert_eq!(self.mode, InputMode::Command); } + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); loop { let stdin_buffer = self.os_input.read_from_stdin(); @@ -109,38 +117,38 @@ impl InputHandler { [106] => { // j self.send_screen_instructions - .send(ScreenInstruction::ResizeDown) + .send((err_ctx.clone(), ScreenInstruction::ResizeDown)) .unwrap(); } [107] => { // k self.send_screen_instructions - .send(ScreenInstruction::ResizeUp) + .send((err_ctx.clone(), ScreenInstruction::ResizeUp)) .unwrap(); } [112] => { // p self.send_screen_instructions - .send(ScreenInstruction::MoveFocus) + .send((err_ctx.clone(), ScreenInstruction::MoveFocus)) .unwrap(); } [104] => { // h self.send_screen_instructions - .send(ScreenInstruction::ResizeLeft) + .send((err_ctx.clone(), ScreenInstruction::ResizeLeft)) .unwrap(); } [108] => { // l self.send_screen_instructions - .send(ScreenInstruction::ResizeRight) + .send((err_ctx.clone(), ScreenInstruction::ResizeRight)) .unwrap(); } [122] => { // z self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send(PtyInstruction::SpawnTerminal(None)) + .send((err_ctx.clone(), PtyInstruction::SpawnTerminal(None))) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -148,7 +156,10 @@ impl InputHandler { // n self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send(PtyInstruction::SpawnTerminalVertically(None)) + .send(( + err_ctx.clone(), + PtyInstruction::SpawnTerminalVertically(None), + )) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -156,7 +167,10 @@ impl InputHandler { // b self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send(PtyInstruction::SpawnTerminalHorizontally(None)) + .send(( + err_ctx.clone(), + PtyInstruction::SpawnTerminalHorizontally(None), + )) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -168,51 +182,54 @@ impl InputHandler { [27, 91, 53, 126] => { // PgUp self.send_screen_instructions - .send(ScreenInstruction::ScrollUp) + .send((err_ctx.clone(), ScreenInstruction::ScrollUp)) .unwrap(); } [27, 91, 54, 126] => { // PgDown self.send_screen_instructions - .send(ScreenInstruction::ScrollDown) + .send((err_ctx.clone(), ScreenInstruction::ScrollDown)) .unwrap(); } [120] => { // x self.command_is_executing.closing_pane(); self.send_screen_instructions - .send(ScreenInstruction::CloseFocusedPane) + .send((err_ctx.clone(), ScreenInstruction::CloseFocusedPane)) .unwrap(); self.command_is_executing.wait_until_pane_is_closed(); } [101] => { // e self.send_screen_instructions - .send(ScreenInstruction::ToggleActiveTerminalFullscreen) + .send(( + err_ctx.clone(), + ScreenInstruction::ToggleActiveTerminalFullscreen, + )) .unwrap(); } [121] => { // y self.send_screen_instructions - .send(ScreenInstruction::MoveFocusLeft) + .send((err_ctx.clone(), ScreenInstruction::MoveFocusLeft)) .unwrap() } [117] => { // u self.send_screen_instructions - .send(ScreenInstruction::MoveFocusDown) + .send((err_ctx.clone(), ScreenInstruction::MoveFocusDown)) .unwrap() } [105] => { // i self.send_screen_instructions - .send(ScreenInstruction::MoveFocusUp) + .send((err_ctx.clone(), ScreenInstruction::MoveFocusUp)) .unwrap() } [111] => { // o self.send_screen_instructions - .send(ScreenInstruction::MoveFocusRight) + .send((err_ctx.clone(), ScreenInstruction::MoveFocusRight)) .unwrap() } //@@@khs26 Write this to the powerbar? @@ -229,14 +246,15 @@ impl InputHandler { /// Routine to be called when the input handler exits (at the moment this is the /// same as quitting mosaic) fn exit(&mut self) { + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send(ScreenInstruction::Quit) + .send((err_ctx.clone(), ScreenInstruction::Quit)) .unwrap(); self.send_pty_instructions - .send(PtyInstruction::Quit) + .send((err_ctx.clone(), PtyInstruction::Quit)) .unwrap(); self.send_app_instructions - .send(AppInstruction::Exit) + .send((err_ctx.clone(), AppInstruction::Exit)) .unwrap(); } } @@ -263,9 +281,9 @@ pub enum InputMode { pub fn input_loop( os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender, - send_pty_instructions: Sender, - send_app_instructions: SyncSender, + send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, + send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, + send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, ) { let _handler = InputHandler::new( os_input, diff --git a/src/main.rs b/src/main.rs index 0ad09ed00c..e0df387c32 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ use serde::{Deserialize, Serialize}; use structopt::StructOpt; use crate::command_is_executing::CommandIsExecuting; +use crate::errors::ErrorContext; use crate::input::input_loop; use crate::layout::Layout; use crate::os_input_output::{get_os_input, OsApi}; @@ -31,6 +32,9 @@ use crate::utils::{ consts::{MOSAIC_IPC_PIPE, MOSAIC_TMP_DIR, MOSAIC_TMP_LOG_DIR}, logging::*, }; +use std::cell::RefCell; + +thread_local!(static OPENCALLS: RefCell = RefCell::new(ErrorContext::new())); #[derive(Serialize, Deserialize, Debug)] enum ApiCommand { @@ -107,16 +111,16 @@ pub fn start(mut os_input: Box, opts: Opt) { let full_screen_ws = os_input.get_terminal_size_using_fd(0); os_input.into_raw_mode(0); let (send_screen_instructions, receive_screen_instructions): ( - Sender, - Receiver, + Sender<(ErrorContext, ScreenInstruction)>, + Receiver<(ErrorContext, ScreenInstruction)>, ) = channel(); let (send_pty_instructions, receive_pty_instructions): ( - Sender, - Receiver, + Sender<(ErrorContext, PtyInstruction)>, + Receiver<(ErrorContext, PtyInstruction)>, ) = channel(); let (send_app_instructions, receive_app_instructions): ( - SyncSender, - Receiver, + SyncSender<(ErrorContext, AppInstruction)>, + Receiver<(ErrorContext, AppInstruction)>, ) = sync_channel(0); let mut screen = Screen::new( receive_screen_instructions, @@ -156,25 +160,30 @@ pub fn start(mut os_input: Box, opts: Opt) { } loop { - let event = pty_bus + let (mut err_ctx, event) = pty_bus .receive_pty_instructions .recv() .expect("failed to receive event on channel"); match event { PtyInstruction::SpawnTerminal(file_to_open) => { + err_ctx.add_call("pty_thread(SpawnTerminal)"); pty_bus.spawn_terminal(file_to_open); } PtyInstruction::SpawnTerminalVertically(file_to_open) => { + err_ctx.add_call("pty_thread(SpawnTerminalVertically)"); pty_bus.spawn_terminal_vertically(file_to_open); } PtyInstruction::SpawnTerminalHorizontally(file_to_open) => { + err_ctx.add_call("pty_thread(SpawnTerminalHorizontally)"); pty_bus.spawn_terminal_horizontally(file_to_open); } PtyInstruction::ClosePane(id) => { + err_ctx.add_call("pty_thread(ClosePane)"); pty_bus.close_pane(id); command_is_executing.done_closing_pane(); } PtyInstruction::Quit => { + err_ctx.add_call("pty_thread(Quit)"); break; } } @@ -190,81 +199,104 @@ pub fn start(mut os_input: Box, opts: Opt) { .spawn({ let mut command_is_executing = command_is_executing.clone(); move || loop { - let event = screen + let (mut err_ctx, event) = screen .receiver .recv() .expect("failed to receive event on channel"); match event { ScreenInstruction::Pty(pid, vte_event) => { + err_ctx.add_call("screen_thread(HandlePtyEvent)"); screen.handle_pty_event(pid, vte_event); } ScreenInstruction::Render => { + err_ctx.add_call("screen_thread(Render)"); screen.render(); } ScreenInstruction::NewPane(pid) => { + err_ctx.add_call("screen_thread(NewPane)"); screen.new_pane(pid); command_is_executing.done_opening_new_pane(); } ScreenInstruction::HorizontalSplit(pid) => { + err_ctx.add_call("screen_thread(HorizontalSplit)"); screen.horizontal_split(pid); command_is_executing.done_opening_new_pane(); } ScreenInstruction::VerticalSplit(pid) => { + err_ctx.add_call("screen_thread(VerticalSplit)"); screen.vertical_split(pid); command_is_executing.done_opening_new_pane(); } ScreenInstruction::WriteCharacter(bytes) => { + err_ctx.add_call("screen_thread(WriteCharacter)"); screen.write_to_active_terminal(bytes); } ScreenInstruction::ResizeLeft => { + err_ctx.add_call("screen_thread(ResizeLeft)"); screen.resize_left(); } ScreenInstruction::ResizeRight => { + err_ctx.add_call("screen_thread(ResizeRight)"); screen.resize_right(); } ScreenInstruction::ResizeDown => { + err_ctx.add_call("screen_thread(ResizeDown)"); screen.resize_down(); } ScreenInstruction::ResizeUp => { + err_ctx.add_call("screen_thread(ResizeUp)"); screen.resize_up(); } ScreenInstruction::MoveFocus => { + err_ctx.add_call("screen_thread(MoveFocus)"); screen.move_focus(); } ScreenInstruction::MoveFocusLeft => { + err_ctx.add_call("screen_thread(MoveFocusLeft)"); screen.move_focus_left(); } ScreenInstruction::MoveFocusDown => { + err_ctx.add_call("screen_thread(MoveFocusDown)"); screen.move_focus_down(); } ScreenInstruction::MoveFocusRight => { + err_ctx.add_call("screen_thread(MoveFocusRight)"); screen.move_focus_right(); } ScreenInstruction::MoveFocusUp => { + err_ctx.add_call("screen_thread(MoveFocusUp)"); screen.move_focus_up(); } ScreenInstruction::ScrollUp => { + err_ctx.add_call("screen_thread(ScrollUp)"); screen.scroll_active_terminal_up(); } ScreenInstruction::ScrollDown => { + err_ctx.add_call("screen_thread(ScrollDown)"); screen.scroll_active_terminal_down(); } ScreenInstruction::ClearScroll => { + err_ctx.add_call("screen_thread(ClearScroll)"); screen.clear_active_terminal_scroll(); } ScreenInstruction::CloseFocusedPane => { + err_ctx.add_call("screen_thread(CloseFocusedPane)"); screen.close_focused_pane(); } ScreenInstruction::ClosePane(id) => { + err_ctx.add_call("screen_thread(ClosePane)"); screen.close_pane(id); } ScreenInstruction::ToggleActiveTerminalFullscreen => { + err_ctx.add_call("screen_thread(ToggleActiveTerminalFullscreen)"); screen.toggle_active_terminal_fullscreen(); } ScreenInstruction::ApplyLayout((layout, new_pane_pids)) => { + err_ctx.add_call("screen_thread(ApplyLayout)"); screen.apply_layout(layout, new_pane_pids) } ScreenInstruction::Quit => { + err_ctx.add_call("screen_thread(Quit)"); break; } } @@ -394,6 +426,8 @@ pub fn start(mut os_input: Box, opts: Opt) { std::fs::remove_file(MOSAIC_IPC_PIPE).ok(); let listener = std::os::unix::net::UnixListener::bind(MOSAIC_IPC_PIPE) .expect("could not listen on ipc socket"); + let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + err_ctx.add_call("ipc_server(AcceptInput)"); for stream in listener.incoming() { match stream { @@ -408,22 +442,31 @@ pub fn start(mut os_input: Box, opts: Opt) { ApiCommand::OpenFile(file_name) => { let path = PathBuf::from(file_name); send_pty_instructions - .send(PtyInstruction::SpawnTerminal(Some(path))) + .send(( + err_ctx.clone(), + PtyInstruction::SpawnTerminal(Some(path)), + )) .unwrap(); } ApiCommand::SplitHorizontally => { send_pty_instructions - .send(PtyInstruction::SpawnTerminalHorizontally(None)) + .send(( + err_ctx.clone(), + PtyInstruction::SpawnTerminalHorizontally(None), + )) .unwrap(); } ApiCommand::SplitVertically => { send_pty_instructions - .send(PtyInstruction::SpawnTerminalVertically(None)) + .send(( + err_ctx.clone(), + PtyInstruction::SpawnTerminalVertically(None), + )) .unwrap(); } ApiCommand::MoveFocus => { send_screen_instructions - .send(ScreenInstruction::MoveFocus) + .send((err_ctx.clone(), ScreenInstruction::MoveFocus)) .unwrap(); } } @@ -456,20 +499,23 @@ pub fn start(mut os_input: Box, opts: Opt) { #[warn(clippy::never_loop)] loop { - let app_instruction = receive_app_instructions + let (mut err_ctx, app_instruction) = receive_app_instructions .recv() .expect("failed to receive app instruction on channel"); + + err_ctx.add_call("main_thread(Exit)"); match app_instruction { AppInstruction::Exit => { - let _ = send_screen_instructions.send(ScreenInstruction::Quit); - let _ = send_pty_instructions.send(PtyInstruction::Quit); + let _ = send_screen_instructions.send((err_ctx.clone(), ScreenInstruction::Quit)); + let _ = send_pty_instructions.send((err_ctx, PtyInstruction::Quit)); break; } AppInstruction::Error(backtrace) => { os_input.unset_raw_mode(0); - println!("{}", backtrace); - let _ = send_screen_instructions.send(ScreenInstruction::Quit); - let _ = send_pty_instructions.send(PtyInstruction::Quit); + let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1); + println!("{}\n{}", goto_start_of_last_line, backtrace); + let _ = send_screen_instructions.send((err_ctx.clone(), ScreenInstruction::Quit)); + let _ = send_pty_instructions.send((err_ctx, PtyInstruction::Quit)); for thread_handler in active_threads { let _ = thread_handler.join(); } diff --git a/src/pty_bus.rs b/src/pty_bus.rs index 078e327152..c21545e8e0 100644 --- a/src/pty_bus.rs +++ b/src/pty_bus.rs @@ -9,10 +9,11 @@ use ::std::time::{Duration, Instant}; use ::vte; use std::path::PathBuf; +use crate::errors::ErrorContext; use crate::layout::Layout; use crate::os_input_output::OsApi; use crate::utils::logging::debug_to_file; -use crate::ScreenInstruction; +use crate::{ScreenInstruction, OPENCALLS}; pub struct ReadFromPid { pid: RawFd, @@ -75,25 +76,32 @@ pub enum VteEvent { struct VteEventSender { id: RawFd, - sender: Sender, + sender: Sender<(ErrorContext, ScreenInstruction)>, + err_ctx: ErrorContext, } impl VteEventSender { - pub fn new(id: RawFd, sender: Sender) -> Self { - VteEventSender { id, sender } + pub fn new(id: RawFd, sender: Sender<(ErrorContext, ScreenInstruction)>) -> Self { + VteEventSender { + id, + sender, + err_ctx: OPENCALLS.with(|ctx| ctx.borrow().clone()), + } } } impl vte::Perform for VteEventSender { fn print(&mut self, c: char) { - let _ = self - .sender - .send(ScreenInstruction::Pty(self.id, VteEvent::Print(c))); + let _ = self.sender.send(( + self.err_ctx.clone(), + ScreenInstruction::Pty(self.id, VteEvent::Print(c)), + )); } fn execute(&mut self, byte: u8) { - let _ = self - .sender - .send(ScreenInstruction::Pty(self.id, VteEvent::Execute(byte))); + let _ = self.sender.send(( + self.err_ctx.clone(), + ScreenInstruction::Pty(self.id, VteEvent::Execute(byte)), + )); } fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { @@ -101,26 +109,28 @@ impl vte::Perform for VteEventSender { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::Hook(params, intermediates, ignore, c)); - let _ = self.sender.send(instruction); + let _ = self.sender.send((self.err_ctx.clone(), instruction)); } fn put(&mut self, byte: u8) { - let _ = self - .sender - .send(ScreenInstruction::Pty(self.id, VteEvent::Put(byte))); + let _ = self.sender.send(( + self.err_ctx.clone(), + ScreenInstruction::Pty(self.id, VteEvent::Put(byte)), + )); } fn unhook(&mut self) { - let _ = self - .sender - .send(ScreenInstruction::Pty(self.id, VteEvent::Unhook)); + let _ = self.sender.send(( + self.err_ctx.clone(), + ScreenInstruction::Pty(self.id, VteEvent::Unhook), + )); } fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { let params = params.iter().map(|p| p.to_vec()).collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::OscDispatch(params, bell_terminated)); - let _ = self.sender.send(instruction); + let _ = self.sender.send((self.err_ctx.clone(), instruction)); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { @@ -130,14 +140,14 @@ impl vte::Perform for VteEventSender { self.id, VteEvent::CsiDispatch(params, intermediates, ignore, c), ); - let _ = self.sender.send(instruction); + let _ = self.sender.send((self.err_ctx.clone(), instruction)); } fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::EscDispatch(intermediates, ignore, byte)); - let _ = self.sender.send(instruction); + let _ = self.sender.send((self.err_ctx.clone(), instruction)); } } @@ -151,8 +161,8 @@ pub enum PtyInstruction { } pub struct PtyBus { - pub send_screen_instructions: Sender, - pub receive_pty_instructions: Receiver, + pub send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, + pub receive_pty_instructions: Receiver<(ErrorContext, PtyInstruction)>, pub id_to_child_pid: HashMap, os_input: Box, debug_to_file: bool, @@ -160,12 +170,14 @@ pub struct PtyBus { fn stream_terminal_bytes( pid: RawFd, - send_screen_instructions: Sender, + send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, os_input: Box, debug: bool, ) { + let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); task::spawn({ async move { + err_ctx.add_call("stream_terminal_bytes(AsyncTask)"); let mut vte_parser = vte::Parser::new(); let mut vte_event_sender = VteEventSender::new(pid, send_screen_instructions.clone()); let mut terminal_bytes = ReadFromPid::new(&pid, os_input); @@ -194,7 +206,7 @@ fn stream_terminal_bytes( if receive_time.elapsed() > max_render_pause { pending_render = false; send_screen_instructions - .send(ScreenInstruction::Render) + .send((err_ctx.clone(), ScreenInstruction::Render)) .unwrap(); last_byte_receive_time = Some(Instant::now()); } else { @@ -210,7 +222,7 @@ fn stream_terminal_bytes( if pending_render { pending_render = false; send_screen_instructions - .send(ScreenInstruction::Render) + .send((err_ctx.clone(), ScreenInstruction::Render)) .unwrap(); } last_byte_receive_time = None; @@ -218,14 +230,14 @@ fn stream_terminal_bytes( } } send_screen_instructions - .send(ScreenInstruction::Render) + .send((err_ctx.clone(), ScreenInstruction::Render)) .unwrap(); #[cfg(not(test))] // this is a little hacky, and is because the tests end the file as soon as // we read everything, rather than hanging until there is new data // a better solution would be to fix the test fakes, but this will do for now send_screen_instructions - .send(ScreenInstruction::ClosePane(pid)) + .send((err_ctx, ScreenInstruction::ClosePane(pid))) .unwrap(); } }); @@ -233,8 +245,8 @@ fn stream_terminal_bytes( impl PtyBus { pub fn new( - receive_pty_instructions: Receiver, - send_screen_instructions: Sender, + receive_pty_instructions: Receiver<(ErrorContext, PtyInstruction)>, + send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, os_input: Box, debug_to_file: bool, ) -> Self { @@ -256,8 +268,9 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send(ScreenInstruction::NewPane(pid_primary)) + .send((err_ctx, ScreenInstruction::NewPane(pid_primary))) .unwrap(); } pub fn spawn_terminal_vertically(&mut self, file_to_open: Option) { @@ -270,8 +283,9 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send(ScreenInstruction::VerticalSplit(pid_primary)) + .send((err_ctx, ScreenInstruction::VerticalSplit(pid_primary))) .unwrap(); } pub fn spawn_terminal_horizontally(&mut self, file_to_open: Option) { @@ -284,8 +298,9 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send(ScreenInstruction::HorizontalSplit(pid_primary)) + .send((err_ctx, ScreenInstruction::HorizontalSplit(pid_primary))) .unwrap(); } pub fn spawn_terminals_for_layout(&mut self, layout: Layout) { @@ -296,11 +311,12 @@ impl PtyBus { self.id_to_child_pid.insert(pid_primary, pid_secondary); new_pane_pids.push(pid_primary); } + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send(ScreenInstruction::ApplyLayout(( - layout, - new_pane_pids.clone(), - ))) + .send(( + err_ctx, + ScreenInstruction::ApplyLayout((layout, new_pane_pids.clone())), + )) .unwrap(); for id in new_pane_pids { stream_terminal_bytes( diff --git a/src/screen.rs b/src/screen.rs index e00cc0a9a2..ba42d1d4b6 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -5,12 +5,12 @@ use std::sync::mpsc::{Receiver, Sender, SyncSender}; use crate::boundaries::Boundaries; use crate::boundaries::Rect; +use crate::errors::ErrorContext; use crate::layout::Layout; use crate::os_input_output::OsApi; use crate::pty_bus::{PtyInstruction, VteEvent}; use crate::terminal_pane::{PositionAndSize, TerminalPane}; -use crate::utils::logging::debug_log_to_file; -use crate::AppInstruction; +use crate::{AppInstruction, OPENCALLS}; /* * Screen @@ -78,10 +78,10 @@ pub enum ScreenInstruction { } pub struct Screen { - pub receiver: Receiver, + pub receiver: Receiver<(ErrorContext, ScreenInstruction)>, max_panes: Option, - send_pty_instructions: Sender, - send_app_instructions: SyncSender, + send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, + send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, full_screen_ws: PositionAndSize, terminals: BTreeMap, // BTreeMap because we need a predictable order when changing focus panes_to_hide: HashSet, @@ -92,9 +92,9 @@ pub struct Screen { impl Screen { pub fn new( - receive_screen_instructions: Receiver, - send_pty_instructions: Sender, - send_app_instructions: SyncSender, + receive_screen_instructions: Receiver<(ErrorContext, ScreenInstruction)>, + send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, + send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, full_screen_ws: &PositionAndSize, os_api: Box, max_panes: Option, @@ -164,8 +164,9 @@ impl Screen { // this is a bit of a hack and happens because we don't have any central location that // can query the screen as to how many panes it needs to create a layout // fixing this will require a bit of an architecture change + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_pty_instructions - .send(PtyInstruction::ClosePane(*unused_pid)) + .send((err_ctx, PtyInstruction::ClosePane(*unused_pid))) .unwrap(); } self.active_terminal = Some(*self.terminals.iter().next().unwrap().0); @@ -1532,10 +1533,11 @@ impl Screen { fn close_down_to_max_terminals(&mut self) { if let Some(max_panes) = self.max_panes { if self.terminals.len() >= max_panes { + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); for _ in max_panes..=self.terminals.len() { let first_pid = *self.terminals.iter().next().unwrap().0; self.send_pty_instructions - .send(PtyInstruction::ClosePane(first_pid)) + .send((err_ctx.clone(), PtyInstruction::ClosePane(first_pid))) .unwrap(); self.close_pane_without_rerender(first_pid); // TODO: do not render yet } @@ -1590,15 +1592,19 @@ impl Screen { self.terminals.remove(&id); if self.terminals.is_empty() { self.active_terminal = None; - let _ = self.send_app_instructions.send(AppInstruction::Exit); + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let _ = self + .send_app_instructions + .send((err_ctx, AppInstruction::Exit)); } } } pub fn close_focused_pane(&mut self) { if let Some(active_terminal_id) = self.get_active_terminal_id() { self.close_pane(active_terminal_id); + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_pty_instructions - .send(PtyInstruction::ClosePane(active_terminal_id)) + .send((err_ctx, PtyInstruction::ClosePane(active_terminal_id))) .unwrap(); } } diff --git a/src/terminal_pane/terminal_pane.rs b/src/terminal_pane/terminal_pane.rs index 348a9fe0c8..9f8ddcfa6b 100644 --- a/src/terminal_pane/terminal_pane.rs +++ b/src/terminal_pane/terminal_pane.rs @@ -9,7 +9,7 @@ use crate::terminal_pane::terminal_character::{ AnsiCode, CharacterStyles, NamedColor, TerminalCharacter, }; use crate::terminal_pane::Scroll; -use crate::utils::logging::{debug_log_to_file, debug_log_to_file_pid_3}; +use crate::utils::logging::debug_log_to_file; use crate::VteEvent; #[derive(Clone, Copy, Debug)] diff --git a/src/utils/logging.rs b/src/utils/logging.rs index 84a2da8fab..05af455c06 100644 --- a/src/utils/logging.rs +++ b/src/utils/logging.rs @@ -37,7 +37,7 @@ pub fn debug_log_to_file_without_newline(message: String) -> io::Result<()> { file.write_all(message.as_bytes()) } -pub fn debug_log_to_file_pid_3(message: String, pid: RawFd) -> io::Result<()> { +pub fn _debug_log_to_file_pid_3(message: String, pid: RawFd) -> io::Result<()> { if pid == 3 { debug_log_to_file(message) } else { From 2fcfbbb1400e40bcc6fb6cc5a9a12094edb4fd22 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Mon, 7 Dec 2020 23:26:33 +0530 Subject: [PATCH 02/10] reorder Instruction and ErrorContext --- src/errors.rs | 8 +++++-- src/input.rs | 60 +++++++++++++++++++++++++------------------------- src/main.rs | 34 ++++++++++++++-------------- src/pty_bus.rs | 46 +++++++++++++++++++------------------- src/screen.rs | 20 ++++++++--------- 5 files changed, 86 insertions(+), 82 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 5d6dc730c8..18e7657e33 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -6,7 +6,7 @@ use std::{process, thread}; pub fn handle_panic( info: &PanicInfo<'_>, - send_app_instructions: &SyncSender<(ErrorContext, AppInstruction)>, + send_app_instructions: &SyncSender<(AppInstruction, ErrorContext)>, ) { let backtrace = Backtrace::new(); let thread = thread::current(); @@ -53,7 +53,7 @@ pub fn handle_panic( } else { err_ctx.add_call("panic_hook(handle_panic)"); send_app_instructions - .send((err_ctx, AppInstruction::Error(backtrace))) + .send((AppInstruction::Error(backtrace), err_ctx)) .unwrap(); } } @@ -73,3 +73,7 @@ impl ErrorContext { OPENCALLS.with(|ctx| *ctx.borrow_mut() = self.clone()); } } + +pub trait InstType {} + +impl InstType for AppInstruction {} diff --git a/src/input.rs b/src/input.rs index 5f8f25ef63..51b2e1330f 100644 --- a/src/input.rs +++ b/src/input.rs @@ -12,18 +12,18 @@ struct InputHandler { mode: InputMode, os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, - send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, - send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, + send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, + send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, + send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, } impl InputHandler { fn new( os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, - send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, - send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, + send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, + send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, + send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, ) -> Self { InputHandler { mode: InputMode::Normal, @@ -67,12 +67,12 @@ impl InputHandler { } _ => { self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::ClearScroll)) + .send((ScreenInstruction::ClearScroll, err_ctx.clone())) .unwrap(); self.send_screen_instructions .send(( - err_ctx.clone(), ScreenInstruction::WriteCharacter(stdin_buffer), + err_ctx.clone(), )) .unwrap(); } @@ -117,38 +117,38 @@ impl InputHandler { [106] => { // j self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::ResizeDown)) + .send((ScreenInstruction::ResizeDown, err_ctx.clone())) .unwrap(); } [107] => { // k self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::ResizeUp)) + .send((ScreenInstruction::ResizeUp, err_ctx.clone())) .unwrap(); } [112] => { // p self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::MoveFocus)) + .send((ScreenInstruction::MoveFocus, err_ctx.clone())) .unwrap(); } [104] => { // h self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::ResizeLeft)) + .send((ScreenInstruction::ResizeLeft, err_ctx.clone())) .unwrap(); } [108] => { // l self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::ResizeRight)) + .send((ScreenInstruction::ResizeRight, err_ctx.clone())) .unwrap(); } [122] => { // z self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send((err_ctx.clone(), PtyInstruction::SpawnTerminal(None))) + .send((PtyInstruction::SpawnTerminal(None), err_ctx.clone())) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -157,8 +157,8 @@ impl InputHandler { self.command_is_executing.opening_new_pane(); self.send_pty_instructions .send(( - err_ctx.clone(), PtyInstruction::SpawnTerminalVertically(None), + err_ctx.clone(), )) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); @@ -168,8 +168,8 @@ impl InputHandler { self.command_is_executing.opening_new_pane(); self.send_pty_instructions .send(( - err_ctx.clone(), PtyInstruction::SpawnTerminalHorizontally(None), + err_ctx.clone(), )) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); @@ -182,20 +182,20 @@ impl InputHandler { [27, 91, 53, 126] => { // PgUp self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::ScrollUp)) + .send((ScreenInstruction::ScrollUp, err_ctx.clone())) .unwrap(); } [27, 91, 54, 126] => { // PgDown self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::ScrollDown)) + .send((ScreenInstruction::ScrollDown, err_ctx.clone())) .unwrap(); } [120] => { // x self.command_is_executing.closing_pane(); self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::CloseFocusedPane)) + .send((ScreenInstruction::CloseFocusedPane, err_ctx.clone())) .unwrap(); self.command_is_executing.wait_until_pane_is_closed(); } @@ -203,33 +203,33 @@ impl InputHandler { // e self.send_screen_instructions .send(( - err_ctx.clone(), ScreenInstruction::ToggleActiveTerminalFullscreen, + err_ctx.clone(), )) .unwrap(); } [121] => { // y self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::MoveFocusLeft)) + .send((ScreenInstruction::MoveFocusLeft, err_ctx.clone())) .unwrap() } [117] => { // u self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::MoveFocusDown)) + .send((ScreenInstruction::MoveFocusDown, err_ctx.clone())) .unwrap() } [105] => { // i self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::MoveFocusUp)) + .send((ScreenInstruction::MoveFocusUp, err_ctx.clone())) .unwrap() } [111] => { // o self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::MoveFocusRight)) + .send((ScreenInstruction::MoveFocusRight, err_ctx.clone())) .unwrap() } //@@@khs26 Write this to the powerbar? @@ -248,13 +248,13 @@ impl InputHandler { fn exit(&mut self) { let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::Quit)) + .send((ScreenInstruction::Quit, err_ctx.clone())) .unwrap(); self.send_pty_instructions - .send((err_ctx.clone(), PtyInstruction::Quit)) + .send((PtyInstruction::Quit, err_ctx.clone())) .unwrap(); self.send_app_instructions - .send((err_ctx.clone(), AppInstruction::Exit)) + .send((AppInstruction::Exit, err_ctx)) .unwrap(); } } @@ -281,9 +281,9 @@ pub enum InputMode { pub fn input_loop( os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, - send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, - send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, + send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, + send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, + send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, ) { let _handler = InputHandler::new( os_input, diff --git a/src/main.rs b/src/main.rs index e0df387c32..c044d4b199 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,16 +111,16 @@ pub fn start(mut os_input: Box, opts: Opt) { let full_screen_ws = os_input.get_terminal_size_using_fd(0); os_input.into_raw_mode(0); let (send_screen_instructions, receive_screen_instructions): ( - Sender<(ErrorContext, ScreenInstruction)>, - Receiver<(ErrorContext, ScreenInstruction)>, + Sender<(ScreenInstruction, ErrorContext)>, + Receiver<(ScreenInstruction, ErrorContext)>, ) = channel(); let (send_pty_instructions, receive_pty_instructions): ( - Sender<(ErrorContext, PtyInstruction)>, - Receiver<(ErrorContext, PtyInstruction)>, + Sender<(PtyInstruction, ErrorContext)>, + Receiver<(PtyInstruction, ErrorContext)>, ) = channel(); let (send_app_instructions, receive_app_instructions): ( - SyncSender<(ErrorContext, AppInstruction)>, - Receiver<(ErrorContext, AppInstruction)>, + SyncSender<(AppInstruction, ErrorContext)>, + Receiver<(AppInstruction, ErrorContext)>, ) = sync_channel(0); let mut screen = Screen::new( receive_screen_instructions, @@ -160,7 +160,7 @@ pub fn start(mut os_input: Box, opts: Opt) { } loop { - let (mut err_ctx, event) = pty_bus + let (event, mut err_ctx) = pty_bus .receive_pty_instructions .recv() .expect("failed to receive event on channel"); @@ -199,7 +199,7 @@ pub fn start(mut os_input: Box, opts: Opt) { .spawn({ let mut command_is_executing = command_is_executing.clone(); move || loop { - let (mut err_ctx, event) = screen + let (event, mut err_ctx) = screen .receiver .recv() .expect("failed to receive event on channel"); @@ -443,30 +443,30 @@ pub fn start(mut os_input: Box, opts: Opt) { let path = PathBuf::from(file_name); send_pty_instructions .send(( - err_ctx.clone(), PtyInstruction::SpawnTerminal(Some(path)), + err_ctx.clone(), )) .unwrap(); } ApiCommand::SplitHorizontally => { send_pty_instructions .send(( - err_ctx.clone(), PtyInstruction::SpawnTerminalHorizontally(None), + err_ctx.clone(), )) .unwrap(); } ApiCommand::SplitVertically => { send_pty_instructions .send(( - err_ctx.clone(), PtyInstruction::SpawnTerminalVertically(None), + err_ctx.clone(), )) .unwrap(); } ApiCommand::MoveFocus => { send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::MoveFocus)) + .send((ScreenInstruction::MoveFocus, err_ctx.clone())) .unwrap(); } } @@ -499,23 +499,23 @@ pub fn start(mut os_input: Box, opts: Opt) { #[warn(clippy::never_loop)] loop { - let (mut err_ctx, app_instruction) = receive_app_instructions + let (app_instruction, mut err_ctx) = receive_app_instructions .recv() .expect("failed to receive app instruction on channel"); err_ctx.add_call("main_thread(Exit)"); match app_instruction { AppInstruction::Exit => { - let _ = send_screen_instructions.send((err_ctx.clone(), ScreenInstruction::Quit)); - let _ = send_pty_instructions.send((err_ctx, PtyInstruction::Quit)); + let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx.clone())); + let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); break; } AppInstruction::Error(backtrace) => { os_input.unset_raw_mode(0); let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1); println!("{}\n{}", goto_start_of_last_line, backtrace); - let _ = send_screen_instructions.send((err_ctx.clone(), ScreenInstruction::Quit)); - let _ = send_pty_instructions.send((err_ctx, PtyInstruction::Quit)); + let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx.clone())); + let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); for thread_handler in active_threads { let _ = thread_handler.join(); } diff --git a/src/pty_bus.rs b/src/pty_bus.rs index c21545e8e0..8a1f3365ea 100644 --- a/src/pty_bus.rs +++ b/src/pty_bus.rs @@ -76,12 +76,12 @@ pub enum VteEvent { struct VteEventSender { id: RawFd, - sender: Sender<(ErrorContext, ScreenInstruction)>, + sender: Sender<(ScreenInstruction, ErrorContext)>, err_ctx: ErrorContext, } impl VteEventSender { - pub fn new(id: RawFd, sender: Sender<(ErrorContext, ScreenInstruction)>) -> Self { + pub fn new(id: RawFd, sender: Sender<(ScreenInstruction, ErrorContext)>) -> Self { VteEventSender { id, sender, @@ -93,14 +93,14 @@ impl VteEventSender { impl vte::Perform for VteEventSender { fn print(&mut self, c: char) { let _ = self.sender.send(( - self.err_ctx.clone(), ScreenInstruction::Pty(self.id, VteEvent::Print(c)), + self.err_ctx.clone(), )); } fn execute(&mut self, byte: u8) { let _ = self.sender.send(( - self.err_ctx.clone(), ScreenInstruction::Pty(self.id, VteEvent::Execute(byte)), + self.err_ctx.clone(), )); } @@ -109,20 +109,20 @@ impl vte::Perform for VteEventSender { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::Hook(params, intermediates, ignore, c)); - let _ = self.sender.send((self.err_ctx.clone(), instruction)); + let _ = self.sender.send((instruction, self.err_ctx.clone())); } fn put(&mut self, byte: u8) { let _ = self.sender.send(( - self.err_ctx.clone(), ScreenInstruction::Pty(self.id, VteEvent::Put(byte)), + self.err_ctx.clone(), )); } fn unhook(&mut self) { let _ = self.sender.send(( - self.err_ctx.clone(), ScreenInstruction::Pty(self.id, VteEvent::Unhook), + self.err_ctx.clone(), )); } @@ -130,7 +130,7 @@ impl vte::Perform for VteEventSender { let params = params.iter().map(|p| p.to_vec()).collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::OscDispatch(params, bell_terminated)); - let _ = self.sender.send((self.err_ctx.clone(), instruction)); + let _ = self.sender.send((instruction, self.err_ctx.clone())); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { @@ -140,14 +140,14 @@ impl vte::Perform for VteEventSender { self.id, VteEvent::CsiDispatch(params, intermediates, ignore, c), ); - let _ = self.sender.send((self.err_ctx.clone(), instruction)); + let _ = self.sender.send((instruction, self.err_ctx.clone())); } fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::EscDispatch(intermediates, ignore, byte)); - let _ = self.sender.send((self.err_ctx.clone(), instruction)); + let _ = self.sender.send((instruction, self.err_ctx.clone())); } } @@ -161,8 +161,8 @@ pub enum PtyInstruction { } pub struct PtyBus { - pub send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, - pub receive_pty_instructions: Receiver<(ErrorContext, PtyInstruction)>, + pub send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, + pub receive_pty_instructions: Receiver<(PtyInstruction, ErrorContext)>, pub id_to_child_pid: HashMap, os_input: Box, debug_to_file: bool, @@ -170,7 +170,7 @@ pub struct PtyBus { fn stream_terminal_bytes( pid: RawFd, - send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, + send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, os_input: Box, debug: bool, ) { @@ -206,7 +206,7 @@ fn stream_terminal_bytes( if receive_time.elapsed() > max_render_pause { pending_render = false; send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::Render)) + .send((ScreenInstruction::Render, err_ctx.clone())) .unwrap(); last_byte_receive_time = Some(Instant::now()); } else { @@ -222,7 +222,7 @@ fn stream_terminal_bytes( if pending_render { pending_render = false; send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::Render)) + .send((ScreenInstruction::Render, err_ctx.clone())) .unwrap(); } last_byte_receive_time = None; @@ -230,14 +230,14 @@ fn stream_terminal_bytes( } } send_screen_instructions - .send((err_ctx.clone(), ScreenInstruction::Render)) + .send((ScreenInstruction::Render, err_ctx.clone())) .unwrap(); #[cfg(not(test))] // this is a little hacky, and is because the tests end the file as soon as // we read everything, rather than hanging until there is new data // a better solution would be to fix the test fakes, but this will do for now send_screen_instructions - .send((err_ctx, ScreenInstruction::ClosePane(pid))) + .send((ScreenInstruction::ClosePane(pid), err_ctx)) .unwrap(); } }); @@ -245,8 +245,8 @@ fn stream_terminal_bytes( impl PtyBus { pub fn new( - receive_pty_instructions: Receiver<(ErrorContext, PtyInstruction)>, - send_screen_instructions: Sender<(ErrorContext, ScreenInstruction)>, + receive_pty_instructions: Receiver<(PtyInstruction, ErrorContext)>, + send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, os_input: Box, debug_to_file: bool, ) -> Self { @@ -270,7 +270,7 @@ impl PtyBus { self.id_to_child_pid.insert(pid_primary, pid_secondary); let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send((err_ctx, ScreenInstruction::NewPane(pid_primary))) + .send((ScreenInstruction::NewPane(pid_primary), err_ctx)) .unwrap(); } pub fn spawn_terminal_vertically(&mut self, file_to_open: Option) { @@ -285,7 +285,7 @@ impl PtyBus { self.id_to_child_pid.insert(pid_primary, pid_secondary); let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send((err_ctx, ScreenInstruction::VerticalSplit(pid_primary))) + .send((ScreenInstruction::VerticalSplit(pid_primary), err_ctx)) .unwrap(); } pub fn spawn_terminal_horizontally(&mut self, file_to_open: Option) { @@ -300,7 +300,7 @@ impl PtyBus { self.id_to_child_pid.insert(pid_primary, pid_secondary); let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions - .send((err_ctx, ScreenInstruction::HorizontalSplit(pid_primary))) + .send((ScreenInstruction::HorizontalSplit(pid_primary), err_ctx)) .unwrap(); } pub fn spawn_terminals_for_layout(&mut self, layout: Layout) { @@ -314,8 +314,8 @@ impl PtyBus { let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_screen_instructions .send(( - err_ctx, ScreenInstruction::ApplyLayout((layout, new_pane_pids.clone())), + err_ctx, )) .unwrap(); for id in new_pane_pids { diff --git a/src/screen.rs b/src/screen.rs index ba42d1d4b6..dfa6192020 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -78,10 +78,10 @@ pub enum ScreenInstruction { } pub struct Screen { - pub receiver: Receiver<(ErrorContext, ScreenInstruction)>, + pub receiver: Receiver<(ScreenInstruction, ErrorContext)>, max_panes: Option, - send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, - send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, + send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, + send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, full_screen_ws: PositionAndSize, terminals: BTreeMap, // BTreeMap because we need a predictable order when changing focus panes_to_hide: HashSet, @@ -92,9 +92,9 @@ pub struct Screen { impl Screen { pub fn new( - receive_screen_instructions: Receiver<(ErrorContext, ScreenInstruction)>, - send_pty_instructions: Sender<(ErrorContext, PtyInstruction)>, - send_app_instructions: SyncSender<(ErrorContext, AppInstruction)>, + receive_screen_instructions: Receiver<(ScreenInstruction, ErrorContext)>, + send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, + send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, full_screen_ws: &PositionAndSize, os_api: Box, max_panes: Option, @@ -166,7 +166,7 @@ impl Screen { // fixing this will require a bit of an architecture change let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_pty_instructions - .send((err_ctx, PtyInstruction::ClosePane(*unused_pid))) + .send((PtyInstruction::ClosePane(*unused_pid), err_ctx)) .unwrap(); } self.active_terminal = Some(*self.terminals.iter().next().unwrap().0); @@ -1537,7 +1537,7 @@ impl Screen { for _ in max_panes..=self.terminals.len() { let first_pid = *self.terminals.iter().next().unwrap().0; self.send_pty_instructions - .send((err_ctx.clone(), PtyInstruction::ClosePane(first_pid))) + .send((PtyInstruction::ClosePane(first_pid), err_ctx.clone())) .unwrap(); self.close_pane_without_rerender(first_pid); // TODO: do not render yet } @@ -1595,7 +1595,7 @@ impl Screen { let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); let _ = self .send_app_instructions - .send((err_ctx, AppInstruction::Exit)); + .send((AppInstruction::Exit, err_ctx)); } } } @@ -1604,7 +1604,7 @@ impl Screen { self.close_pane(active_terminal_id); let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); self.send_pty_instructions - .send((err_ctx, PtyInstruction::ClosePane(active_terminal_id))) + .send((PtyInstruction::ClosePane(active_terminal_id), err_ctx)) .unwrap(); } } From 50e4e6856ea0635ebbbd183d389aa77be04c94b1 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Tue, 8 Dec 2020 01:04:14 +0530 Subject: [PATCH 03/10] Add ContextType, AppContext, ScreenContext, PtyContext --- src/errors.rs | 120 +++++++++++++++++++++++++++++++++++++++++++++---- src/input.rs | 4 +- src/main.rs | 36 +++------------ src/pty_bus.rs | 4 +- 4 files changed, 120 insertions(+), 44 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 18e7657e33..28d8f3c462 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,5 @@ +use crate::pty_bus::PtyInstruction; +use crate::screen::ScreenInstruction; use crate::{AppInstruction, OPENCALLS}; use backtrace::Backtrace; use std::panic::PanicInfo; @@ -51,16 +53,15 @@ pub fn handle_panic( println!("{}", backtrace); process::exit(1); } else { - err_ctx.add_call("panic_hook(handle_panic)"); - send_app_instructions - .send((AppInstruction::Error(backtrace), err_ctx)) - .unwrap(); + let instruction = AppInstruction::Error(backtrace); + err_ctx.add_call(ContextType::App(AppContext::from(&instruction))); + send_app_instructions.send((instruction, err_ctx)).unwrap(); } } #[derive(Clone, Debug)] pub struct ErrorContext { - calls: Vec, + calls: Vec, } impl ErrorContext { @@ -68,12 +69,113 @@ impl ErrorContext { Self { calls: Vec::new() } } - pub fn add_call(&mut self, call: &str) { - self.calls.push(call.into()); + pub fn add_call(&mut self, call: ContextType) { + self.calls.push(call); OPENCALLS.with(|ctx| *ctx.borrow_mut() = self.clone()); } } -pub trait InstType {} +#[derive(Debug, Copy, Clone)] +pub enum ContextType { + Screen(ScreenContext), + Pty(PtyContext), + App(AppContext), + IPCServer, + StdinHandler, + AsyncTask, +} + +#[derive(Debug, Clone, Copy)] +pub enum ScreenContext { + HandlePtyEvent, + Render, + NewPane, + HorizontalSplit, + VerticalSplit, + WriteCharacter, + ResizeLeft, + ResizeRight, + ResizeDown, + ResizeUp, + MoveFocus, + MoveFocusLeft, + MoveFocusDown, + MoveFocusUp, + MoveFocusRight, + Quit, + ScrollUp, + ScrollDown, + ClearScroll, + CloseFocusedPane, + ToggleActiveTerminalFullscreen, + ClosePane, + ApplyLayout, +} + +impl From<&ScreenInstruction> for ScreenContext { + fn from(screen_instruction: &ScreenInstruction) -> Self { + match *screen_instruction { + ScreenInstruction::Pty(..) => ScreenContext::HandlePtyEvent, + ScreenInstruction::Render => ScreenContext::Render, + ScreenInstruction::NewPane(_) => ScreenContext::NewPane, + ScreenInstruction::HorizontalSplit(_) => ScreenContext::HorizontalSplit, + ScreenInstruction::VerticalSplit(_) => ScreenContext::VerticalSplit, + ScreenInstruction::WriteCharacter(_) => ScreenContext::WriteCharacter, + ScreenInstruction::ResizeLeft => ScreenContext::ResizeLeft, + ScreenInstruction::ResizeRight => ScreenContext::ResizeRight, + ScreenInstruction::ResizeDown => ScreenContext::ResizeDown, + ScreenInstruction::ResizeUp => ScreenContext::ResizeUp, + ScreenInstruction::MoveFocus => ScreenContext::MoveFocus, + ScreenInstruction::MoveFocusLeft => ScreenContext::MoveFocusLeft, + ScreenInstruction::MoveFocusDown => ScreenContext::MoveFocusDown, + ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp, + ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight, + ScreenInstruction::Quit => ScreenContext::Quit, + ScreenInstruction::ScrollUp => ScreenContext::ScrollUp, + ScreenInstruction::ScrollDown => ScreenContext::ScrollDown, + ScreenInstruction::ClearScroll => ScreenContext::ClearScroll, + ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane, + ScreenInstruction::ToggleActiveTerminalFullscreen => { + ScreenContext::ToggleActiveTerminalFullscreen + } + ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane, + ScreenInstruction::ApplyLayout(_) => ScreenContext::ApplyLayout, + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum PtyContext { + SpawnTerminal, + SpawnTerminalVertically, + SpawnTerminalHorizontally, + ClosePane, + Quit, +} -impl InstType for AppInstruction {} +impl From<&PtyInstruction> for PtyContext { + fn from(pty_instruction: &PtyInstruction) -> Self { + match *pty_instruction { + PtyInstruction::SpawnTerminal(_) => PtyContext::SpawnTerminal, + PtyInstruction::SpawnTerminalVertically(_) => PtyContext::SpawnTerminalVertically, + PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally, + PtyInstruction::ClosePane(_) => PtyContext::ClosePane, + PtyInstruction::Quit => PtyContext::Quit, + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum AppContext { + Exit, + Error, +} + +impl From<&AppInstruction> for AppContext { + fn from(app_instruction: &AppInstruction) -> Self { + match *app_instruction { + AppInstruction::Exit => AppContext::Exit, + AppInstruction::Error(_) => AppContext::Error, + } + } +} diff --git a/src/input.rs b/src/input.rs index 51b2e1330f..67c984db1e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,7 +1,7 @@ /// Module for handling input use std::sync::mpsc::{Sender, SyncSender}; -use crate::errors::ErrorContext; +use crate::errors::{ContextType, ErrorContext}; use crate::os_input_output::OsApi; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; @@ -38,7 +38,7 @@ impl InputHandler { /// Main event loop fn get_input(&mut self) { let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); - err_ctx.add_call("stdin_handler(AcceptInput)"); + err_ctx.add_call(ContextType::StdinHandler); loop { match self.mode { InputMode::Normal => self.read_normal_mode(), diff --git a/src/main.rs b/src/main.rs index c044d4b199..d06ba7a9ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; use structopt::StructOpt; use crate::command_is_executing::CommandIsExecuting; -use crate::errors::ErrorContext; +use crate::errors::{AppContext, ContextType, ErrorContext, PtyContext, ScreenContext}; use crate::input::input_loop; use crate::layout::Layout; use crate::os_input_output::{get_os_input, OsApi}; @@ -164,26 +164,22 @@ pub fn start(mut os_input: Box, opts: Opt) { .receive_pty_instructions .recv() .expect("failed to receive event on channel"); + err_ctx.add_call(ContextType::Pty(PtyContext::from(&event))); match event { PtyInstruction::SpawnTerminal(file_to_open) => { - err_ctx.add_call("pty_thread(SpawnTerminal)"); pty_bus.spawn_terminal(file_to_open); } PtyInstruction::SpawnTerminalVertically(file_to_open) => { - err_ctx.add_call("pty_thread(SpawnTerminalVertically)"); pty_bus.spawn_terminal_vertically(file_to_open); } PtyInstruction::SpawnTerminalHorizontally(file_to_open) => { - err_ctx.add_call("pty_thread(SpawnTerminalHorizontally)"); pty_bus.spawn_terminal_horizontally(file_to_open); } PtyInstruction::ClosePane(id) => { - err_ctx.add_call("pty_thread(ClosePane)"); pty_bus.close_pane(id); command_is_executing.done_closing_pane(); } PtyInstruction::Quit => { - err_ctx.add_call("pty_thread(Quit)"); break; } } @@ -203,100 +199,78 @@ pub fn start(mut os_input: Box, opts: Opt) { .receiver .recv() .expect("failed to receive event on channel"); + err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event))); match event { ScreenInstruction::Pty(pid, vte_event) => { - err_ctx.add_call("screen_thread(HandlePtyEvent)"); screen.handle_pty_event(pid, vte_event); } ScreenInstruction::Render => { - err_ctx.add_call("screen_thread(Render)"); screen.render(); } ScreenInstruction::NewPane(pid) => { - err_ctx.add_call("screen_thread(NewPane)"); screen.new_pane(pid); command_is_executing.done_opening_new_pane(); } ScreenInstruction::HorizontalSplit(pid) => { - err_ctx.add_call("screen_thread(HorizontalSplit)"); screen.horizontal_split(pid); command_is_executing.done_opening_new_pane(); } ScreenInstruction::VerticalSplit(pid) => { - err_ctx.add_call("screen_thread(VerticalSplit)"); screen.vertical_split(pid); command_is_executing.done_opening_new_pane(); } ScreenInstruction::WriteCharacter(bytes) => { - err_ctx.add_call("screen_thread(WriteCharacter)"); screen.write_to_active_terminal(bytes); } ScreenInstruction::ResizeLeft => { - err_ctx.add_call("screen_thread(ResizeLeft)"); screen.resize_left(); } ScreenInstruction::ResizeRight => { - err_ctx.add_call("screen_thread(ResizeRight)"); screen.resize_right(); } ScreenInstruction::ResizeDown => { - err_ctx.add_call("screen_thread(ResizeDown)"); screen.resize_down(); } ScreenInstruction::ResizeUp => { - err_ctx.add_call("screen_thread(ResizeUp)"); screen.resize_up(); } ScreenInstruction::MoveFocus => { - err_ctx.add_call("screen_thread(MoveFocus)"); screen.move_focus(); } ScreenInstruction::MoveFocusLeft => { - err_ctx.add_call("screen_thread(MoveFocusLeft)"); screen.move_focus_left(); } ScreenInstruction::MoveFocusDown => { - err_ctx.add_call("screen_thread(MoveFocusDown)"); screen.move_focus_down(); } ScreenInstruction::MoveFocusRight => { - err_ctx.add_call("screen_thread(MoveFocusRight)"); screen.move_focus_right(); } ScreenInstruction::MoveFocusUp => { - err_ctx.add_call("screen_thread(MoveFocusUp)"); screen.move_focus_up(); } ScreenInstruction::ScrollUp => { - err_ctx.add_call("screen_thread(ScrollUp)"); screen.scroll_active_terminal_up(); } ScreenInstruction::ScrollDown => { - err_ctx.add_call("screen_thread(ScrollDown)"); screen.scroll_active_terminal_down(); } ScreenInstruction::ClearScroll => { - err_ctx.add_call("screen_thread(ClearScroll)"); screen.clear_active_terminal_scroll(); } ScreenInstruction::CloseFocusedPane => { - err_ctx.add_call("screen_thread(CloseFocusedPane)"); screen.close_focused_pane(); } ScreenInstruction::ClosePane(id) => { - err_ctx.add_call("screen_thread(ClosePane)"); screen.close_pane(id); } ScreenInstruction::ToggleActiveTerminalFullscreen => { - err_ctx.add_call("screen_thread(ToggleActiveTerminalFullscreen)"); screen.toggle_active_terminal_fullscreen(); } ScreenInstruction::ApplyLayout((layout, new_pane_pids)) => { - err_ctx.add_call("screen_thread(ApplyLayout)"); screen.apply_layout(layout, new_pane_pids) } ScreenInstruction::Quit => { - err_ctx.add_call("screen_thread(Quit)"); break; } } @@ -427,7 +401,7 @@ pub fn start(mut os_input: Box, opts: Opt) { let listener = std::os::unix::net::UnixListener::bind(MOSAIC_IPC_PIPE) .expect("could not listen on ipc socket"); let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); - err_ctx.add_call("ipc_server(AcceptInput)"); + err_ctx.add_call(ContextType::IPCServer); for stream in listener.incoming() { match stream { @@ -503,7 +477,7 @@ pub fn start(mut os_input: Box, opts: Opt) { .recv() .expect("failed to receive app instruction on channel"); - err_ctx.add_call("main_thread(Exit)"); + err_ctx.add_call(ContextType::App(AppContext::from(&app_instruction))); match app_instruction { AppInstruction::Exit => { let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx.clone())); diff --git a/src/pty_bus.rs b/src/pty_bus.rs index 8a1f3365ea..61956a23d7 100644 --- a/src/pty_bus.rs +++ b/src/pty_bus.rs @@ -9,7 +9,7 @@ use ::std::time::{Duration, Instant}; use ::vte; use std::path::PathBuf; -use crate::errors::ErrorContext; +use crate::errors::{ContextType, ErrorContext}; use crate::layout::Layout; use crate::os_input_output::OsApi; use crate::utils::logging::debug_to_file; @@ -177,7 +177,7 @@ fn stream_terminal_bytes( let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); task::spawn({ async move { - err_ctx.add_call("stream_terminal_bytes(AsyncTask)"); + err_ctx.add_call(ContextType::AsyncTask); let mut vte_parser = vte::Parser::new(); let mut vte_event_sender = VteEventSender::new(pid, send_screen_instructions.clone()); let mut terminal_bytes = ReadFromPid::new(&pid, os_input); From e1d6b2f43f5b05a9f431b8af19c9d89a14783d8b Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Tue, 8 Dec 2020 02:05:29 +0530 Subject: [PATCH 04/10] Use ArrayVec in ErrorContext --- Cargo.lock | 5 +++-- Cargo.toml | 1 + src/errors.rs | 17 +++++++++++------ src/main.rs | 4 ++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c7bf2c6dd..d8d32ec90d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,9 +32,9 @@ checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" [[package]] name = "arrayvec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "async-channel" @@ -861,6 +861,7 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" name = "mosaic" version = "0.1.0" dependencies = [ + "arrayvec", "async-std", "backtrace", "bincode", diff --git a/Cargo.toml b/Cargo.toml index 41dd317531..0c81f3206c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +arrayvec = "0.5.2" backtrace = "0.3.55" bincode = "1.3.1" futures = "0.3.5" diff --git a/src/errors.rs b/src/errors.rs index 28d8f3c462..19be9c5c86 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,11 +1,14 @@ use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; use crate::{AppInstruction, OPENCALLS}; +use arrayvec::ArrayVec; use backtrace::Backtrace; use std::panic::PanicInfo; use std::sync::mpsc::SyncSender; use std::{process, thread}; +const MAX_THREAD_CALL_STACK: usize = 5; + pub fn handle_panic( info: &PanicInfo<'_>, send_app_instructions: &SyncSender<(AppInstruction, ErrorContext)>, @@ -19,7 +22,7 @@ pub fn handle_panic( None => info.payload().downcast_ref::().map(|s| &**s), }; - let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); let backtrace = match (info.location(), msg) { (Some(location), Some(msg)) => format!( @@ -53,20 +56,22 @@ pub fn handle_panic( println!("{}", backtrace); process::exit(1); } else { - let instruction = AppInstruction::Error(backtrace); - err_ctx.add_call(ContextType::App(AppContext::from(&instruction))); - send_app_instructions.send((instruction, err_ctx)).unwrap(); + send_app_instructions + .send((AppInstruction::Error(backtrace), err_ctx)) + .unwrap(); } } #[derive(Clone, Debug)] pub struct ErrorContext { - calls: Vec, + calls: ArrayVec<[ContextType; MAX_THREAD_CALL_STACK]>, } impl ErrorContext { pub fn new() -> Self { - Self { calls: Vec::new() } + Self { + calls: ArrayVec::new(), + } } pub fn add_call(&mut self, call: ContextType) { diff --git a/src/main.rs b/src/main.rs index d06ba7a9ff..3b0dba799a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -485,11 +485,11 @@ pub fn start(mut os_input: Box, opts: Opt) { break; } AppInstruction::Error(backtrace) => { + let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx.clone())); + let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); os_input.unset_raw_mode(0); let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1); println!("{}\n{}", goto_start_of_last_line, backtrace); - let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx.clone())); - let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); for thread_handler in active_threads { let _ = thread_handler.join(); } From 56cf487c700c236fa486172f2c1836f721911810 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Tue, 8 Dec 2020 02:13:48 +0530 Subject: [PATCH 05/10] increase MAX_THREAD_CALL_STACK to 6 --- src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/errors.rs b/src/errors.rs index 19be9c5c86..e94b3b2784 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -7,7 +7,7 @@ use std::panic::PanicInfo; use std::sync::mpsc::SyncSender; use std::{process, thread}; -const MAX_THREAD_CALL_STACK: usize = 5; +const MAX_THREAD_CALL_STACK: usize = 6; pub fn handle_panic( info: &PanicInfo<'_>, From fe97191239008a4ea97a1386aa5cae86098f4f51 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Tue, 8 Dec 2020 11:41:13 +0530 Subject: [PATCH 06/10] Custom implement Debug for ErrorContext ad ContextType and color output --- src/errors.rs | 50 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index e94b3b2784..018d26118c 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -3,6 +3,7 @@ use crate::screen::ScreenInstruction; use crate::{AppInstruction, OPENCALLS}; use arrayvec::ArrayVec; use backtrace::Backtrace; +use std::fmt::{Debug, Error, Formatter}; use std::panic::PanicInfo; use std::sync::mpsc::SyncSender; use std::{process, thread}; @@ -26,29 +27,29 @@ pub fn handle_panic( let backtrace = match (info.location(), msg) { (Some(location), Some(msg)) => format!( - "thread '{}' panicked at '{}': {}:{}\n{:#?}\n{:?}", + "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}': {}:{}\n\u{1b}[0;0m{:?}", + err_ctx, thread, msg, location.file(), location.line(), - err_ctx, backtrace ), (Some(location), None) => format!( - "thread '{}' panicked: {}:{}\n{:#?}\n{:?}", + "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}", + err_ctx, thread, location.file(), location.line(), - err_ctx, backtrace ), (None, Some(msg)) => format!( - "thread '{}' panicked at '{}'\n{:#?}\n{:?}", - thread, msg, err_ctx, backtrace + "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}'\n\u{1b}[0;0m{:?}", + err_ctx, thread, msg, backtrace ), (None, None) => format!( - "thread '{}' panicked\n{:#?}\n{:?}", - thread, err_ctx, backtrace + "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked\n\u{1b}[0;0m{:?}", + err_ctx, thread, backtrace ), }; @@ -62,7 +63,7 @@ pub fn handle_panic( } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct ErrorContext { calls: ArrayVec<[ContextType; MAX_THREAD_CALL_STACK]>, } @@ -80,7 +81,17 @@ impl ErrorContext { } } -#[derive(Debug, Copy, Clone)] +impl Debug for ErrorContext { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + writeln!(f, "Originating Thread(s):")?; + for (index, ctx) in self.calls.iter().enumerate() { + writeln!(f, "\u{1b}[0;0m{}. {:?}", index + 1, ctx)?; + } + Ok(()) + } +} + +#[derive(Copy, Clone)] pub enum ContextType { Screen(ScreenContext), Pty(PtyContext), @@ -90,6 +101,25 @@ pub enum ContextType { AsyncTask, } +impl Debug for ContextType { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let purple = "\u{1b}[1;35m"; + let green = "\u{1b}[0;32m"; + match *self { + ContextType::Screen(c) => write!(f, "{}screen_thread: {}{:?}", purple, green, c), + ContextType::Pty(c) => write!(f, "{}pty_thread: {}{:?}", purple, green, c), + ContextType::App(c) => write!(f, "{}main_thread: {}{:?}", purple, green, c), + ContextType::IPCServer => write!(f, "{}ipc_server: {}AcceptInput", purple, green), + ContextType::StdinHandler => { + write!(f, "{}stdin_handler_thread: {}AcceptInput", purple, green) + } + ContextType::AsyncTask => { + write!(f, "{}stream_terminal_bytes: {}AsyncTask", purple, green) + } + } + } +} + #[derive(Debug, Clone, Copy)] pub enum ScreenContext { HandlePtyEvent, From cb99090c94b13d1bbab3844f8a1bb8615845e6cd Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Tue, 8 Dec 2020 11:44:52 +0530 Subject: [PATCH 07/10] Use os_input instead of println!() --- src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3b0dba799a..c75d8bb47a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -489,7 +489,11 @@ pub fn start(mut os_input: Box, opts: Opt) { let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); os_input.unset_raw_mode(0); let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1); - println!("{}\n{}", goto_start_of_last_line, backtrace); + let error = format!("{}\n{}", goto_start_of_last_line, backtrace); + let _ = os_input + .get_stdout_writer() + .write(error.as_bytes()) + .unwrap(); for thread_handler in active_threads { let _ = thread_handler.join(); } From fc88c48a4938618979540c1bf2ace002383671dc Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Tue, 8 Dec 2020 20:55:16 +0530 Subject: [PATCH 08/10] Use array instead of ArrayVec and some cleanup --- Cargo.lock | 1 - Cargo.toml | 1 - src/errors.rs | 31 +++++++++++++++++--------- src/input.rs | 60 ++++++++++++++++++++------------------------------ src/main.rs | 17 ++++++-------- src/pty_bus.rs | 34 ++++++++++++++-------------- src/screen.rs | 10 ++++----- 7 files changed, 73 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8d32ec90d..e1508ff6bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -861,7 +861,6 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" name = "mosaic" version = "0.1.0" dependencies = [ - "arrayvec", "async-std", "backtrace", "bincode", diff --git a/Cargo.toml b/Cargo.toml index 0c81f3206c..41dd317531 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -arrayvec = "0.5.2" backtrace = "0.3.55" bincode = "1.3.1" futures = "0.3.5" diff --git a/src/errors.rs b/src/errors.rs index 018d26118c..2a615d8383 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,7 +1,6 @@ use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; use crate::{AppInstruction, OPENCALLS}; -use arrayvec::ArrayVec; use backtrace::Backtrace; use std::fmt::{Debug, Error, Formatter}; use std::panic::PanicInfo; @@ -23,7 +22,7 @@ pub fn handle_panic( None => info.payload().downcast_ref::().map(|s| &**s), }; - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); let backtrace = match (info.location(), msg) { (Some(location), Some(msg)) => format!( @@ -63,21 +62,26 @@ pub fn handle_panic( } } -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct ErrorContext { - calls: ArrayVec<[ContextType; MAX_THREAD_CALL_STACK]>, + calls: [ContextType; MAX_THREAD_CALL_STACK], } impl ErrorContext { pub fn new() -> Self { Self { - calls: ArrayVec::new(), + calls: [ContextType::Empty; MAX_THREAD_CALL_STACK], } } pub fn add_call(&mut self, call: ContextType) { - self.calls.push(call); - OPENCALLS.with(|ctx| *ctx.borrow_mut() = self.clone()); + for ctx in self.calls.iter_mut() { + if *ctx == ContextType::Empty { + *ctx = call; + break; + } + } + OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self); } } @@ -85,13 +89,16 @@ impl Debug for ErrorContext { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { writeln!(f, "Originating Thread(s):")?; for (index, ctx) in self.calls.iter().enumerate() { + if *ctx == ContextType::Empty { + break; + } writeln!(f, "\u{1b}[0;0m{}. {:?}", index + 1, ctx)?; } Ok(()) } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub enum ContextType { Screen(ScreenContext), Pty(PtyContext), @@ -99,6 +106,7 @@ pub enum ContextType { IPCServer, StdinHandler, AsyncTask, + Empty, } impl Debug for ContextType { @@ -116,11 +124,12 @@ impl Debug for ContextType { ContextType::AsyncTask => { write!(f, "{}stream_terminal_bytes: {}AsyncTask", purple, green) } + ContextType::Empty => write!(f, ""), } } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum ScreenContext { HandlePtyEvent, Render, @@ -179,7 +188,7 @@ impl From<&ScreenInstruction> for ScreenContext { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum PtyContext { SpawnTerminal, SpawnTerminalVertically, @@ -200,7 +209,7 @@ impl From<&PtyInstruction> for PtyContext { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum AppContext { Exit, Error, diff --git a/src/input.rs b/src/input.rs index 67c984db1e..368b7a89e9 100644 --- a/src/input.rs +++ b/src/input.rs @@ -37,7 +37,7 @@ impl InputHandler { /// Main event loop fn get_input(&mut self) { - let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::StdinHandler); loop { match self.mode { @@ -55,7 +55,7 @@ impl InputHandler { /// Read input to the terminal (or switch to command mode) fn read_normal_mode(&mut self) { assert_eq!(self.mode, InputMode::Normal); - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); loop { let stdin_buffer = self.os_input.read_from_stdin(); @@ -67,13 +67,10 @@ impl InputHandler { } _ => { self.send_screen_instructions - .send((ScreenInstruction::ClearScroll, err_ctx.clone())) + .send((ScreenInstruction::ClearScroll, err_ctx)) .unwrap(); self.send_screen_instructions - .send(( - ScreenInstruction::WriteCharacter(stdin_buffer), - err_ctx.clone(), - )) + .send((ScreenInstruction::WriteCharacter(stdin_buffer), err_ctx)) .unwrap(); } } @@ -88,7 +85,7 @@ impl InputHandler { } else { assert_eq!(self.mode, InputMode::Command); } - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); loop { let stdin_buffer = self.os_input.read_from_stdin(); @@ -117,38 +114,38 @@ impl InputHandler { [106] => { // j self.send_screen_instructions - .send((ScreenInstruction::ResizeDown, err_ctx.clone())) + .send((ScreenInstruction::ResizeDown, err_ctx)) .unwrap(); } [107] => { // k self.send_screen_instructions - .send((ScreenInstruction::ResizeUp, err_ctx.clone())) + .send((ScreenInstruction::ResizeUp, err_ctx)) .unwrap(); } [112] => { // p self.send_screen_instructions - .send((ScreenInstruction::MoveFocus, err_ctx.clone())) + .send((ScreenInstruction::MoveFocus, err_ctx)) .unwrap(); } [104] => { // h self.send_screen_instructions - .send((ScreenInstruction::ResizeLeft, err_ctx.clone())) + .send((ScreenInstruction::ResizeLeft, err_ctx)) .unwrap(); } [108] => { // l self.send_screen_instructions - .send((ScreenInstruction::ResizeRight, err_ctx.clone())) + .send((ScreenInstruction::ResizeRight, err_ctx)) .unwrap(); } [122] => { // z self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send((PtyInstruction::SpawnTerminal(None), err_ctx.clone())) + .send((PtyInstruction::SpawnTerminal(None), err_ctx)) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -156,10 +153,7 @@ impl InputHandler { // n self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send(( - PtyInstruction::SpawnTerminalVertically(None), - err_ctx.clone(), - )) + .send((PtyInstruction::SpawnTerminalVertically(None), err_ctx)) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -167,10 +161,7 @@ impl InputHandler { // b self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send(( - PtyInstruction::SpawnTerminalHorizontally(None), - err_ctx.clone(), - )) + .send((PtyInstruction::SpawnTerminalHorizontally(None), err_ctx)) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -182,54 +173,51 @@ impl InputHandler { [27, 91, 53, 126] => { // PgUp self.send_screen_instructions - .send((ScreenInstruction::ScrollUp, err_ctx.clone())) + .send((ScreenInstruction::ScrollUp, err_ctx)) .unwrap(); } [27, 91, 54, 126] => { // PgDown self.send_screen_instructions - .send((ScreenInstruction::ScrollDown, err_ctx.clone())) + .send((ScreenInstruction::ScrollDown, err_ctx)) .unwrap(); } [120] => { // x self.command_is_executing.closing_pane(); self.send_screen_instructions - .send((ScreenInstruction::CloseFocusedPane, err_ctx.clone())) + .send((ScreenInstruction::CloseFocusedPane, err_ctx)) .unwrap(); self.command_is_executing.wait_until_pane_is_closed(); } [101] => { // e self.send_screen_instructions - .send(( - ScreenInstruction::ToggleActiveTerminalFullscreen, - err_ctx.clone(), - )) + .send((ScreenInstruction::ToggleActiveTerminalFullscreen, err_ctx)) .unwrap(); } [121] => { // y self.send_screen_instructions - .send((ScreenInstruction::MoveFocusLeft, err_ctx.clone())) + .send((ScreenInstruction::MoveFocusLeft, err_ctx)) .unwrap() } [117] => { // u self.send_screen_instructions - .send((ScreenInstruction::MoveFocusDown, err_ctx.clone())) + .send((ScreenInstruction::MoveFocusDown, err_ctx)) .unwrap() } [105] => { // i self.send_screen_instructions - .send((ScreenInstruction::MoveFocusUp, err_ctx.clone())) + .send((ScreenInstruction::MoveFocusUp, err_ctx)) .unwrap() } [111] => { // o self.send_screen_instructions - .send((ScreenInstruction::MoveFocusRight, err_ctx.clone())) + .send((ScreenInstruction::MoveFocusRight, err_ctx)) .unwrap() } //@@@khs26 Write this to the powerbar? @@ -246,12 +234,12 @@ impl InputHandler { /// Routine to be called when the input handler exits (at the moment this is the /// same as quitting mosaic) fn exit(&mut self) { - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions - .send((ScreenInstruction::Quit, err_ctx.clone())) + .send((ScreenInstruction::Quit, err_ctx)) .unwrap(); self.send_pty_instructions - .send((PtyInstruction::Quit, err_ctx.clone())) + .send((PtyInstruction::Quit, err_ctx)) .unwrap(); self.send_app_instructions .send((AppInstruction::Exit, err_ctx)) diff --git a/src/main.rs b/src/main.rs index c75d8bb47a..3ef25e900b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -400,7 +400,7 @@ pub fn start(mut os_input: Box, opts: Opt) { std::fs::remove_file(MOSAIC_IPC_PIPE).ok(); let listener = std::os::unix::net::UnixListener::bind(MOSAIC_IPC_PIPE) .expect("could not listen on ipc socket"); - let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::IPCServer); for stream in listener.incoming() { @@ -416,17 +416,14 @@ pub fn start(mut os_input: Box, opts: Opt) { ApiCommand::OpenFile(file_name) => { let path = PathBuf::from(file_name); send_pty_instructions - .send(( - PtyInstruction::SpawnTerminal(Some(path)), - err_ctx.clone(), - )) + .send((PtyInstruction::SpawnTerminal(Some(path)), err_ctx)) .unwrap(); } ApiCommand::SplitHorizontally => { send_pty_instructions .send(( PtyInstruction::SpawnTerminalHorizontally(None), - err_ctx.clone(), + err_ctx, )) .unwrap(); } @@ -434,13 +431,13 @@ pub fn start(mut os_input: Box, opts: Opt) { send_pty_instructions .send(( PtyInstruction::SpawnTerminalVertically(None), - err_ctx.clone(), + err_ctx, )) .unwrap(); } ApiCommand::MoveFocus => { send_screen_instructions - .send((ScreenInstruction::MoveFocus, err_ctx.clone())) + .send((ScreenInstruction::MoveFocus, err_ctx)) .unwrap(); } } @@ -480,12 +477,12 @@ pub fn start(mut os_input: Box, opts: Opt) { err_ctx.add_call(ContextType::App(AppContext::from(&app_instruction))); match app_instruction { AppInstruction::Exit => { - let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx.clone())); + let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx)); let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); break; } AppInstruction::Error(backtrace) => { - let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx.clone())); + let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx)); let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); os_input.unset_raw_mode(0); let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1); diff --git a/src/pty_bus.rs b/src/pty_bus.rs index 61956a23d7..e029a687a3 100644 --- a/src/pty_bus.rs +++ b/src/pty_bus.rs @@ -85,7 +85,7 @@ impl VteEventSender { VteEventSender { id, sender, - err_ctx: OPENCALLS.with(|ctx| ctx.borrow().clone()), + err_ctx: OPENCALLS.with(|ctx| *ctx.borrow()), } } } @@ -94,13 +94,13 @@ impl vte::Perform for VteEventSender { fn print(&mut self, c: char) { let _ = self.sender.send(( ScreenInstruction::Pty(self.id, VteEvent::Print(c)), - self.err_ctx.clone(), + self.err_ctx, )); } fn execute(&mut self, byte: u8) { let _ = self.sender.send(( ScreenInstruction::Pty(self.id, VteEvent::Execute(byte)), - self.err_ctx.clone(), + self.err_ctx, )); } @@ -109,20 +109,20 @@ impl vte::Perform for VteEventSender { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::Hook(params, intermediates, ignore, c)); - let _ = self.sender.send((instruction, self.err_ctx.clone())); + let _ = self.sender.send((instruction, self.err_ctx)); } fn put(&mut self, byte: u8) { let _ = self.sender.send(( ScreenInstruction::Pty(self.id, VteEvent::Put(byte)), - self.err_ctx.clone(), + self.err_ctx, )); } fn unhook(&mut self) { let _ = self.sender.send(( ScreenInstruction::Pty(self.id, VteEvent::Unhook), - self.err_ctx.clone(), + self.err_ctx, )); } @@ -130,7 +130,7 @@ impl vte::Perform for VteEventSender { let params = params.iter().map(|p| p.to_vec()).collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::OscDispatch(params, bell_terminated)); - let _ = self.sender.send((instruction, self.err_ctx.clone())); + let _ = self.sender.send((instruction, self.err_ctx)); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { @@ -140,14 +140,14 @@ impl vte::Perform for VteEventSender { self.id, VteEvent::CsiDispatch(params, intermediates, ignore, c), ); - let _ = self.sender.send((instruction, self.err_ctx.clone())); + let _ = self.sender.send((instruction, self.err_ctx)); } fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::EscDispatch(intermediates, ignore, byte)); - let _ = self.sender.send((instruction, self.err_ctx.clone())); + let _ = self.sender.send((instruction, self.err_ctx)); } } @@ -174,7 +174,7 @@ fn stream_terminal_bytes( os_input: Box, debug: bool, ) { - let mut err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); task::spawn({ async move { err_ctx.add_call(ContextType::AsyncTask); @@ -206,7 +206,7 @@ fn stream_terminal_bytes( if receive_time.elapsed() > max_render_pause { pending_render = false; send_screen_instructions - .send((ScreenInstruction::Render, err_ctx.clone())) + .send((ScreenInstruction::Render, err_ctx)) .unwrap(); last_byte_receive_time = Some(Instant::now()); } else { @@ -222,7 +222,7 @@ fn stream_terminal_bytes( if pending_render { pending_render = false; send_screen_instructions - .send((ScreenInstruction::Render, err_ctx.clone())) + .send((ScreenInstruction::Render, err_ctx)) .unwrap(); } last_byte_receive_time = None; @@ -230,7 +230,7 @@ fn stream_terminal_bytes( } } send_screen_instructions - .send((ScreenInstruction::Render, err_ctx.clone())) + .send((ScreenInstruction::Render, err_ctx)) .unwrap(); #[cfg(not(test))] // this is a little hacky, and is because the tests end the file as soon as @@ -268,7 +268,7 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions .send((ScreenInstruction::NewPane(pid_primary), err_ctx)) .unwrap(); @@ -283,7 +283,7 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions .send((ScreenInstruction::VerticalSplit(pid_primary), err_ctx)) .unwrap(); @@ -298,7 +298,7 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions .send((ScreenInstruction::HorizontalSplit(pid_primary), err_ctx)) .unwrap(); @@ -311,7 +311,7 @@ impl PtyBus { self.id_to_child_pid.insert(pid_primary, pid_secondary); new_pane_pids.push(pid_primary); } - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions .send(( ScreenInstruction::ApplyLayout((layout, new_pane_pids.clone())), diff --git a/src/screen.rs b/src/screen.rs index dfa6192020..48af3a8779 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -164,7 +164,7 @@ impl Screen { // this is a bit of a hack and happens because we don't have any central location that // can query the screen as to how many panes it needs to create a layout // fixing this will require a bit of an architecture change - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_pty_instructions .send((PtyInstruction::ClosePane(*unused_pid), err_ctx)) .unwrap(); @@ -1533,11 +1533,11 @@ impl Screen { fn close_down_to_max_terminals(&mut self) { if let Some(max_panes) = self.max_panes { if self.terminals.len() >= max_panes { - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); for _ in max_panes..=self.terminals.len() { let first_pid = *self.terminals.iter().next().unwrap().0; self.send_pty_instructions - .send((PtyInstruction::ClosePane(first_pid), err_ctx.clone())) + .send((PtyInstruction::ClosePane(first_pid), err_ctx)) .unwrap(); self.close_pane_without_rerender(first_pid); // TODO: do not render yet } @@ -1592,7 +1592,7 @@ impl Screen { self.terminals.remove(&id); if self.terminals.is_empty() { self.active_terminal = None; - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); let _ = self .send_app_instructions .send((AppInstruction::Exit, err_ctx)); @@ -1602,7 +1602,7 @@ impl Screen { pub fn close_focused_pane(&mut self) { if let Some(active_terminal_id) = self.get_active_terminal_id() { self.close_pane(active_terminal_id); - let err_ctx: ErrorContext = OPENCALLS.with(|ctx| ctx.borrow().clone()); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_pty_instructions .send((PtyInstruction::ClosePane(active_terminal_id), err_ctx)) .unwrap(); From b6af3bd1eb531b3454984a979f4e6e57878b735a Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Wed, 9 Dec 2020 16:59:47 +0530 Subject: [PATCH 09/10] Introduce SenderWithContext --- src/errors.rs | 23 +++++++------- src/input.rs | 72 +++++++++++++++++++++---------------------- src/main.rs | 75 ++++++++++++++++++++++++++++++++++---------- src/pty_bus.rs | 84 ++++++++++++++++++++++---------------------------- src/screen.rs | 26 ++++++---------- 5 files changed, 150 insertions(+), 130 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 2a615d8383..8478969dfb 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,17 +1,16 @@ use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; -use crate::{AppInstruction, OPENCALLS}; +use crate::{AppInstruction, SenderWithContext, OPENCALLS}; use backtrace::Backtrace; -use std::fmt::{Debug, Error, Formatter}; +use std::fmt::{Display, Error, Formatter}; use std::panic::PanicInfo; -use std::sync::mpsc::SyncSender; use std::{process, thread}; const MAX_THREAD_CALL_STACK: usize = 6; pub fn handle_panic( info: &PanicInfo<'_>, - send_app_instructions: &SyncSender<(AppInstruction, ErrorContext)>, + send_app_instructions: &SenderWithContext, ) { let backtrace = Backtrace::new(); let thread = thread::current(); @@ -26,7 +25,7 @@ pub fn handle_panic( let backtrace = match (info.location(), msg) { (Some(location), Some(msg)) => format!( - "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}': {}:{}\n\u{1b}[0;0m{:?}", + "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}': {}:{}\n\u{1b}[0;0m{:?}", err_ctx, thread, msg, @@ -35,7 +34,7 @@ pub fn handle_panic( backtrace ), (Some(location), None) => format!( - "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}", + "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}", err_ctx, thread, location.file(), @@ -43,11 +42,11 @@ pub fn handle_panic( backtrace ), (None, Some(msg)) => format!( - "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}'\n\u{1b}[0;0m{:?}", + "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}'\n\u{1b}[0;0m{:?}", err_ctx, thread, msg, backtrace ), (None, None) => format!( - "{:#?}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked\n\u{1b}[0;0m{:?}", + "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked\n\u{1b}[0;0m{:?}", err_ctx, thread, backtrace ), }; @@ -57,7 +56,7 @@ pub fn handle_panic( process::exit(1); } else { send_app_instructions - .send((AppInstruction::Error(backtrace), err_ctx)) + .send(AppInstruction::Error(backtrace)) .unwrap(); } } @@ -85,14 +84,14 @@ impl ErrorContext { } } -impl Debug for ErrorContext { +impl Display for ErrorContext { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { writeln!(f, "Originating Thread(s):")?; for (index, ctx) in self.calls.iter().enumerate() { if *ctx == ContextType::Empty { break; } - writeln!(f, "\u{1b}[0;0m{}. {:?}", index + 1, ctx)?; + writeln!(f, "\u{1b}[0;0m{}. {}", index + 1, ctx)?; } Ok(()) } @@ -109,7 +108,7 @@ pub enum ContextType { Empty, } -impl Debug for ContextType { +impl Display for ContextType { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { let purple = "\u{1b}[1;35m"; let green = "\u{1b}[0;32m"; diff --git a/src/input.rs b/src/input.rs index 368b7a89e9..6d82f4f921 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,29 +1,27 @@ /// Module for handling input -use std::sync::mpsc::{Sender, SyncSender}; - -use crate::errors::{ContextType, ErrorContext}; +use crate::errors::ContextType; use crate::os_input_output::OsApi; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; use crate::CommandIsExecuting; -use crate::{AppInstruction, OPENCALLS}; +use crate::{AppInstruction, SenderWithContext, OPENCALLS}; struct InputHandler { mode: InputMode, os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, - send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, - send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, + send_screen_instructions: SenderWithContext, + send_pty_instructions: SenderWithContext, + send_app_instructions: SenderWithContext, } impl InputHandler { fn new( os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, - send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, - send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, + send_screen_instructions: SenderWithContext, + send_pty_instructions: SenderWithContext, + send_app_instructions: SenderWithContext, ) -> Self { InputHandler { mode: InputMode::Normal, @@ -39,6 +37,9 @@ impl InputHandler { fn get_input(&mut self) { let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::StdinHandler); + self.send_pty_instructions.update(err_ctx); + self.send_app_instructions.update(err_ctx); + self.send_screen_instructions.update(err_ctx); loop { match self.mode { InputMode::Normal => self.read_normal_mode(), @@ -55,7 +56,6 @@ impl InputHandler { /// Read input to the terminal (or switch to command mode) fn read_normal_mode(&mut self) { assert_eq!(self.mode, InputMode::Normal); - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); loop { let stdin_buffer = self.os_input.read_from_stdin(); @@ -67,10 +67,10 @@ impl InputHandler { } _ => { self.send_screen_instructions - .send((ScreenInstruction::ClearScroll, err_ctx)) + .send(ScreenInstruction::ClearScroll) .unwrap(); self.send_screen_instructions - .send((ScreenInstruction::WriteCharacter(stdin_buffer), err_ctx)) + .send(ScreenInstruction::WriteCharacter(stdin_buffer)) .unwrap(); } } @@ -85,7 +85,6 @@ impl InputHandler { } else { assert_eq!(self.mode, InputMode::Command); } - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); loop { let stdin_buffer = self.os_input.read_from_stdin(); @@ -114,38 +113,38 @@ impl InputHandler { [106] => { // j self.send_screen_instructions - .send((ScreenInstruction::ResizeDown, err_ctx)) + .send(ScreenInstruction::ResizeDown) .unwrap(); } [107] => { // k self.send_screen_instructions - .send((ScreenInstruction::ResizeUp, err_ctx)) + .send(ScreenInstruction::ResizeUp) .unwrap(); } [112] => { // p self.send_screen_instructions - .send((ScreenInstruction::MoveFocus, err_ctx)) + .send(ScreenInstruction::MoveFocus) .unwrap(); } [104] => { // h self.send_screen_instructions - .send((ScreenInstruction::ResizeLeft, err_ctx)) + .send(ScreenInstruction::ResizeLeft) .unwrap(); } [108] => { // l self.send_screen_instructions - .send((ScreenInstruction::ResizeRight, err_ctx)) + .send(ScreenInstruction::ResizeRight) .unwrap(); } [122] => { // z self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send((PtyInstruction::SpawnTerminal(None), err_ctx)) + .send(PtyInstruction::SpawnTerminal(None)) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -153,7 +152,7 @@ impl InputHandler { // n self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send((PtyInstruction::SpawnTerminalVertically(None), err_ctx)) + .send(PtyInstruction::SpawnTerminalVertically(None)) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -161,7 +160,7 @@ impl InputHandler { // b self.command_is_executing.opening_new_pane(); self.send_pty_instructions - .send((PtyInstruction::SpawnTerminalHorizontally(None), err_ctx)) + .send(PtyInstruction::SpawnTerminalHorizontally(None)) .unwrap(); self.command_is_executing.wait_until_new_pane_is_opened(); } @@ -173,51 +172,51 @@ impl InputHandler { [27, 91, 53, 126] => { // PgUp self.send_screen_instructions - .send((ScreenInstruction::ScrollUp, err_ctx)) + .send(ScreenInstruction::ScrollUp) .unwrap(); } [27, 91, 54, 126] => { // PgDown self.send_screen_instructions - .send((ScreenInstruction::ScrollDown, err_ctx)) + .send(ScreenInstruction::ScrollDown) .unwrap(); } [120] => { // x self.command_is_executing.closing_pane(); self.send_screen_instructions - .send((ScreenInstruction::CloseFocusedPane, err_ctx)) + .send(ScreenInstruction::CloseFocusedPane) .unwrap(); self.command_is_executing.wait_until_pane_is_closed(); } [101] => { // e self.send_screen_instructions - .send((ScreenInstruction::ToggleActiveTerminalFullscreen, err_ctx)) + .send(ScreenInstruction::ToggleActiveTerminalFullscreen) .unwrap(); } [121] => { // y self.send_screen_instructions - .send((ScreenInstruction::MoveFocusLeft, err_ctx)) + .send(ScreenInstruction::MoveFocusLeft) .unwrap() } [117] => { // u self.send_screen_instructions - .send((ScreenInstruction::MoveFocusDown, err_ctx)) + .send(ScreenInstruction::MoveFocusDown) .unwrap() } [105] => { // i self.send_screen_instructions - .send((ScreenInstruction::MoveFocusUp, err_ctx)) + .send(ScreenInstruction::MoveFocusUp) .unwrap() } [111] => { // o self.send_screen_instructions - .send((ScreenInstruction::MoveFocusRight, err_ctx)) + .send(ScreenInstruction::MoveFocusRight) .unwrap() } //@@@khs26 Write this to the powerbar? @@ -234,15 +233,14 @@ impl InputHandler { /// Routine to be called when the input handler exits (at the moment this is the /// same as quitting mosaic) fn exit(&mut self) { - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions - .send((ScreenInstruction::Quit, err_ctx)) + .send(ScreenInstruction::Quit) .unwrap(); self.send_pty_instructions - .send((PtyInstruction::Quit, err_ctx)) + .send(PtyInstruction::Quit) .unwrap(); self.send_app_instructions - .send((AppInstruction::Exit, err_ctx)) + .send(AppInstruction::Exit) .unwrap(); } } @@ -269,9 +267,9 @@ pub enum InputMode { pub fn input_loop( os_input: Box, command_is_executing: CommandIsExecuting, - send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, - send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, - send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, + send_screen_instructions: SenderWithContext, + send_pty_instructions: SenderWithContext, + send_app_instructions: SenderWithContext, ) { let _handler = InputHandler::new( os_input, diff --git a/src/main.rs b/src/main.rs index 3ef25e900b..27deb0933a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ mod utils; use std::io::Write; use std::os::unix::net::UnixStream; use std::path::PathBuf; -use std::sync::mpsc::{channel, sync_channel, Receiver, Sender, SyncSender}; +use std::sync::mpsc::{channel, sync_channel, Receiver, SendError, Sender, SyncSender}; use std::thread; use serde::{Deserialize, Serialize}; @@ -44,6 +44,38 @@ enum ApiCommand { MoveFocus, } +#[derive(Clone)] +enum SenderType { + Sender(Sender<(T, ErrorContext)>), + SyncSender(SyncSender<(T, ErrorContext)>), +} + +#[derive(Clone)] +pub struct SenderWithContext { + err_ctx: ErrorContext, + sender: SenderType, +} + +impl SenderWithContext { + fn new(err_ctx: ErrorContext, sender: SenderType) -> Self { + Self { err_ctx, sender } + } + + pub fn send(&self, event: T) -> Result<(), SendError<(T, ErrorContext)>> { + match self.sender { + SenderType::Sender(ref s) => s.send((event, self.err_ctx)), + SenderType::SyncSender(ref s) => s.send((event, self.err_ctx)), + } + } + + pub fn update(&mut self, new_ctx: ErrorContext) { + self.err_ctx = new_ctx; + } +} + +unsafe impl Send for SenderWithContext {} +unsafe impl Sync for SenderWithContext {} + #[derive(StructOpt, Debug, Default)] #[structopt(name = "mosaic")] pub struct Opt { @@ -98,6 +130,7 @@ pub fn main() { } } +#[derive(Clone)] pub enum AppInstruction { Exit, Error(String), @@ -114,14 +147,21 @@ pub fn start(mut os_input: Box, opts: Opt) { Sender<(ScreenInstruction, ErrorContext)>, Receiver<(ScreenInstruction, ErrorContext)>, ) = channel(); + let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); + let mut send_screen_instructions = + SenderWithContext::new(err_ctx, SenderType::Sender(send_screen_instructions)); let (send_pty_instructions, receive_pty_instructions): ( Sender<(PtyInstruction, ErrorContext)>, Receiver<(PtyInstruction, ErrorContext)>, ) = channel(); + let mut send_pty_instructions = + SenderWithContext::new(err_ctx, SenderType::Sender(send_pty_instructions)); let (send_app_instructions, receive_app_instructions): ( SyncSender<(AppInstruction, ErrorContext)>, Receiver<(AppInstruction, ErrorContext)>, ) = sync_channel(0); + let send_app_instructions = + SenderWithContext::new(err_ctx, SenderType::SyncSender(send_app_instructions)); let mut screen = Screen::new( receive_screen_instructions, send_pty_instructions.clone(), @@ -165,6 +205,7 @@ pub fn start(mut os_input: Box, opts: Opt) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Pty(PtyContext::from(&event))); + pty_bus.send_screen_instructions.update(err_ctx); match event { PtyInstruction::SpawnTerminal(file_to_open) => { pty_bus.spawn_terminal(file_to_open); @@ -200,6 +241,8 @@ pub fn start(mut os_input: Box, opts: Opt) { .recv() .expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event))); + screen.send_app_instructions.update(err_ctx); + screen.send_pty_instructions.update(err_ctx); match event { ScreenInstruction::Pty(pid, vte_event) => { screen.handle_pty_event(pid, vte_event); @@ -394,14 +437,16 @@ pub fn start(mut os_input: Box, opts: Opt) { .name("ipc_server".to_string()) .spawn({ use std::io::Read; - let send_pty_instructions = send_pty_instructions.clone(); - let send_screen_instructions = send_screen_instructions.clone(); + let mut send_pty_instructions = send_pty_instructions.clone(); + let mut send_screen_instructions = send_screen_instructions.clone(); move || { std::fs::remove_file(MOSAIC_IPC_PIPE).ok(); let listener = std::os::unix::net::UnixListener::bind(MOSAIC_IPC_PIPE) .expect("could not listen on ipc socket"); let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::IPCServer); + send_pty_instructions.update(err_ctx); + send_screen_instructions.update(err_ctx); for stream in listener.incoming() { match stream { @@ -416,28 +461,22 @@ pub fn start(mut os_input: Box, opts: Opt) { ApiCommand::OpenFile(file_name) => { let path = PathBuf::from(file_name); send_pty_instructions - .send((PtyInstruction::SpawnTerminal(Some(path)), err_ctx)) + .send(PtyInstruction::SpawnTerminal(Some(path))) .unwrap(); } ApiCommand::SplitHorizontally => { send_pty_instructions - .send(( - PtyInstruction::SpawnTerminalHorizontally(None), - err_ctx, - )) + .send(PtyInstruction::SpawnTerminalHorizontally(None)) .unwrap(); } ApiCommand::SplitVertically => { send_pty_instructions - .send(( - PtyInstruction::SpawnTerminalVertically(None), - err_ctx, - )) + .send(PtyInstruction::SpawnTerminalVertically(None)) .unwrap(); } ApiCommand::MoveFocus => { send_screen_instructions - .send((ScreenInstruction::MoveFocus, err_ctx)) + .send(ScreenInstruction::MoveFocus) .unwrap(); } } @@ -475,15 +514,17 @@ pub fn start(mut os_input: Box, opts: Opt) { .expect("failed to receive app instruction on channel"); err_ctx.add_call(ContextType::App(AppContext::from(&app_instruction))); + send_screen_instructions.update(err_ctx); + send_pty_instructions.update(err_ctx); match app_instruction { AppInstruction::Exit => { - let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx)); - let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); + let _ = send_screen_instructions.send(ScreenInstruction::Quit); + let _ = send_pty_instructions.send(PtyInstruction::Quit); break; } AppInstruction::Error(backtrace) => { - let _ = send_screen_instructions.send((ScreenInstruction::Quit, err_ctx)); - let _ = send_pty_instructions.send((PtyInstruction::Quit, err_ctx)); + let _ = send_screen_instructions.send(ScreenInstruction::Quit); + let _ = send_pty_instructions.send(PtyInstruction::Quit); os_input.unset_raw_mode(0); let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1); let error = format!("{}\n{}", goto_start_of_last_line, backtrace); diff --git a/src/pty_bus.rs b/src/pty_bus.rs index e029a687a3..758271c355 100644 --- a/src/pty_bus.rs +++ b/src/pty_bus.rs @@ -4,7 +4,7 @@ use ::async_std::task::*; use ::std::collections::HashMap; use ::std::os::unix::io::RawFd; use ::std::pin::*; -use ::std::sync::mpsc::{Receiver, Sender}; +use ::std::sync::mpsc::Receiver; use ::std::time::{Duration, Instant}; use ::vte; use std::path::PathBuf; @@ -13,7 +13,7 @@ use crate::errors::{ContextType, ErrorContext}; use crate::layout::Layout; use crate::os_input_output::OsApi; use crate::utils::logging::debug_to_file; -use crate::{ScreenInstruction, OPENCALLS}; +use crate::{ScreenInstruction, SenderWithContext, OPENCALLS}; pub struct ReadFromPid { pid: RawFd, @@ -76,32 +76,25 @@ pub enum VteEvent { struct VteEventSender { id: RawFd, - sender: Sender<(ScreenInstruction, ErrorContext)>, - err_ctx: ErrorContext, + sender: SenderWithContext, } impl VteEventSender { - pub fn new(id: RawFd, sender: Sender<(ScreenInstruction, ErrorContext)>) -> Self { - VteEventSender { - id, - sender, - err_ctx: OPENCALLS.with(|ctx| *ctx.borrow()), - } + pub fn new(id: RawFd, sender: SenderWithContext) -> Self { + VteEventSender { id, sender } } } impl vte::Perform for VteEventSender { fn print(&mut self, c: char) { - let _ = self.sender.send(( - ScreenInstruction::Pty(self.id, VteEvent::Print(c)), - self.err_ctx, - )); + let _ = self + .sender + .send(ScreenInstruction::Pty(self.id, VteEvent::Print(c))); } fn execute(&mut self, byte: u8) { - let _ = self.sender.send(( - ScreenInstruction::Pty(self.id, VteEvent::Execute(byte)), - self.err_ctx, - )); + let _ = self + .sender + .send(ScreenInstruction::Pty(self.id, VteEvent::Execute(byte))); } fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { @@ -109,28 +102,26 @@ impl vte::Perform for VteEventSender { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::Hook(params, intermediates, ignore, c)); - let _ = self.sender.send((instruction, self.err_ctx)); + let _ = self.sender.send(instruction); } fn put(&mut self, byte: u8) { - let _ = self.sender.send(( - ScreenInstruction::Pty(self.id, VteEvent::Put(byte)), - self.err_ctx, - )); + let _ = self + .sender + .send(ScreenInstruction::Pty(self.id, VteEvent::Put(byte))); } fn unhook(&mut self) { - let _ = self.sender.send(( - ScreenInstruction::Pty(self.id, VteEvent::Unhook), - self.err_ctx, - )); + let _ = self + .sender + .send(ScreenInstruction::Pty(self.id, VteEvent::Unhook)); } fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { let params = params.iter().map(|p| p.to_vec()).collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::OscDispatch(params, bell_terminated)); - let _ = self.sender.send((instruction, self.err_ctx)); + let _ = self.sender.send(instruction); } fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { @@ -140,14 +131,14 @@ impl vte::Perform for VteEventSender { self.id, VteEvent::CsiDispatch(params, intermediates, ignore, c), ); - let _ = self.sender.send((instruction, self.err_ctx)); + let _ = self.sender.send(instruction); } fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { let intermediates = intermediates.iter().copied().collect(); let instruction = ScreenInstruction::Pty(self.id, VteEvent::EscDispatch(intermediates, ignore, byte)); - let _ = self.sender.send((instruction, self.err_ctx)); + let _ = self.sender.send(instruction); } } @@ -161,7 +152,7 @@ pub enum PtyInstruction { } pub struct PtyBus { - pub send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, + pub send_screen_instructions: SenderWithContext, pub receive_pty_instructions: Receiver<(PtyInstruction, ErrorContext)>, pub id_to_child_pid: HashMap, os_input: Box, @@ -170,7 +161,7 @@ pub struct PtyBus { fn stream_terminal_bytes( pid: RawFd, - send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, + mut send_screen_instructions: SenderWithContext, os_input: Box, debug: bool, ) { @@ -178,6 +169,7 @@ fn stream_terminal_bytes( task::spawn({ async move { err_ctx.add_call(ContextType::AsyncTask); + send_screen_instructions.update(err_ctx); let mut vte_parser = vte::Parser::new(); let mut vte_event_sender = VteEventSender::new(pid, send_screen_instructions.clone()); let mut terminal_bytes = ReadFromPid::new(&pid, os_input); @@ -206,7 +198,7 @@ fn stream_terminal_bytes( if receive_time.elapsed() > max_render_pause { pending_render = false; send_screen_instructions - .send((ScreenInstruction::Render, err_ctx)) + .send(ScreenInstruction::Render) .unwrap(); last_byte_receive_time = Some(Instant::now()); } else { @@ -222,7 +214,7 @@ fn stream_terminal_bytes( if pending_render { pending_render = false; send_screen_instructions - .send((ScreenInstruction::Render, err_ctx)) + .send(ScreenInstruction::Render) .unwrap(); } last_byte_receive_time = None; @@ -230,14 +222,14 @@ fn stream_terminal_bytes( } } send_screen_instructions - .send((ScreenInstruction::Render, err_ctx)) + .send(ScreenInstruction::Render) .unwrap(); #[cfg(not(test))] // this is a little hacky, and is because the tests end the file as soon as // we read everything, rather than hanging until there is new data // a better solution would be to fix the test fakes, but this will do for now send_screen_instructions - .send((ScreenInstruction::ClosePane(pid), err_ctx)) + .send(ScreenInstruction::ClosePane(pid)) .unwrap(); } }); @@ -246,7 +238,7 @@ fn stream_terminal_bytes( impl PtyBus { pub fn new( receive_pty_instructions: Receiver<(PtyInstruction, ErrorContext)>, - send_screen_instructions: Sender<(ScreenInstruction, ErrorContext)>, + send_screen_instructions: SenderWithContext, os_input: Box, debug_to_file: bool, ) -> Self { @@ -268,9 +260,8 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions - .send((ScreenInstruction::NewPane(pid_primary), err_ctx)) + .send(ScreenInstruction::NewPane(pid_primary)) .unwrap(); } pub fn spawn_terminal_vertically(&mut self, file_to_open: Option) { @@ -283,9 +274,8 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions - .send((ScreenInstruction::VerticalSplit(pid_primary), err_ctx)) + .send(ScreenInstruction::VerticalSplit(pid_primary)) .unwrap(); } pub fn spawn_terminal_horizontally(&mut self, file_to_open: Option) { @@ -298,9 +288,8 @@ impl PtyBus { self.debug_to_file, ); self.id_to_child_pid.insert(pid_primary, pid_secondary); - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions - .send((ScreenInstruction::HorizontalSplit(pid_primary), err_ctx)) + .send(ScreenInstruction::HorizontalSplit(pid_primary)) .unwrap(); } pub fn spawn_terminals_for_layout(&mut self, layout: Layout) { @@ -311,12 +300,11 @@ impl PtyBus { self.id_to_child_pid.insert(pid_primary, pid_secondary); new_pane_pids.push(pid_primary); } - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_screen_instructions - .send(( - ScreenInstruction::ApplyLayout((layout, new_pane_pids.clone())), - err_ctx, - )) + .send(ScreenInstruction::ApplyLayout(( + layout, + new_pane_pids.clone(), + ))) .unwrap(); for id in new_pane_pids { stream_terminal_bytes( diff --git a/src/screen.rs b/src/screen.rs index 48af3a8779..79442a97f8 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashSet}; use std::io::Write; use std::os::unix::io::RawFd; -use std::sync::mpsc::{Receiver, Sender, SyncSender}; +use std::sync::mpsc::Receiver; use crate::boundaries::Boundaries; use crate::boundaries::Rect; @@ -10,7 +10,7 @@ use crate::layout::Layout; use crate::os_input_output::OsApi; use crate::pty_bus::{PtyInstruction, VteEvent}; use crate::terminal_pane::{PositionAndSize, TerminalPane}; -use crate::{AppInstruction, OPENCALLS}; +use crate::{AppInstruction, SenderWithContext}; /* * Screen @@ -80,8 +80,8 @@ pub enum ScreenInstruction { pub struct Screen { pub receiver: Receiver<(ScreenInstruction, ErrorContext)>, max_panes: Option, - send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, - send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, + pub send_pty_instructions: SenderWithContext, + pub send_app_instructions: SenderWithContext, full_screen_ws: PositionAndSize, terminals: BTreeMap, // BTreeMap because we need a predictable order when changing focus panes_to_hide: HashSet, @@ -93,8 +93,8 @@ pub struct Screen { impl Screen { pub fn new( receive_screen_instructions: Receiver<(ScreenInstruction, ErrorContext)>, - send_pty_instructions: Sender<(PtyInstruction, ErrorContext)>, - send_app_instructions: SyncSender<(AppInstruction, ErrorContext)>, + send_pty_instructions: SenderWithContext, + send_app_instructions: SenderWithContext, full_screen_ws: &PositionAndSize, os_api: Box, max_panes: Option, @@ -164,9 +164,8 @@ impl Screen { // this is a bit of a hack and happens because we don't have any central location that // can query the screen as to how many panes it needs to create a layout // fixing this will require a bit of an architecture change - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_pty_instructions - .send((PtyInstruction::ClosePane(*unused_pid), err_ctx)) + .send(PtyInstruction::ClosePane(*unused_pid)) .unwrap(); } self.active_terminal = Some(*self.terminals.iter().next().unwrap().0); @@ -1533,11 +1532,10 @@ impl Screen { fn close_down_to_max_terminals(&mut self) { if let Some(max_panes) = self.max_panes { if self.terminals.len() >= max_panes { - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); for _ in max_panes..=self.terminals.len() { let first_pid = *self.terminals.iter().next().unwrap().0; self.send_pty_instructions - .send((PtyInstruction::ClosePane(first_pid), err_ctx)) + .send(PtyInstruction::ClosePane(first_pid)) .unwrap(); self.close_pane_without_rerender(first_pid); // TODO: do not render yet } @@ -1592,19 +1590,15 @@ impl Screen { self.terminals.remove(&id); if self.terminals.is_empty() { self.active_terminal = None; - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); - let _ = self - .send_app_instructions - .send((AppInstruction::Exit, err_ctx)); + let _ = self.send_app_instructions.send(AppInstruction::Exit); } } } pub fn close_focused_pane(&mut self) { if let Some(active_terminal_id) = self.get_active_terminal_id() { self.close_pane(active_terminal_id); - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); self.send_pty_instructions - .send((PtyInstruction::ClosePane(active_terminal_id), err_ctx)) + .send(PtyInstruction::ClosePane(active_terminal_id)) .unwrap(); } } From 8a7af50efd2472790a87a385b4c7667f22acd808 Mon Sep 17 00:00:00 2001 From: Kunal Mohan Date: Wed, 9 Dec 2020 22:21:00 +0530 Subject: [PATCH 10/10] Keep arrayvec at v0.5.1 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1508ff6bc..3c7bf2c6dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,9 +32,9 @@ checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" [[package]] name = "arrayvec" -version = "0.5.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "async-channel"