diff options
| author | Kunal Mohan <kunalmohan99@gmail.com> | 2021-03-18 22:37:25 +0530 |
|---|---|---|
| committer | Kunal Mohan <kunalmohan99@gmail.com> | 2021-05-04 20:47:51 +0530 |
| commit | 0d814ebcde98659babeaaa71a3ad5ee720021fc4 (patch) | |
| tree | 28b136c7ebde8f00375712c3fcec38992e81a60e /src/common | |
| parent | wip: remove the commands that are called only on the client (diff) | |
| download | sl0ppij-0d814ebcde98659babeaaa71a3ad5ee720021fc4.tar.gz sl0ppij-0d814ebcde98659babeaaa71a3ad5ee720021fc4.tar.xz sl0ppij-0d814ebcde98659babeaaa71a3ad5ee720021fc4.zip | |
Divide OsApi into ClientOsApi and ServerOsApi and move calls to os thread
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/errors.rs | 27 | ||||
| -rw-r--r-- | src/common/input/handler.rs | 10 | ||||
| -rw-r--r-- | src/common/mod.rs | 20 | ||||
| -rw-r--r-- | src/common/os_input_output.rs | 144 | ||||
| -rw-r--r-- | src/common/pty_bus.rs | 12 | ||||
| -rw-r--r-- | src/common/screen.rs | 9 |
6 files changed, 114 insertions, 108 deletions
diff --git a/src/common/errors.rs b/src/common/errors.rs index 3b5c8354..4259600f 100644 --- a/src/common/errors.rs +++ b/src/common/errors.rs @@ -1,7 +1,7 @@ //! Error context system based on a thread-local representation of the call stack, itself based on //! the instructions that are sent between threads. -use super::{os_input_output::OsApiInstruction, AppInstruction, OPENCALLS}; +use super::{os_input_output::ServerOsApiInstruction, AppInstruction, OPENCALLS}; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; use serde::{Deserialize, Serialize}; @@ -297,26 +297,21 @@ impl From<&PtyInstruction> for PtyContext { #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum OsContext { - SpawnTerminal, - GetTerminalSizeUsingFd, SetTerminalSizeUsingFd, - SetRawMode, - UnsetRawMode, - ReadFromTtyStdout, WriteToTtyStdin, TcDrain, - Kill, - ReadFromStdin, - GetStdoutWriter, - BoxClone, + Exit, } -impl From<&OsApiInstruction> for OsContext { - fn from(os_instruction: &OsApiInstruction) -> Self { +impl From<&ServerOsApiInstruction> for OsContext { + fn from(os_instruction: &ServerOsApiInstruction) -> Self { match *os_instruction { - OsApiInstruction::SetTerminalSizeUsingFd(_, _, _) => OsContext::SetTerminalSizeUsingFd, - OsApiInstruction::WriteToTtyStdin(_, _) => OsContext::WriteToTtyStdin, - OsApiInstruction::TcDrain(_) => OsContext::TcDrain, + ServerOsApiInstruction::SetTerminalSizeUsingFd(_, _, _) => { + OsContext::SetTerminalSizeUsingFd + } + ServerOsApiInstruction::WriteToTtyStdin(_, _) => OsContext::WriteToTtyStdin, + ServerOsApiInstruction::TcDrain(_) => OsContext::TcDrain, + ServerOsApiInstruction::Exit => OsContext::Exit, } } } @@ -356,6 +351,7 @@ pub enum AppContext { ToPlugin, ToScreen, DoneClosingPane, + OsApi, } impl From<&AppInstruction> for AppContext { @@ -364,6 +360,7 @@ impl From<&AppInstruction> for AppContext { AppInstruction::Exit => AppContext::Exit, AppInstruction::Error(_) => AppContext::Error, AppInstruction::ToPty(_) => AppContext::ToPty, + AppInstruction::OsApi(_) => AppContext::OsApi, AppInstruction::ToPlugin(_) => AppContext::ToPlugin, AppInstruction::ToScreen(_) => AppContext::ToScreen, AppInstruction::DoneClosingPane => AppContext::DoneClosingPane, diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index f8f07f53..b74e2929 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -5,7 +5,7 @@ use super::keybinds::Keybinds; use crate::common::input::config::Config; use crate::common::{AppInstruction, SenderWithContext, OPENCALLS}; use crate::errors::ContextType; -use crate::os_input_output::OsApi; +use crate::os_input_output::ClientOsApi; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; use crate::wasm_vm::PluginInstruction; @@ -19,8 +19,7 @@ use zellij_tile::data::{Event, InputMode, Key, ModeInfo, Palette}; struct InputHandler { /// The current input mode mode: InputMode, - os_input: Box<dyn OsApi>, - config: Config, + os_input: Box<dyn ClientOsApi>, command_is_executing: CommandIsExecuting, send_screen_instructions: SenderWithContext<ScreenInstruction>, send_plugin_instructions: SenderWithContext<PluginInstruction>, @@ -31,7 +30,7 @@ struct InputHandler { impl InputHandler { /// Returns a new [`InputHandler`] with the attributes specified as arguments. fn new( - os_input: Box<dyn OsApi>, + os_input: Box<dyn ClientOsApi>, command_is_executing: CommandIsExecuting, config: Config, send_screen_instructions: SenderWithContext<ScreenInstruction>, @@ -336,8 +335,7 @@ pub fn get_mode_info(mode: InputMode, palette: Palette) -> ModeInfo { /// Entry point to the module. Instantiates an [`InputHandler`] and starts /// its [`InputHandler::handle_input()`] loop. pub fn input_loop( - os_input: Box<dyn OsApi>, - config: Config, + os_input: Box<dyn ClientOsApi>, command_is_executing: CommandIsExecuting, send_screen_instructions: SenderWithContext<ScreenInstruction>, send_plugin_instructions: SenderWithContext<PluginInstruction>, diff --git a/src/common/mod.rs b/src/common/mod.rs index d003aab0..0b55d3b9 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -31,7 +31,7 @@ use crate::server::start_server; use command_is_executing::CommandIsExecuting; use errors::{AppContext, ContextType, ErrorContext, PluginContext, ScreenContext}; use input::handler::input_loop; -use os_input_output::{OsApi, OsApiInstruction}; +use os_input_output::{ClientOsApi, ServerOsApiInstruction}; use pty_bus::PtyInstruction; use screen::{Screen, ScreenInstruction}; use serde::{Deserialize, Serialize}; @@ -51,7 +51,7 @@ pub enum ServerInstruction { NewClient(String), ToPty(PtyInstruction), ToScreen(ScreenInstruction), - OsApi(OsApiInstruction), + OsApi(ServerOsApiInstruction), DoneClosingPane, ClosePluginPane(u32), Exit, @@ -180,6 +180,7 @@ pub enum AppInstruction { ToPty(PtyInstruction), ToScreen(ScreenInstruction), ToPlugin(PluginInstruction), + OsApi(ServerOsApiInstruction), DoneClosingPane, } @@ -199,7 +200,9 @@ impl From<ClientInstruction> for AppInstruction { /// Start Zellij with the specified [`OsApi`] and command-line arguments. // FIXME this should definitely be modularized and split into different functions. -pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs, config: Config) { +pub fn start(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs) { + let (ipc_thread, server_name) = start_server(opts.clone()); + let take_snapshot = "\u{1b}[?1049h"; os_input.unset_raw_mode(0); let _ = os_input @@ -228,8 +231,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs, config: Config) { let mut send_app_instructions = SenderWithContext::new(err_ctx, SenderType::SyncSender(send_app_instructions)); - let (ipc_thread, server_name) = start_server(os_input.clone(), opts.clone()); - let (client_buffer_path, client_buffer) = SharedRingBuffer::create_temp(8192).unwrap(); let mut send_server_instructions = IpcSenderWithContext::new(SharedRingBuffer::open(&server_name).unwrap()); @@ -612,7 +613,14 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs, config: Config) { send_plugin_instructions.send(instruction).unwrap(); } AppInstruction::ToPty(instruction) => { - let _ = send_server_instructions.send(ServerInstruction::ToPty(instruction)); + let _ = send_server_instructions + .send(ServerInstruction::ToPty(instruction)) + .unwrap(); + } + AppInstruction::OsApi(instruction) => { + let _ = send_server_instructions + .send(ServerInstruction::OsApi(instruction)) + .unwrap(); } AppInstruction::DoneClosingPane => command_is_executing.done_closing_pane(), } diff --git a/src/common/os_input_output.rs b/src/common/os_input_output.rs index 0e7363ea..5c0115bc 100644 --- a/src/common/os_input_output.rs +++ b/src/common/os_input_output.rs @@ -7,13 +7,13 @@ use nix::sys::termios; use nix::sys::wait::waitpid; use nix::unistd; use nix::unistd::{ForkResult, Pid}; +use serde::{Deserialize, Serialize}; use std::io; use std::io::prelude::*; use std::os::unix::io::RawFd; use std::path::PathBuf; use std::process::{Child, Command}; use std::sync::{Arc, Mutex}; -use serde::{Deserialize, Serialize}; use signal_hook::{consts::signal::*, iterator::Signals}; @@ -156,23 +156,15 @@ fn spawn_terminal(file_to_open: Option<PathBuf>, orig_termios: termios::Termios) } #[derive(Clone)] -pub struct OsInputOutput { +pub struct ServerOsInputOutput { orig_termios: Arc<Mutex<termios::Termios>>, } /// The `OsApi` trait represents an abstract interface to the features of an operating system that /// Zellij requires. -pub trait OsApi: Send + Sync { - /// Returns the size of the terminal associated to file descriptor `fd`. - fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize; +pub trait ServerOsApi: Send + Sync { /// Sets the size of the terminal associated to file descriptor `fd`. fn set_terminal_size_using_fd(&mut self, fd: RawFd, cols: u16, rows: u16); - /// Set the terminal associated to file descriptor `fd` to - /// [raw mode](https://en.wikipedia.org/wiki/Terminal_mode). - fn set_raw_mode(&mut self, fd: RawFd); - /// Set the terminal associated to file descriptor `fd` to - /// [cooked mode](https://en.wikipedia.org/wiki/Terminal_mode). - fn unset_raw_mode(&mut self, fd: RawFd); /// Spawn a new terminal, with an optional file to open in a terminal program. fn spawn_terminal(&mut self, file_to_open: Option<PathBuf>) -> (RawFd, RawFd); /// Read bytes from the standard output of the virtual terminal referred to by `fd`. @@ -186,30 +178,14 @@ pub trait OsApi: Send + Sync { // or a nix::unistd::Pid. See `man kill.3`, nix::sys::signal::kill (both take an argument // called `pid` and of type `pid_t`, and not `fd`) fn kill(&mut self, pid: RawFd) -> Result<(), nix::Error>; - /// Returns the raw contents of standard input. - fn read_from_stdin(&self) -> Vec<u8>; - /// Returns the writer that allows writing to standard output. - fn get_stdout_writer(&self) -> Box<dyn io::Write>; /// Returns a [`Box`] pointer to this [`OsApi`] struct. - fn box_clone(&self) -> Box<dyn OsApi>; - fn receive_sigwinch(&self, cb: Box<dyn Fn()>); - fn load_palette(&self) -> Palette; + fn box_clone(&self) -> Box<dyn ServerOsApi>; } -impl OsApi for OsInputOutput { - fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize { - get_terminal_size_using_fd(fd) - } +impl ServerOsApi for ServerOsInputOutput { fn set_terminal_size_using_fd(&mut self, fd: RawFd, cols: u16, rows: u16) { set_terminal_size_using_fd(fd, cols, rows); } - fn set_raw_mode(&mut self, fd: RawFd) { - into_raw_mode(fd); - } - fn unset_raw_mode(&mut self, fd: RawFd) { - let orig_termios = self.orig_termios.lock().unwrap(); - unset_raw_mode(fd, orig_termios.clone()); - } fn spawn_terminal(&mut self, file_to_open: Option<PathBuf>) -> (RawFd, RawFd) { let orig_termios = self.orig_termios.lock().unwrap(); spawn_terminal(file_to_open, orig_termios.clone()) @@ -223,7 +199,72 @@ impl OsApi for OsInputOutput { fn tcdrain(&mut self, fd: RawFd) -> Result<(), nix::Error> { termios::tcdrain(fd) } - fn box_clone(&self) -> Box<dyn OsApi> { + fn box_clone(&self) -> Box<dyn ServerOsApi> { + Box::new((*self).clone()) + } + fn kill(&mut self, pid: RawFd) -> Result<(), nix::Error> { + kill(Pid::from_raw(pid), Some(Signal::SIGINT)).unwrap(); + waitpid(Pid::from_raw(pid), None).unwrap(); + Ok(()) + } +} + +impl Clone for Box<dyn ServerOsApi> { + fn clone(&self) -> Box<dyn ServerOsApi> { + self.box_clone() + } +} + +pub fn get_server_os_input() -> ServerOsInputOutput { + let current_termios = termios::tcgetattr(0).unwrap(); + let orig_termios = Arc::new(Mutex::new(current_termios)); + ServerOsInputOutput { orig_termios } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ServerOsApiInstruction { + SetTerminalSizeUsingFd(RawFd, u16, u16), + WriteToTtyStdin(RawFd, Vec<u8>), + TcDrain(RawFd), + Exit, +} + +#[derive(Clone)] +pub struct ClientOsInputOutput { + orig_termios: Arc<Mutex<termios::Termios>>, +} + +/// The `OsApi` trait represents an abstract interface to the features of an operating system that +/// Zellij requires. +pub trait ClientOsApi: Send + Sync { + /// Returns the size of the terminal associated to file descriptor `fd`. + fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize; + /// Set the terminal associated to file descriptor `fd` to + /// [raw mode](https://en.wikipedia.org/wiki/Terminal_mode). + fn set_raw_mode(&mut self, fd: RawFd); + /// Set the terminal associated to file descriptor `fd` to + /// [cooked mode](https://en.wikipedia.org/wiki/Terminal_mode). + fn unset_raw_mode(&mut self, fd: RawFd); + /// Returns the writer that allows writing to standard output. + fn get_stdout_writer(&self) -> Box<dyn io::Write>; + /// Returns the raw contents of standard input. + fn read_from_stdin(&self) -> Vec<u8>; + /// Returns a [`Box`] pointer to this [`OsApi`] struct. + fn box_clone(&self) -> Box<dyn ClientOsApi>; +} + +impl ClientOsApi for ClientOsInputOutput { + fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize { + get_terminal_size_using_fd(fd) + } + fn set_raw_mode(&mut self, fd: RawFd) { + into_raw_mode(fd); + } + fn unset_raw_mode(&mut self, fd: RawFd) { + let orig_termios = self.orig_termios.lock().unwrap(); + unset_raw_mode(fd, orig_termios.clone()); + } + fn box_clone(&self) -> Box<dyn ClientOsApi> { Box::new((*self).clone()) } fn read_from_stdin(&self) -> Vec<u8> { @@ -239,51 +280,16 @@ impl OsApi for OsInputOutput { let stdout = ::std::io::stdout(); Box::new(stdout) } - fn kill(&mut self, pid: RawFd) -> Result<(), nix::Error> { - // TODO: - // Ideally, we should be using SIGINT rather than SIGKILL here, but there are cases in which - // the terminal we're trying to kill hangs on SIGINT and so all the app gets stuck - // that's why we're sending SIGKILL here - // A better solution would be to send SIGINT here and not wait for it, and then have - // a background thread do the waitpid stuff and send SIGKILL if the process is stuck - kill(Pid::from_raw(pid), Some(Signal::SIGKILL)).unwrap(); - waitpid(Pid::from_raw(pid), None).unwrap(); - Ok(()) - } - fn receive_sigwinch(&self, cb: Box<dyn Fn()>) { - let mut signals = Signals::new(&[SIGWINCH, SIGTERM, SIGINT, SIGQUIT]).unwrap(); - for signal in signals.forever() { - match signal { - SIGWINCH => { - cb(); - } - SIGTERM | SIGINT | SIGQUIT => { - break; - } - _ => unreachable!(), - } - } - } - fn load_palette(&self) -> Palette { - default_palette() - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum OsApiInstruction { - SetTerminalSizeUsingFd(RawFd, u16, u16), - WriteToTtyStdin(RawFd, Vec<u8>), - TcDrain(RawFd), } -impl Clone for Box<dyn OsApi> { - fn clone(&self) -> Box<dyn OsApi> { +impl Clone for Box<dyn ClientOsApi> { + fn clone(&self) -> Box<dyn ClientOsApi> { self.box_clone() } } -pub fn get_os_input() -> OsInputOutput { +pub fn get_client_os_input() -> ClientOsInputOutput { let current_termios = termios::tcgetattr(0).unwrap(); let orig_termios = Arc::new(Mutex::new(current_termios)); - OsInputOutput { orig_termios } + ClientOsInputOutput { orig_termios } } diff --git a/src/common/pty_bus.rs b/src/common/pty_bus.rs index e08e8576..a0eda375 100644 --- a/src/common/pty_bus.rs +++ b/src/common/pty_bus.rs @@ -12,7 +12,7 @@ use std::path::PathBuf; use super::{IpcSenderWithContext, ScreenInstruction, OPENCALLS}; use crate::layout::Layout; -use crate::os_input_output::OsApi; +use crate::os_input_output::ServerOsApi; use crate::utils::logging::debug_to_file; use crate::{ common::ServerInstruction, @@ -22,11 +22,11 @@ use crate::{ pub struct ReadFromPid { pid: RawFd, - os_input: Box<dyn OsApi>, + os_input: Box<dyn ServerOsApi>, } impl ReadFromPid { - pub fn new(pid: &RawFd, os_input: Box<dyn OsApi>) -> ReadFromPid { + pub fn new(pid: &RawFd, os_input: Box<dyn ServerOsApi>) -> ReadFromPid { ReadFromPid { pid: *pid, os_input, @@ -187,7 +187,7 @@ pub enum PtyInstruction { pub struct PtyBus { pub receive_pty_instructions: Receiver<(PtyInstruction, ErrorContext)>, pub id_to_child_pid: HashMap<RawFd, RawFd>, - os_input: Box<dyn OsApi>, + os_input: Box<dyn ServerOsApi>, debug_to_file: bool, task_handles: HashMap<RawFd, JoinHandle<()>>, pub send_server_instructions: IpcSenderWithContext, @@ -195,7 +195,7 @@ pub struct PtyBus { fn stream_terminal_bytes( pid: RawFd, - os_input: Box<dyn OsApi>, + os_input: Box<dyn ServerOsApi>, mut send_server_instructions: IpcSenderWithContext, debug: bool, ) -> JoinHandle<()> { @@ -274,7 +274,7 @@ fn stream_terminal_bytes( impl PtyBus { pub fn new( receive_pty_instructions: Receiver<(PtyInstruction, ErrorContext)>, - os_input: Box<dyn OsApi>, + os_input: Box<dyn ServerOsApi>, send_server_instructions: IpcSenderWithContext, debug_to_file: bool, ) -> Self { diff --git a/src/common/screen.rs b/src/common/screen.rs index 7848c243..ae1f4dd7 100644 --- a/src/common/screen.rs +++ b/src/common/screen.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use std::sync::mpsc::Receiver; use super::{AppInstruction, SenderWithContext}; -use crate::os_input_output::OsApi; +use crate::os_input_output::ClientOsApi; use crate::panes::PositionAndSize; use crate::pty_bus::{PtyInstruction, VteBytes}; use crate::tab::Tab; @@ -78,10 +78,7 @@ pub struct Screen { /// The index of this [`Screen`]'s active [`Tab`]. active_tab_index: Option<usize>, /// The [`OsApi`] this [`Screen`] uses. - os_api: Box<dyn OsApi>, - mode_info: ModeInfo, - input_mode: InputMode, - colors: Palette, + os_api: Box<dyn ClientOsApi>, } impl Screen { @@ -93,7 +90,7 @@ impl Screen { send_plugin_instructions: SenderWithContext<PluginInstruction>, send_app_instructions: SenderWithContext<AppInstruction>, full_screen_ws: &PositionAndSize, - os_api: Box<dyn OsApi>, + os_api: Box<dyn ClientOsApi>, max_panes: Option<usize>, mode_info: ModeInfo, input_mode: InputMode, |
