diff --git a/Cargo.lock b/Cargo.lock index 92b2d0ca7e..a3037b008a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -222,18 +222,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "blocking" version = "1.0.2" @@ -620,12 +608,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futures" version = "0.3.14" @@ -950,19 +932,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" -[[package]] -name = "lexical-core" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.0", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.93" @@ -987,9 +956,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ "scopeguard", ] @@ -1074,19 +1043,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nom" -version = "6.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" -dependencies = [ - "bitvec", - "funty", - "lexical-core", - "memchr", - "version_check", -] - [[package]] name = "num_cpus" version = "1.13.0" @@ -1226,12 +1182,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "rand" version = "0.3.23" @@ -1542,12 +1492,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "status-bar" version = "0.1.0" @@ -1651,12 +1595,6 @@ dependencies = [ "zellij-tile-utils", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "target-lexicon" version = "0.11.2" @@ -1699,15 +1637,6 @@ dependencies = [ "redox_termios", ] -[[package]] -name = "termios" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" -dependencies = [ - "libc", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -1810,15 +1739,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" -[[package]] -name = "unicode-truncate" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a04be5ca5f7a4a7270ffea82bc41c59b87c611ed04f20e77c338e8d3c2348e42" -dependencies = [ - "unicode-width", -] - [[package]] name = "unicode-width" version = "0.1.8" @@ -2253,12 +2173,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "yaml-rust" version = "0.4.5" @@ -2271,38 +2185,53 @@ dependencies = [ [[package]] name = "zellij" version = "0.12.0" +dependencies = [ + "insta", + "interprocess", + "nix", + "structopt", + "vte 0.10.1", + "zellij-client", + "zellij-server", + "zellij-tile", + "zellij-utils", +] + +[[package]] +name = "zellij-client" +version = "0.12.0" +dependencies = [ + "interprocess", + "libc", + "nix", + "signal-hook", + "termion", + "zellij-tile", + "zellij-utils", +] + +[[package]] +name = "zellij-server" +version = "0.12.0" dependencies = [ "ansi_term 0.12.1", "async-std", - "backtrace", - "bincode", - "colors-transform", "daemonize", - "directories-next", - "futures", "insta", "interprocess", - "lazy_static", "libc", - "names", "nix", - "nom", "serde", "serde_json", "serde_yaml", "signal-hook", - "strip-ansi-escapes", - "structopt", - "strum", - "tempfile", "termion", - "termios", - "unicode-truncate", "unicode-width", "vte 0.10.1", "wasmer", "wasmer-wasi", "zellij-tile", + "zellij-utils", ] [[package]] @@ -2321,3 +2250,26 @@ version = "0.12.0" dependencies = [ "ansi_term 0.12.1", ] + +[[package]] +name = "zellij-utils" +version = "0.12.0" +dependencies = [ + "async-std", + "backtrace", + "bincode", + "colors-transform", + "directories-next", + "interprocess", + "lazy_static", + "names", + "nix", + "serde", + "serde_yaml", + "strip-ansi-escapes", + "structopt", + "strum", + "tempfile", + "termion", + "zellij-tile", +] diff --git a/Cargo.toml b/Cargo.toml index 099d17f6a0..231b480a33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,52 +8,34 @@ license = "MIT" repository = "https://github.com/zellij-org/zellij" homepage = "https://zellij.dev" include = ["src/**/*", "assets/plugins/*", "assets/layouts/*", "assets/config/*", "LICENSE.md", "README.md", "!**/*_test.*", "!**/tests/**/*"] +resolver = "2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ansi_term = "0.12.1" -backtrace = "0.3.55" -bincode = "1.3.1" -daemonize = "0.4.1" -directories-next = "2.0" -futures = "0.3.5" -libc = "0.2" -nix = "0.19.1" -nom = "6.0.1" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_yaml = "0.8" -signal-hook = "0.3" -strip-ansi-escapes = "0.1.0" +zellij-utils = { path = "zellij-utils/", version = "0.12.0" } +zellij-client = { path = "zellij-client/", version = "0.12.0" } +zellij-server = { path = "zellij-server/", version = "0.12.0" } +zellij-tile = { path = "zellij-tile/", version = "0.12.0" } structopt = "0.3" -termion = "1.5.0" -termios = "0.3" -unicode-truncate = "0.2.0" -unicode-width = "0.1.8" -vte = "0.10.1" -strum = "0.20.0" -lazy_static = "1.4.0" -wasmer = "1.0.0" -wasmer-wasi = "1.0.0" interprocess = "1.1.1" -names = "0.11.0" -colors-transform = "0.2.5" -zellij-tile = { path = "zellij-tile/", version = "0.12.0" } - -[dependencies.async-std] -version = "1.3.0" -features = ["unstable"] +vte = "0.10.1" +nix = "0.19.1" [dev-dependencies] insta = "1.6.0" -tempfile = "3.2.0" +zellij-utils = { path = "zellij-utils/", version = "*", features = ["test"] } +zellij-client = { path = "zellij-client/", version = "*", features = ["test"] } +zellij-server = { path = "zellij-server/", version = "*", features = ["test"] } [build-dependencies] structopt = "0.3" [workspace] members = [ + "zellij-client", + "zellij-server", + "zellij-utils", "zellij-tile", "zellij-tile-utils", "default-plugins/status-bar", diff --git a/Makefile.toml b/Makefile.toml index 75f78b2582..6decb0de72 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -24,6 +24,7 @@ env = { "SKIP_TEST" = true } [tasks.test] condition = { env_false = ["SKIP_TEST"] } dependencies = ["pre-test"] +args = ["test"] [tasks.post-test] env = { "SKIP_TEST" = false } @@ -37,6 +38,12 @@ run_task = "launch" [tasks.build-workspace] run_task = { name = "build", fork = true } +[tasks.build] +args = ["build"] + +[tasks.build-release] +args = ["build", "--release"] + [tasks.build-dev-data-dir] script_runner = "@duckscript" script = ''' diff --git a/src/common/input/mod.rs b/src/common/input/mod.rs deleted file mode 100644 index f30ccf23b7..0000000000 --- a/src/common/input/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! The way terminal input is handled. - -pub mod actions; -pub mod config; -pub mod handler; -pub mod keybinds; -pub mod options; diff --git a/src/common/mod.rs b/src/common/mod.rs deleted file mode 100644 index c91e1e05b1..0000000000 --- a/src/common/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod command_is_executing; -pub mod errors; -pub mod input; -pub mod ipc; -pub mod os_input_output; -pub mod pty; -pub mod screen; -pub mod setup; -pub mod thread_bus; -pub mod utils; -pub mod wasm_vm; - -use crate::panes::PaneId; -use crate::server::ServerInstruction; diff --git a/src/common/thread_bus.rs b/src/common/thread_bus.rs deleted file mode 100644 index 8827d068fd..0000000000 --- a/src/common/thread_bus.rs +++ /dev/null @@ -1,142 +0,0 @@ -//! Definitions and helpers for sending and receiving messages between threads. - -use async_std::task_local; -use std::cell::RefCell; -use std::sync::mpsc; - -use crate::common::pty::PtyInstruction; -use crate::common::ServerInstruction; -use crate::errors::{get_current_ctx, ErrorContext}; -use crate::os_input_output::ServerOsApi; -use crate::screen::ScreenInstruction; -use crate::wasm_vm::PluginInstruction; - -/// An [MPSC](mpsc) asynchronous channel with added error context. -pub type ChannelWithContext = ( - mpsc::Sender<(T, ErrorContext)>, - mpsc::Receiver<(T, ErrorContext)>, -); -/// An [MPSC](mpsc) synchronous channel with added error context. -pub type SyncChannelWithContext = ( - mpsc::SyncSender<(T, ErrorContext)>, - mpsc::Receiver<(T, ErrorContext)>, -); - -/// Wrappers around the two standard [MPSC](mpsc) sender types, [`mpsc::Sender`] and [`mpsc::SyncSender`], with an additional [`ErrorContext`]. -#[derive(Clone)] -pub enum SenderType { - /// A wrapper around an [`mpsc::Sender`], adding an [`ErrorContext`]. - Sender(mpsc::Sender<(T, ErrorContext)>), - /// A wrapper around an [`mpsc::SyncSender`], adding an [`ErrorContext`]. - SyncSender(mpsc::SyncSender<(T, ErrorContext)>), -} - -/// Sends messages on an [MPSC](std::sync::mpsc) channel, along with an [`ErrorContext`], -/// synchronously or asynchronously depending on the underlying [`SenderType`]. -#[derive(Clone)] -pub struct SenderWithContext { - sender: SenderType, -} - -impl SenderWithContext { - pub fn new(sender: SenderType) -> Self { - Self { sender } - } - - /// Sends an event, along with the current [`ErrorContext`], on this - /// [`SenderWithContext`]'s channel. - pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> { - let err_ctx = get_current_ctx(); - match self.sender { - SenderType::Sender(ref s) => s.send((event, err_ctx)), - SenderType::SyncSender(ref s) => s.send((event, err_ctx)), - } - } -} - -unsafe impl Send for SenderWithContext {} -unsafe impl Sync for SenderWithContext {} - -thread_local!( - /// A key to some thread local storage (TLS) that holds a representation of the thread's call - /// stack in the form of an [`ErrorContext`]. - pub static OPENCALLS: RefCell = RefCell::default() -); - -task_local! { - /// A key to some task local storage that holds a representation of the task's call - /// stack in the form of an [`ErrorContext`]. - pub static ASYNCOPENCALLS: RefCell = RefCell::default() -} - -/// A container for senders to the different threads in zellij on the server side -#[derive(Clone)] -pub struct ThreadSenders { - pub to_screen: Option>, - pub to_pty: Option>, - pub to_plugin: Option>, - pub to_server: Option>, -} - -impl ThreadSenders { - pub fn send_to_screen( - &self, - instruction: ScreenInstruction, - ) -> Result<(), mpsc::SendError<(ScreenInstruction, ErrorContext)>> { - self.to_screen.as_ref().unwrap().send(instruction) - } - - pub fn send_to_pty( - &self, - instruction: PtyInstruction, - ) -> Result<(), mpsc::SendError<(PtyInstruction, ErrorContext)>> { - self.to_pty.as_ref().unwrap().send(instruction) - } - - pub fn send_to_plugin( - &self, - instruction: PluginInstruction, - ) -> Result<(), mpsc::SendError<(PluginInstruction, ErrorContext)>> { - self.to_plugin.as_ref().unwrap().send(instruction) - } - - pub fn send_to_server( - &self, - instruction: ServerInstruction, - ) -> Result<(), mpsc::SendError<(ServerInstruction, ErrorContext)>> { - self.to_server.as_ref().unwrap().send(instruction) - } -} - -/// A container for a receiver, OS input and the senders to a given thread -pub struct Bus { - pub receiver: mpsc::Receiver<(T, ErrorContext)>, - pub senders: ThreadSenders, - pub os_input: Option>, -} - -impl Bus { - pub fn new( - receiver: mpsc::Receiver<(T, ErrorContext)>, - to_screen: Option<&SenderWithContext>, - to_pty: Option<&SenderWithContext>, - to_plugin: Option<&SenderWithContext>, - to_server: Option<&SenderWithContext>, - os_input: Option>, - ) -> Self { - Bus { - receiver, - senders: ThreadSenders { - to_screen: to_screen.cloned(), - to_pty: to_pty.cloned(), - to_plugin: to_plugin.cloned(), - to_server: to_server.cloned(), - }, - os_input: os_input.clone(), - } - } - - pub fn recv(&self) -> Result<(T, ErrorContext), mpsc::RecvError> { - self.receiver.recv() - } -} diff --git a/src/common/utils/mod.rs b/src/common/utils/mod.rs deleted file mode 100644 index 1cb4df2757..0000000000 --- a/src/common/utils/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Zellij utilities. - -pub mod consts; -pub mod logging; -pub mod shared; diff --git a/src/main.rs b/src/main.rs index 12842b58cb..1e1d4764e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,22 @@ -mod cli; -mod client; -mod common; -mod server; #[cfg(test)] mod tests; -use client::{boundaries, layout, panes, start_client, tab}; -use common::{ - command_is_executing, errors, os_input_output, pty, screen, setup::Setup, utils, wasm_vm, -}; -use server::start_server; +use std::convert::TryFrom; use structopt::StructOpt; - -use crate::cli::CliArgs; -use crate::command_is_executing::CommandIsExecuting; -use crate::common::input::config::Config; -use crate::os_input_output::{get_client_os_input, get_server_os_input}; -use crate::utils::{ +use zellij_client::{os_input_output::get_client_os_input, start_client}; +use zellij_server::{os_input_output::get_server_os_input, start_server}; +use zellij_utils::{ + cli::{CliArgs, ConfigCli}, consts::{ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR}, + input::config::Config, logging::*, + setup::Setup, }; -use std::convert::TryFrom; pub fn main() { let opts = CliArgs::from_args(); - if let Some(crate::cli::ConfigCli::Setup(setup)) = opts.option.clone() { + if let Some(ConfigCli::Setup(setup)) = opts.option.clone() { Setup::from_cli(&setup, opts).expect("Failed to print to stdout"); std::process::exit(0); } else { diff --git a/src/tests/fakes.rs b/src/tests/fakes.rs index 98ec694a7f..3fefa663a7 100644 --- a/src/tests/fakes.rs +++ b/src/tests/fakes.rs @@ -1,4 +1,5 @@ -use crate::panes::PositionAndSize; +use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes}; +use crate::tests::utils::commands::{QUIT, SLEEP}; use interprocess::local_socket::LocalSocketStream; use std::collections::{HashMap, VecDeque}; use std::io::Write; @@ -6,15 +7,16 @@ use std::os::unix::io::RawFd; use std::path::PathBuf; use std::sync::{mpsc, Arc, Condvar, Mutex}; use std::time::{Duration, Instant}; - -use crate::common::ipc::{ClientToServerMsg, ServerToClientMsg}; -use crate::common::thread_bus::{ChannelWithContext, SenderType, SenderWithContext}; -use crate::errors::ErrorContext; -use crate::os_input_output::{ClientOsApi, ServerOsApi}; -use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes}; -use crate::tests::utils::commands::{QUIT, SLEEP}; -use crate::utils::shared::default_palette; +use zellij_client::os_input_output::ClientOsApi; +use zellij_server::os_input_output::ServerOsApi; use zellij_tile::data::Palette; +use zellij_utils::{ + channels::{ChannelWithContext, SenderType, SenderWithContext}, + errors::ErrorContext, + ipc::{ClientToServerMsg, ServerToClientMsg}, + pane_size::PositionAndSize, + shared::default_palette, +}; const MIN_TIME_BETWEEN_SNAPSHOTS: Duration = Duration::from_millis(150); diff --git a/src/tests/integration/basic.rs b/src/tests/integration/basic.rs index bb581eb141..640b1c553c 100644 --- a/src/tests/integration/basic.rs +++ b/src/tests/integration/basic.rs @@ -1,7 +1,6 @@ -use crate::panes::PositionAndSize; use ::insta::assert_snapshot; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::commands::{ @@ -12,6 +11,7 @@ use crate::tests::utils::commands::{ }; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/close_pane.rs b/src/tests/integration/close_pane.rs index cfb912ee37..b5ba7f1985 100644 --- a/src/tests/integration/close_pane.rs +++ b/src/tests/integration/close_pane.rs @@ -1,17 +1,17 @@ -use crate::panes::PositionAndSize; use ::insta::assert_snapshot; +use zellij_utils::pane_size::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ CLOSE_PANE_IN_PANE_MODE, ESC, MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/compatibility.rs b/src/tests/integration/compatibility.rs index 06222a3aa2..3b28a97032 100644 --- a/src/tests/integration/compatibility.rs +++ b/src/tests/integration/compatibility.rs @@ -1,15 +1,15 @@ use ::insta::assert_snapshot; use ::std::collections::HashMap; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::possible_tty_inputs::Bytes; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::QUIT; +use zellij_utils::input::config::Config; /* * These tests are general compatibility tests for non-trivial scenarios running in the terminal. diff --git a/src/tests/integration/layouts.rs b/src/tests/integration/layouts.rs index 4c64afb2be..1f02122c4f 100644 --- a/src/tests/integration/layouts.rs +++ b/src/tests/integration/layouts.rs @@ -1,13 +1,13 @@ use insta::assert_snapshot; use std::path::PathBuf; -use crate::common::input::config::Config; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::commands::QUIT; use crate::tests::utils::get_output_frame_snapshots; use crate::CliArgs; +use zellij_utils::input::config::Config; +use zellij_utils::pane_size::PositionAndSize; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/move_focus_down.rs b/src/tests/integration/move_focus_down.rs index b1032bd0aa..2f18ab6234 100644 --- a/src/tests/integration/move_focus_down.rs +++ b/src/tests/integration/move_focus_down.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_DOWN_IN_PANE_MODE, MOVE_FOCUS_UP_IN_PANE_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/move_focus_left.rs b/src/tests/integration/move_focus_left.rs index 4842f34271..a9fca49edb 100644 --- a/src/tests/integration/move_focus_left.rs +++ b/src/tests/integration/move_focus_left.rs @@ -1,17 +1,17 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ ENTER, MOVE_FOCUS_LEFT_IN_NORMAL_MODE, MOVE_FOCUS_LEFT_IN_PANE_MODE, MOVE_FOCUS_RIGHT_IN_PANE_MODE, NEW_TAB_IN_TAB_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, TAB_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/move_focus_right.rs b/src/tests/integration/move_focus_right.rs index 6ff6e21a80..c85d5b96ec 100644 --- a/src/tests/integration/move_focus_right.rs +++ b/src/tests/integration/move_focus_right.rs @@ -1,17 +1,17 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ ENTER, MOVE_FOCUS_LEFT_IN_PANE_MODE, MOVE_FOCUS_RIGHT_IN_NORMAL_MODE, MOVE_FOCUS_RIGHT_IN_PANE_MODE, NEW_TAB_IN_TAB_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, TAB_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/move_focus_up.rs b/src/tests/integration/move_focus_up.rs index 068ded522d..d161ff8a40 100644 --- a/src/tests/integration/move_focus_up.rs +++ b/src/tests/integration/move_focus_up.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_DOWN_IN_PANE_MODE, MOVE_FOCUS_UP_IN_PANE_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_down.rs b/src/tests/integration/resize_down.rs index cc4b9ec4fb..4ef45a0692 100644 --- a/src/tests/integration/resize_down.rs +++ b/src/tests/integration/resize_down.rs @@ -1,17 +1,17 @@ use insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_left.rs b/src/tests/integration/resize_left.rs index c5ba54274b..1b82050191 100644 --- a/src/tests/integration/resize_left.rs +++ b/src/tests/integration/resize_left.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_right.rs b/src/tests/integration/resize_right.rs index 43409ec158..44601f2cd6 100644 --- a/src/tests/integration/resize_right.rs +++ b/src/tests/integration/resize_right.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_MODE, RESIZE_RIGHT_IN_RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_up.rs b/src/tests/integration/resize_up.rs index 200fcc6e20..9aca8d5a26 100644 --- a/src/tests/integration/resize_up.rs +++ b/src/tests/integration/resize_up.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/tabs.rs b/src/tests/integration/tabs.rs index 0995d16c9a..90f82c6d4a 100644 --- a/src/tests/integration/tabs.rs +++ b/src/tests/integration/tabs.rs @@ -2,16 +2,17 @@ use insta::assert_snapshot; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; +use crate::tests::utils::commands::CLOSE_PANE_IN_PANE_MODE; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; -use crate::{panes::PositionAndSize, tests::utils::commands::CLOSE_PANE_IN_PANE_MODE}; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ CLOSE_TAB_IN_TAB_MODE, NEW_TAB_IN_TAB_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SWITCH_NEXT_TAB_IN_TAB_MODE, SWITCH_PREV_TAB_IN_TAB_MODE, TAB_MODE, TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; +use zellij_utils::pane_size::PositionAndSize; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/terminal_window_resize.rs b/src/tests/integration/terminal_window_resize.rs index 2e56300fce..2be41c3a1c 100644 --- a/src/tests/integration/terminal_window_resize.rs +++ b/src/tests/integration/terminal_window_resize.rs @@ -1,12 +1,12 @@ -use crate::panes::PositionAndSize; use ::insta::assert_snapshot; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::commands::QUIT; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/toggle_fullscreen.rs b/src/tests/integration/toggle_fullscreen.rs index 00d9817059..8025798292 100644 --- a/src/tests/integration/toggle_fullscreen.rs +++ b/src/tests/integration/toggle_fullscreen.rs @@ -1,16 +1,16 @@ use insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 7aaad79fa9..3e548db7cd 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -4,12 +4,10 @@ pub mod possible_tty_inputs; pub mod tty_inputs; pub mod utils; -use crate::cli::CliArgs; -use crate::client::start_client; -use crate::common::input::config::Config; -use crate::os_input_output::{ClientOsApi, ServerOsApi}; -use crate::server::start_server; use std::path::PathBuf; +use zellij_client::{os_input_output::ClientOsApi, start_client}; +use zellij_server::{os_input_output::ServerOsApi, start_server}; +use zellij_utils::{cli::CliArgs, input::config::Config}; pub fn start( client_os_input: Box, diff --git a/src/tests/utils.rs b/src/tests/utils.rs index f01c1ac503..ee2de3cd8d 100644 --- a/src/tests/utils.rs +++ b/src/tests/utils.rs @@ -1,5 +1,5 @@ -use crate::panes::PositionAndSize; -use crate::panes::TerminalPane; +use zellij_server::{panes::TerminalPane, tab::Pane}; +use zellij_utils::pane_size::PositionAndSize; pub fn get_output_frame_snapshots( output_frames: &[Vec], diff --git a/zellij-client/Cargo.toml b/zellij-client/Cargo.toml new file mode 100644 index 0000000000..f5e668c776 --- /dev/null +++ b/zellij-client/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "zellij-client" +version = "0.12.0" +authors = ["Kunal Mohan "] +edition = "2018" +description = "The client-side library for Zellij" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +zellij-utils = { path = "../zellij-utils/", version = "0.12.0" } +zellij-tile = { path = "../zellij-tile/", version = "0.12.0" } +termion = "1.5.0" +signal-hook = "0.3" +nix = "0.19.1" +interprocess = "1.1.1" +libc = "0.2" + +[features] +test = ["zellij-utils/test"] diff --git a/src/common/command_is_executing.rs b/zellij-client/src/command_is_executing.rs similarity index 96% rename from src/common/command_is_executing.rs rename to zellij-client/src/command_is_executing.rs index ad032557c5..3d672d9a2d 100644 --- a/src/common/command_is_executing.rs +++ b/zellij-client/src/command_is_executing.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, Condvar, Mutex}; #[derive(Clone)] -pub struct CommandIsExecuting { +pub(crate) struct CommandIsExecuting { input_thread: Arc<(Mutex, Condvar)>, } diff --git a/src/common/input/handler.rs b/zellij-client/src/input_handler.rs similarity index 65% rename from src/common/input/handler.rs rename to zellij-client/src/input_handler.rs index 4ac2cf839f..e67bdf8296 100644 --- a/src/common/input/handler.rs +++ b/zellij-client/src/input_handler.rs @@ -1,17 +1,15 @@ //! Main input logic. -use super::actions::Action; -use super::keybinds::Keybinds; -use crate::client::ClientInstruction; -use crate::common::input::config::Config; -use crate::common::ipc::ClientToServerMsg; -use crate::common::thread_bus::{SenderWithContext, OPENCALLS}; -use crate::errors::ContextType; -use crate::os_input_output::ClientOsApi; -use crate::CommandIsExecuting; +use crate::{os_input_output::ClientOsApi, ClientInstruction, CommandIsExecuting}; +use zellij_utils::{ + channels::{SenderWithContext, OPENCALLS}, + errors::ContextType, + input::{actions::Action, cast_termion_key, config::Config, keybinds::Keybinds}, + ipc::ClientToServerMsg, +}; -use termion::input::{TermRead, TermReadEventsAndRaw}; -use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities}; +use termion::input::TermReadEventsAndRaw; +use zellij_tile::data::{InputMode, Key}; /// Handles the dispatching of [`Action`]s according to the current /// [`InputMode`], and keep tracks of the current [`InputMode`]. @@ -172,55 +170,9 @@ impl InputHandler { } } -/// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds -/// (as pairs of [`String`]s). -// TODO this should probably be automatically generated in some way -pub fn get_mode_info( - mode: InputMode, - palette: Palette, - capabilities: PluginCapabilities, -) -> ModeInfo { - let mut keybinds: Vec<(String, String)> = vec![]; - match mode { - InputMode::Normal | InputMode::Locked => {} - InputMode::Resize => { - keybinds.push(("←↓↑→".to_string(), "Resize".to_string())); - } - InputMode::Pane => { - keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); - keybinds.push(("p".to_string(), "Next".to_string())); - keybinds.push(("n".to_string(), "New".to_string())); - keybinds.push(("d".to_string(), "Down split".to_string())); - keybinds.push(("r".to_string(), "Right split".to_string())); - keybinds.push(("x".to_string(), "Close".to_string())); - keybinds.push(("f".to_string(), "Fullscreen".to_string())); - } - InputMode::Tab => { - keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); - keybinds.push(("n".to_string(), "New".to_string())); - keybinds.push(("x".to_string(), "Close".to_string())); - keybinds.push(("r".to_string(), "Rename".to_string())); - keybinds.push(("s".to_string(), "Sync".to_string())); - } - InputMode::Scroll => { - keybinds.push(("↓↑".to_string(), "Scroll".to_string())); - keybinds.push(("PgUp/PgDn".to_string(), "Scroll Page".to_string())); - } - InputMode::RenameTab => { - keybinds.push(("Enter".to_string(), "when done".to_string())); - } - } - ModeInfo { - mode, - keybinds, - palette, - capabilities, - } -} - /// Entry point to the module. Instantiates an [`InputHandler`] and starts /// its [`InputHandler::handle_input()`] loop. -pub fn input_loop( +pub(crate) fn input_loop( os_input: Box, config: Config, command_is_executing: CommandIsExecuting, @@ -234,35 +186,3 @@ pub fn input_loop( ) .handle_input(); } - -pub fn parse_keys(input_bytes: &[u8]) -> Vec { - input_bytes.keys().flatten().map(cast_termion_key).collect() -} - -// FIXME: This is an absolutely cursed function that should be destroyed as soon -// as an alternative that doesn't touch zellij-tile can be developed... -fn cast_termion_key(event: termion::event::Key) -> Key { - match event { - termion::event::Key::Backspace => Key::Backspace, - termion::event::Key::Left => Key::Left, - termion::event::Key::Right => Key::Right, - termion::event::Key::Up => Key::Up, - termion::event::Key::Down => Key::Down, - termion::event::Key::Home => Key::Home, - termion::event::Key::End => Key::End, - termion::event::Key::PageUp => Key::PageUp, - termion::event::Key::PageDown => Key::PageDown, - termion::event::Key::BackTab => Key::BackTab, - termion::event::Key::Delete => Key::Delete, - termion::event::Key::Insert => Key::Insert, - termion::event::Key::F(n) => Key::F(n), - termion::event::Key::Char(c) => Key::Char(c), - termion::event::Key::Alt(c) => Key::Alt(c), - termion::event::Key::Ctrl(c) => Key::Ctrl(c), - termion::event::Key::Null => Key::Null, - termion::event::Key::Esc => Key::Esc, - _ => { - unimplemented!("Encountered an unknown key!") - } - } -} diff --git a/src/client/mod.rs b/zellij-client/src/lib.rs similarity index 86% rename from src/client/mod.rs rename to zellij-client/src/lib.rs index 862c13ccf0..8ffcf72be0 100644 --- a/src/client/mod.rs +++ b/zellij-client/src/lib.rs @@ -1,8 +1,7 @@ -pub mod boundaries; -pub mod layout; -pub mod pane_resizer; -pub mod panes; -pub mod tab; +pub mod os_input_output; + +mod command_is_executing; +mod input_handler; use std::env::current_exe; use std::io::{self, Write}; @@ -11,22 +10,23 @@ use std::process::Command; use std::sync::mpsc; use std::thread; -use crate::cli::CliArgs; -use crate::common::{ - command_is_executing::CommandIsExecuting, - errors::ContextType, +use crate::{ + command_is_executing::CommandIsExecuting, input_handler::input_loop, + os_input_output::ClientOsApi, +}; +use zellij_utils::cli::CliArgs; +use zellij_utils::{ + channels::{SenderType, SenderWithContext, SyncChannelWithContext}, + consts::ZELLIJ_IPC_PIPE, + errors::{ClientContext, ContextType, ErrorInstruction}, input::config::Config, - input::handler::input_loop, input::options::Options, ipc::{ClientToServerMsg, ServerToClientMsg}, - os_input_output::ClientOsApi, - thread_bus::{SenderType, SenderWithContext, SyncChannelWithContext}, - utils::consts::ZELLIJ_IPC_PIPE, }; -/// Instructions related to the client-side application and sent from server to client +/// Instructions related to the client-side application #[derive(Debug, Clone)] -pub enum ClientInstruction { +pub(crate) enum ClientInstruction { Error(String), Render(Option), UnblockInputThread, @@ -45,6 +45,24 @@ impl From for ClientInstruction { } } +impl From<&ClientInstruction> for ClientContext { + fn from(client_instruction: &ClientInstruction) -> Self { + match *client_instruction { + ClientInstruction::Exit => ClientContext::Exit, + ClientInstruction::Error(_) => ClientContext::Error, + ClientInstruction::ServerError(_) => ClientContext::ServerError, + ClientInstruction::Render(_) => ClientContext::Render, + ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread, + } + } +} + +impl ErrorInstruction for ClientInstruction { + fn error(err: String) -> Self { + ClientInstruction::Error(err) + } +} + fn spawn_server(socket_path: &Path) -> io::Result<()> { let status = Command::new(current_exe()?) .arg("--server") @@ -77,7 +95,7 @@ pub fn start_client(mut os_input: Box, opts: CliArgs, config: C .unwrap(); std::env::set_var(&"ZELLIJ", "0"); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] spawn_server(&*ZELLIJ_IPC_PIPE).unwrap(); let mut command_is_executing = CommandIsExecuting::new(); @@ -103,9 +121,9 @@ pub fn start_client(mut os_input: Box, opts: CliArgs, config: C let send_client_instructions = SenderWithContext::new(SenderType::SyncSender(send_client_instructions)); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] std::panic::set_hook({ - use crate::errors::handle_panic; + use zellij_utils::errors::handle_panic; let send_client_instructions = send_client_instructions.clone(); Box::new(move |info| { handle_panic(info, &send_client_instructions); diff --git a/zellij-client/src/os_input_output.rs b/zellij-client/src/os_input_output.rs new file mode 100644 index 0000000000..680561a863 --- /dev/null +++ b/zellij-client/src/os_input_output.rs @@ -0,0 +1,174 @@ +use interprocess::local_socket::LocalSocketStream; +use nix::pty::Winsize; +use nix::sys::termios; +use signal_hook::{consts::signal::*, iterator::Signals}; +use std::io; +use std::io::prelude::*; +use std::os::unix::io::RawFd; +use std::path::Path; +use std::sync::{Arc, Mutex}; +use zellij_utils::errors::ErrorContext; +use zellij_utils::ipc::{ + ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg, +}; +use zellij_utils::pane_size::PositionAndSize; + +fn into_raw_mode(pid: RawFd) { + let mut tio = termios::tcgetattr(pid).expect("could not get terminal attribute"); + termios::cfmakeraw(&mut tio); + match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &tio) { + Ok(_) => {} + Err(e) => panic!("error {:?}", e), + }; +} + +fn unset_raw_mode(pid: RawFd, orig_termios: termios::Termios) { + match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &orig_termios) { + Ok(_) => {} + Err(e) => panic!("error {:?}", e), + }; +} + +pub(crate) fn get_terminal_size_using_fd(fd: RawFd) -> PositionAndSize { + // TODO: do this with the nix ioctl + use libc::ioctl; + use libc::TIOCGWINSZ; + + let mut winsize = Winsize { + ws_row: 0, + ws_col: 0, + ws_xpixel: 0, + ws_ypixel: 0, + }; + + unsafe { ioctl(fd, TIOCGWINSZ, &mut winsize) }; + PositionAndSize::from(winsize) +} + +#[derive(Clone)] +pub struct ClientOsInputOutput { + orig_termios: Arc>, + send_instructions_to_server: Arc>>>, + receive_instructions_from_server: Arc>>>, +} + +/// The `ClientOsApi` trait represents an abstract interface to the features of an operating system that +/// Zellij client 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(&self, fd: RawFd); + /// Returns the writer that allows writing to standard output. + fn get_stdout_writer(&self) -> Box; + /// Returns the raw contents of standard input. + fn read_from_stdin(&self) -> Vec; + /// Returns a [`Box`] pointer to this [`ClientOsApi`] struct. + fn box_clone(&self) -> Box; + /// Sends a message to the server. + fn send_to_server(&self, msg: ClientToServerMsg); + /// Receives a message on client-side IPC channel + // This should be called from the client-side router thread only. + fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext); + fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box); + /// Establish a connection with the server socket. + fn connect_to_server(&self, path: &Path); +} + +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(&self, fd: RawFd) { + let orig_termios = self.orig_termios.lock().unwrap(); + unset_raw_mode(fd, orig_termios.clone()); + } + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } + fn read_from_stdin(&self) -> Vec { + let stdin = std::io::stdin(); + let mut stdin = stdin.lock(); + let buffer = stdin.fill_buf().unwrap(); + let length = buffer.len(); + let read_bytes = Vec::from(buffer); + stdin.consume(length); + read_bytes + } + fn get_stdout_writer(&self) -> Box { + let stdout = ::std::io::stdout(); + Box::new(stdout) + } + fn send_to_server(&self, msg: ClientToServerMsg) { + self.send_instructions_to_server + .lock() + .unwrap() + .as_mut() + .unwrap() + .send(msg); + } + fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext) { + self.receive_instructions_from_server + .lock() + .unwrap() + .as_mut() + .unwrap() + .recv() + } + fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box) { + let mut signals = Signals::new(&[SIGWINCH, SIGTERM, SIGINT, SIGQUIT, SIGHUP]).unwrap(); + for signal in signals.forever() { + match signal { + SIGWINCH => { + sigwinch_cb(); + } + SIGTERM | SIGINT | SIGQUIT | SIGHUP => { + quit_cb(); + break; + } + _ => unreachable!(), + } + } + } + fn connect_to_server(&self, path: &Path) { + let socket; + loop { + match LocalSocketStream::connect(path) { + Ok(sock) => { + socket = sock; + break; + } + Err(_) => { + std::thread::sleep(std::time::Duration::from_millis(50)); + } + } + } + let sender = IpcSenderWithContext::new(socket); + let receiver = sender.get_receiver(); + *self.send_instructions_to_server.lock().unwrap() = Some(sender); + *self.receive_instructions_from_server.lock().unwrap() = Some(receiver); + } +} + +impl Clone for Box { + fn clone(&self) -> Box { + self.box_clone() + } +} + +pub fn get_client_os_input() -> Result { + let current_termios = termios::tcgetattr(0)?; + let orig_termios = Arc::new(Mutex::new(current_termios)); + Ok(ClientOsInputOutput { + orig_termios, + send_instructions_to_server: Arc::new(Mutex::new(None)), + receive_instructions_from_server: Arc::new(Mutex::new(None)), + }) +} diff --git a/zellij-server/Cargo.toml b/zellij-server/Cargo.toml new file mode 100644 index 0000000000..97930c75bc --- /dev/null +++ b/zellij-server/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "zellij-server" +version = "0.12.0" +authors = ["Kunal Mohan "] +edition = "2018" +description = "The server-side library for Zellij" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +wasmer = "1.0.0" +wasmer-wasi = "1.0.0" +zellij-tile = { path = "../zellij-tile/", version = "0.12.0" } +zellij-utils = { path = "../zellij-utils/", version = "0.12.0" } +vte = "0.10.1" +unicode-width = "0.1.8" +ansi_term = "0.12.1" +serde_yaml = "0.8" +nix = "0.19.1" +termion = "1.5.0" +signal-hook = "0.3" +libc = "0.2" +serde_json = "1.0" +daemonize = "0.4.1" +interprocess = "1.1.1" + +[dependencies.async-std] +version = "1.3.0" +features = ["unstable"] + +[dev-dependencies] +insta = "1.6.0" + +[features] +test = ["zellij-utils/test"] diff --git a/src/server/mod.rs b/zellij-server/src/lib.rs similarity index 85% rename from src/server/mod.rs rename to zellij-server/src/lib.rs index 4c6fb75754..606bf1b0dc 100644 --- a/src/server/mod.rs +++ b/zellij-server/src/lib.rs @@ -1,4 +1,13 @@ -pub mod route; +pub mod os_input_output; +pub mod panes; +pub mod tab; + +mod pty; +mod route; +mod screen; +mod thread_bus; +mod ui; +mod wasm_vm; use std::sync::{Arc, RwLock}; use std::thread; @@ -6,27 +15,28 @@ use std::{path::PathBuf, sync::mpsc}; use wasmer::Store; use zellij_tile::data::PluginCapabilities; -use crate::cli::CliArgs; -use crate::common::thread_bus::{Bus, ThreadSenders}; -use crate::common::{ - errors::ContextType, - input::options::Options, - ipc::{ClientToServerMsg, ServerToClientMsg}, +use crate::{ os_input_output::ServerOsApi, pty::{pty_thread_main, Pty, PtyInstruction}, screen::{screen_thread_main, ScreenInstruction}, - setup::{get_default_data_dir, install::populate_data_dir}, - thread_bus::{ChannelWithContext, SenderType, SenderWithContext, SyncChannelWithContext}, + thread_bus::{Bus, ThreadSenders}, + ui::layout::Layout, wasm_vm::{wasm_thread_main, PluginInstruction}, }; -use crate::layout::Layout; -use crate::panes::PositionAndSize; use route::route_thread_main; +use zellij_utils::{ + channels::{ChannelWithContext, SenderType, SenderWithContext, SyncChannelWithContext}, + cli::CliArgs, + errors::{ContextType, ErrorInstruction, ServerContext}, + input::options::Options, + ipc::{ClientToServerMsg, ServerToClientMsg}, + pane_size::PositionAndSize, + setup::{get_default_data_dir, install::populate_data_dir}, +}; -/// Instructions related to server-side application including the -/// ones sent by client to server +/// Instructions related to server-side application #[derive(Debug, Clone)] -pub enum ServerInstruction { +pub(crate) enum ServerInstruction { NewClient(PositionAndSize, CliArgs, Options), Render(Option), UnblockInputThread, @@ -46,7 +56,25 @@ impl From for ServerInstruction { } } -pub struct SessionMetaData { +impl From<&ServerInstruction> for ServerContext { + fn from(server_instruction: &ServerInstruction) -> Self { + match *server_instruction { + ServerInstruction::NewClient(..) => ServerContext::NewClient, + ServerInstruction::Render(_) => ServerContext::Render, + ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread, + ServerInstruction::ClientExit => ServerContext::ClientExit, + ServerInstruction::Error(_) => ServerContext::Error, + } + } +} + +impl ErrorInstruction for ServerInstruction { + fn error(err: String) -> Self { + ServerInstruction::Error(err) + } +} + +pub(crate) struct SessionMetaData { pub senders: ThreadSenders, pub capabilities: PluginCapabilities, screen_thread: Option>, @@ -66,7 +94,7 @@ impl Drop for SessionMetaData { } pub fn start_server(os_input: Box, socket_path: PathBuf) { - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] daemonize::Daemonize::new() .working_directory(std::env::var("HOME").unwrap()) .umask(0o077) @@ -80,16 +108,16 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { let to_server = SenderWithContext::new(SenderType::SyncSender(to_server)); let sessions: Arc>> = Arc::new(RwLock::new(None)); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] std::panic::set_hook({ - use crate::errors::handle_panic; + use zellij_utils::errors::handle_panic; let to_server = to_server.clone(); Box::new(move |info| { handle_panic(info, &to_server); }) }); - #[cfg(test)] + #[cfg(any(feature = "test", test))] thread::Builder::new() .name("server_router".to_string()) .spawn({ @@ -100,12 +128,12 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { move || route_thread_main(sessions, os_input, to_server) }) .unwrap(); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] let _ = thread::Builder::new() .name("server_listener".to_string()) .spawn({ - use crate::common::os_input_output::set_permissions; use interprocess::local_socket::LocalSocketListener; + use zellij_utils::shared::set_permissions; let os_input = os_input.clone(); let sessions = sessions.clone(); @@ -180,7 +208,7 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { } } } - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] drop(std::fs::remove_file(&socket_path)); } @@ -210,9 +238,9 @@ fn init_session( }; // Don't use default layouts in tests, but do everywhere else - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] let default_layout = Some(PathBuf::from("default")); - #[cfg(test)] + #[cfg(any(feature = "test", test))] let default_layout = None; let maybe_layout = opts .layout diff --git a/src/common/os_input_output.rs b/zellij-server/src/os_input_output.rs similarity index 61% rename from src/common/os_input_output.rs rename to zellij-server/src/os_input_output.rs index 6b849efaba..1fef826b8f 100644 --- a/src/common/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -1,9 +1,3 @@ -use crate::common::ipc::{ - ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg, -}; -use crate::errors::ErrorContext; -use crate::panes::PositionAndSize; -use crate::utils::shared::default_palette; use interprocess::local_socket::LocalSocketStream; use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::pty::{forkpty, Winsize}; @@ -11,56 +5,20 @@ use nix::sys::signal::{kill, Signal}; use nix::sys::termios; use nix::sys::wait::waitpid; use nix::unistd::{self, ForkResult, Pid}; -use signal_hook::{consts::signal::*, iterator::Signals}; -use std::io::prelude::*; -use std::os::unix::{fs::PermissionsExt, io::RawFd}; -use std::path::{Path, PathBuf}; +use signal_hook::consts::*; +use std::env; +use std::os::unix::io::RawFd; +use std::path::PathBuf; use std::process::{Child, Command}; use std::sync::{Arc, Mutex}; -use std::{env, fs, io}; use zellij_tile::data::Palette; +use zellij_utils::errors::ErrorContext; +use zellij_utils::ipc::{ + ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg, +}; +use zellij_utils::shared::default_palette; -const UNIX_PERMISSIONS: u32 = 0o700; - -pub fn set_permissions(path: &Path) -> io::Result<()> { - let mut permissions = fs::metadata(path)?.permissions(); - permissions.set_mode(UNIX_PERMISSIONS); - fs::set_permissions(path, permissions) -} - -fn into_raw_mode(pid: RawFd) { - let mut tio = termios::tcgetattr(pid).expect("could not get terminal attribute"); - termios::cfmakeraw(&mut tio); - match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &tio) { - Ok(_) => {} - Err(e) => panic!("error {:?}", e), - }; -} - -fn unset_raw_mode(pid: RawFd, orig_termios: termios::Termios) { - match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &orig_termios) { - Ok(_) => {} - Err(e) => panic!("error {:?}", e), - }; -} - -pub fn get_terminal_size_using_fd(fd: RawFd) -> PositionAndSize { - // TODO: do this with the nix ioctl - use libc::ioctl; - use libc::TIOCGWINSZ; - - let mut winsize = Winsize { - ws_row: 0, - ws_col: 0, - ws_xpixel: 0, - ws_ypixel: 0, - }; - - unsafe { ioctl(fd, TIOCGWINSZ, &mut winsize) }; - PositionAndSize::from(winsize) -} - -pub fn set_terminal_size_using_fd(fd: RawFd, columns: u16, rows: u16) { +pub(crate) fn set_terminal_size_using_fd(fd: RawFd, columns: u16, rows: u16) { // TODO: do this with the nix ioctl use libc::ioctl; use libc::TIOCSWINSZ; @@ -284,131 +242,3 @@ pub fn get_server_os_input() -> Result { send_instructions_to_client: Arc::new(Mutex::new(None)), }) } - -#[derive(Clone)] -pub struct ClientOsInputOutput { - orig_termios: Arc>, - send_instructions_to_server: Arc>>>, - receive_instructions_from_server: Arc>>>, -} - -/// The `ClientOsApi` trait represents an abstract interface to the features of an operating system that -/// Zellij client 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(&self, fd: RawFd); - /// Returns the writer that allows writing to standard output. - fn get_stdout_writer(&self) -> Box; - /// Returns the raw contents of standard input. - fn read_from_stdin(&self) -> Vec; - /// Returns a [`Box`] pointer to this [`ClientOsApi`] struct. - fn box_clone(&self) -> Box; - /// Sends a message to the server. - fn send_to_server(&self, msg: ClientToServerMsg); - /// Receives a message on client-side IPC channel - // This should be called from the client-side router thread only. - fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext); - fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box); - /// Establish a connection with the server socket. - fn connect_to_server(&self, path: &Path); -} - -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(&self, fd: RawFd) { - let orig_termios = self.orig_termios.lock().unwrap(); - unset_raw_mode(fd, orig_termios.clone()); - } - fn box_clone(&self) -> Box { - Box::new((*self).clone()) - } - fn read_from_stdin(&self) -> Vec { - let stdin = std::io::stdin(); - let mut stdin = stdin.lock(); - let buffer = stdin.fill_buf().unwrap(); - let length = buffer.len(); - let read_bytes = Vec::from(buffer); - stdin.consume(length); - read_bytes - } - fn get_stdout_writer(&self) -> Box { - let stdout = ::std::io::stdout(); - Box::new(stdout) - } - fn send_to_server(&self, msg: ClientToServerMsg) { - self.send_instructions_to_server - .lock() - .unwrap() - .as_mut() - .unwrap() - .send(msg); - } - fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext) { - self.receive_instructions_from_server - .lock() - .unwrap() - .as_mut() - .unwrap() - .recv() - } - fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box) { - let mut signals = Signals::new(&[SIGWINCH, SIGTERM, SIGINT, SIGQUIT, SIGHUP]).unwrap(); - for signal in signals.forever() { - match signal { - SIGWINCH => { - sigwinch_cb(); - } - SIGTERM | SIGINT | SIGQUIT | SIGHUP => { - quit_cb(); - break; - } - _ => unreachable!(), - } - } - } - fn connect_to_server(&self, path: &Path) { - let socket; - loop { - match LocalSocketStream::connect(path) { - Ok(sock) => { - socket = sock; - break; - } - Err(_) => { - std::thread::sleep(std::time::Duration::from_millis(50)); - } - } - } - let sender = IpcSenderWithContext::new(socket); - let receiver = sender.get_receiver(); - *self.send_instructions_to_server.lock().unwrap() = Some(sender); - *self.receive_instructions_from_server.lock().unwrap() = Some(receiver); - } -} - -impl Clone for Box { - fn clone(&self) -> Box { - self.box_clone() - } -} - -pub fn get_client_os_input() -> Result { - let current_termios = termios::tcgetattr(0)?; - let orig_termios = Arc::new(Mutex::new(current_termios)); - Ok(ClientOsInputOutput { - orig_termios, - send_instructions_to_server: Arc::new(Mutex::new(None)), - receive_instructions_from_server: Arc::new(Mutex::new(None)), - }) -} diff --git a/src/client/panes/grid.rs b/zellij-server/src/panes/grid.rs similarity index 99% rename from src/client/panes/grid.rs rename to zellij-server/src/panes/grid.rs index e51b1ed55f..83e8c70f6b 100644 --- a/src/client/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -9,9 +9,7 @@ use vte::{Params, Perform}; const TABSTOP_WIDTH: usize = 8; // TODO: is this always right? const SCROLL_BACK: usize = 10_000; -use crate::utils::consts::VERSION; -use crate::utils::logging::debug_log_to_file; -use crate::utils::shared::version_number; +use zellij_utils::{consts::VERSION, logging::debug_log_to_file, shared::version_number}; use crate::panes::terminal_character::{ CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset, TerminalCharacter, @@ -1347,7 +1345,7 @@ impl Perform for Grid { } } else { let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params)); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] result.unwrap(); } } @@ -1436,13 +1434,19 @@ impl Debug for Row { } } -impl Row { - pub fn new() -> Self { +impl Default for Row { + fn default() -> Self { Row { columns: vec![], is_canonical: false, } } +} + +impl Row { + pub fn new() -> Self { + Self::default() + } pub fn from_columns(columns: Vec) -> Self { Row { columns, @@ -1528,6 +1532,9 @@ impl Row { pub fn len(&self) -> usize { self.columns.len() } + pub fn is_empty(&self) -> bool { + self.columns.is_empty() + } pub fn delete_character(&mut self, x: usize) { if x < self.columns.len() { self.columns.remove(x); diff --git a/src/client/panes/mod.rs b/zellij-server/src/panes/mod.rs similarity index 82% rename from src/client/panes/mod.rs rename to zellij-server/src/panes/mod.rs index 4e7d6e8027..187b364d25 100644 --- a/src/client/panes/mod.rs +++ b/zellij-server/src/panes/mod.rs @@ -4,6 +4,6 @@ mod terminal_character; mod terminal_pane; pub use grid::*; -pub use plugin_pane::*; +pub(crate) use plugin_pane::*; pub use terminal_character::*; pub use terminal_pane::*; diff --git a/src/client/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs similarity index 98% rename from src/client/panes/plugin_pane.rs rename to zellij-server/src/panes/plugin_pane.rs index dde3cd9b26..5549a388fe 100644 --- a/src/client/panes/plugin_pane.rs +++ b/zellij-server/src/panes/plugin_pane.rs @@ -2,13 +2,13 @@ use std::sync::mpsc::channel; use std::time::Instant; use std::unimplemented; -use crate::common::thread_bus::SenderWithContext; -use crate::panes::{PaneId, PositionAndSize}; +use crate::panes::PaneId; use crate::pty::VteBytes; use crate::tab::Pane; use crate::wasm_vm::PluginInstruction; +use zellij_utils::{channels::SenderWithContext, pane_size::PositionAndSize}; -pub struct PluginPane { +pub(crate) struct PluginPane { pub pid: u32, pub should_render: bool, pub selectable: bool, diff --git a/src/client/panes/terminal_character.rs b/zellij-server/src/panes/terminal_character.rs similarity index 99% rename from src/client/panes/terminal_character.rs rename to zellij-server/src/panes/terminal_character.rs index d2340e2e44..c55569f05e 100644 --- a/src/client/panes/terminal_character.rs +++ b/zellij-server/src/panes/terminal_character.rs @@ -1,10 +1,10 @@ use unicode_width::UnicodeWidthChar; -use crate::utils::logging::debug_log_to_file; use std::convert::TryFrom; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::{Index, IndexMut}; use vte::ParamsIter; +use zellij_utils::logging::debug_log_to_file; pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter { character: ' ', @@ -110,9 +110,9 @@ pub struct CharacterStyles { pub italic: Option, } -impl CharacterStyles { - pub fn new() -> Self { - CharacterStyles { +impl Default for CharacterStyles { + fn default() -> Self { + Self { foreground: None, background: None, strike: None, @@ -126,6 +126,12 @@ impl CharacterStyles { italic: None, } } +} + +impl CharacterStyles { + pub fn new() -> Self { + Self::default() + } pub fn foreground(mut self, foreground_code: Option) -> Self { self.foreground = foreground_code; self diff --git a/src/client/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs similarity index 93% rename from src/client/panes/terminal_pane.rs rename to zellij-server/src/panes/terminal_pane.rs index 5c4f55c8c5..25834c35dd 100644 --- a/src/client/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -1,45 +1,23 @@ use std::fmt::Debug; use std::os::unix::io::RawFd; use std::time::Instant; +use zellij_utils::pane_size::PositionAndSize; -use nix::pty::Winsize; -use serde::{Deserialize, Serialize}; - -use crate::panes::grid::Grid; -use crate::panes::terminal_character::{ - CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, +use crate::panes::{ + grid::Grid, + terminal_character::{ + CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, + }, }; use crate::pty::VteBytes; use crate::tab::Pane; -#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Debug)] pub enum PaneId { Terminal(RawFd), Plugin(u32), // FIXME: Drop the trait object, make this a wrapper for the struct? } -/// Contains the position and size of a [`Pane`], or more generally of any terminal, measured -/// in character rows and columns. -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] -pub struct PositionAndSize { - pub x: usize, - pub y: usize, - pub rows: usize, - pub columns: usize, - pub max_rows: Option, - pub max_columns: Option, -} - -impl From for PositionAndSize { - fn from(winsize: Winsize) -> PositionAndSize { - PositionAndSize { - columns: winsize.ws_col as usize, - rows: winsize.ws_row as usize, - ..Default::default() - } - } -} - pub struct TerminalPane { pub grid: Grid, pub pid: RawFd, @@ -354,7 +332,7 @@ impl TerminalPane { pub fn read_buffer_as_lines(&self) -> Vec> { self.grid.as_character_lines() } - #[cfg(test)] + #[cfg(any(feature = "test", test))] pub fn cursor_coordinates(&self) -> Option<(usize, usize)> { // (x, y) self.grid.cursor_coordinates() diff --git a/src/client/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs similarity index 99% rename from src/client/panes/unit/grid_tests.rs rename to zellij-server/src/panes/unit/grid_tests.rs index 8517a975ef..1cd623b6e0 100644 --- a/src/client/panes/unit/grid_tests.rs +++ b/zellij-server/src/panes/unit/grid_tests.rs @@ -3,7 +3,7 @@ use ::insta::assert_snapshot; fn read_fixture(fixture_name: &str) -> Vec { let mut path_to_file = std::path::PathBuf::new(); - path_to_file.push("src"); + path_to_file.push("../src"); path_to_file.push("tests"); path_to_file.push("fixtures"); path_to_file.push(fixture_name); diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_b.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap similarity index 57% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_b.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap index 1d0c34e5f6..2be051c55f 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_b.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_i.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap similarity index 67% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_i.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap index 11f7b8f85d..44026d0465 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_i.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_z.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap similarity index 61% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_z.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap index 04f492b86d..2411b25f0f 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_z.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__terminal_reports.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap similarity index 79% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__terminal_reports.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap index b2dca273ca..d289d93fc3 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__terminal_reports.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid . pending_messages_to_pty)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_0.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_0.snap index 8641098c45..f469f2ef6e 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_1.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_1.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_1.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_1.snap index 09663484d2..6a43da94a0 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_1.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_1.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_2.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_2.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_2.snap index 05d80b1d61..5250338a9d 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_2.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_2.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_3.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_3.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_3.snap index 64c3e7b95c..f33ce41454 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_3.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_3.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_4.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_4.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_4.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_4.snap index dcb417ae15..411bcec55f 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_4.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_4.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_5.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_5.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_5.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_5.snap index d044691ce7..5d16f7d6aa 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_5.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_5.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_0.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_0.snap index f5bd11a5b7..a8250e2998 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_1.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_1.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_1.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_1.snap index 148b873263..8dbcd8fef1 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_1.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_1.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_10.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_10.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_10.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_10.snap index 7cbb854587..8fddefa01c 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_10.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_10.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_11.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_11.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_11.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_11.snap index 1201290ba2..df92663d9f 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_11.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_11.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_12.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_12.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_12.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_12.snap index fc15da63f7..6373f0d5b7 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_12.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_12.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_13.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_13.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_13.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_13.snap index ee8e30fbe2..d250858fe4 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_13.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_13.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_14.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_14.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_14.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_14.snap index 2bdf195612..7d86b997a1 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_14.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_14.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_2.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_2.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_2.snap index 91a9a2e678..d751b7b5f7 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_2.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_2.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_3.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_3.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_3.snap index c3881efba7..0ee924ac44 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_3.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_3.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_4.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_4.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_4.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_4.snap index 089f3d7d46..7c8192796a 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_4.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_4.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_5.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_5.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_5.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_5.snap index 6cf729c1e2..3d14e04214 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_5.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_5.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_6.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_6.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_6.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_6.snap index 3c6a1c7765..20a8aecd7e 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_6.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_6.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_7.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_7.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_7.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_7.snap index 0c4c5cacaf..4a980ffcbb 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_7.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_7.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_8.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_8.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_8.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_8.snap index 9e9ac89141..413f7c8e95 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_8.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_8.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_9.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_9.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_9.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_9.snap index 852203c8dd..6759d12449 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_9.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_9.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest3_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest3_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap index 6902cf25d5..0f9c5ce60e 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest3_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_0.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_0.snap index 18cdd01bb2..86e447a962 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_1.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_1.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_1.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_1.snap index 7618e82bd6..4381306b86 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_1.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_1.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_2.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_2.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_2.snap index 0873ec2336..b65ed724f9 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_2.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_2.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_3.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_3.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_3.snap index 049f508364..d18554a86a 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_3.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_3.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_4.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_4.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_4.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_4.snap index e7eb978fcb..c45da961fc 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_4.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_4.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_5.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_5.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_5.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_5.snap index 9b54cbc8cf..00b8b310ca 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_5.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_5.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/common/pty.rs b/zellij-server/src/pty.rs similarity index 89% rename from src/common/pty.rs rename to zellij-server/src/pty.rs index 5f5442b510..373b5f0b50 100644 --- a/src/common/pty.rs +++ b/zellij-server/src/pty.rs @@ -7,15 +7,19 @@ use std::path::PathBuf; use std::pin::*; use std::time::{Duration, Instant}; -use crate::client::panes::PaneId; -use crate::common::errors::{get_current_ctx, ContextType}; -use crate::common::screen::ScreenInstruction; -use crate::common::thread_bus::{Bus, ThreadSenders}; -use crate::layout::Layout; -use crate::os_input_output::ServerOsApi; -use crate::server::ServerInstruction; -use crate::utils::logging::debug_to_file; -use crate::wasm_vm::PluginInstruction; +use crate::{ + os_input_output::ServerOsApi, + panes::PaneId, + screen::ScreenInstruction, + thread_bus::{Bus, ThreadSenders}, + ui::layout::Layout, + wasm_vm::PluginInstruction, + ServerInstruction, +}; +use zellij_utils::{ + errors::{get_current_ctx, ContextType, PtyContext}, + logging::debug_to_file, +}; pub struct ReadFromPid { pid: RawFd, @@ -67,7 +71,7 @@ pub type VteBytes = Vec; /// Instructions related to PTYs (pseudoterminals). #[derive(Clone, Debug)] -pub enum PtyInstruction { +pub(crate) enum PtyInstruction { SpawnTerminal(Option), SpawnTerminalVertically(Option), SpawnTerminalHorizontally(Option), @@ -77,14 +81,28 @@ pub enum PtyInstruction { Exit, } -pub struct Pty { +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::CloseTab(_) => PtyContext::CloseTab, + PtyInstruction::NewTab => PtyContext::NewTab, + PtyInstruction::Exit => PtyContext::Exit, + } + } +} + +pub(crate) struct Pty { pub bus: Bus, pub id_to_child_pid: HashMap, debug_to_file: bool, task_handles: HashMap>, } -pub fn pty_thread_main(mut pty: Pty, maybe_layout: Option) { +pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option) { loop { let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Pty((&event).into())); @@ -196,7 +214,7 @@ fn stream_terminal_bytes( } } senders.send_to_screen(ScreenInstruction::Render).unwrap(); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", 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 diff --git a/src/server/route.rs b/zellij-server/src/route.rs similarity index 94% rename from src/server/route.rs rename to zellij-server/src/route.rs index c435a0e65f..1d25ae77c4 100644 --- a/src/server/route.rs +++ b/zellij-server/src/route.rs @@ -2,15 +2,18 @@ use std::sync::{Arc, RwLock}; use zellij_tile::data::Event; -use crate::common::input::actions::{Action, Direction}; -use crate::common::input::handler::get_mode_info; -use crate::common::ipc::ClientToServerMsg; -use crate::common::os_input_output::ServerOsApi; -use crate::common::pty::PtyInstruction; -use crate::common::screen::ScreenInstruction; -use crate::common::thread_bus::SenderWithContext; -use crate::common::wasm_vm::PluginInstruction; -use crate::server::{ServerInstruction, SessionMetaData}; +use crate::{ + os_input_output::ServerOsApi, pty::PtyInstruction, screen::ScreenInstruction, + wasm_vm::PluginInstruction, ServerInstruction, SessionMetaData, +}; +use zellij_utils::{ + channels::SenderWithContext, + input::{ + actions::{Action, Direction}, + get_mode_info, + }, + ipc::ClientToServerMsg, +}; fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn ServerOsApi) { match action { @@ -181,7 +184,7 @@ fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn Server } } -pub fn route_thread_main( +pub(crate) fn route_thread_main( sessions: Arc>>, mut os_input: Box, to_server: SenderWithContext, diff --git a/src/common/screen.rs b/zellij-server/src/screen.rs similarity index 84% rename from src/common/screen.rs rename to zellij-server/src/screen.rs index 62fcec1955..91619c57ce 100644 --- a/src/common/screen.rs +++ b/zellij-server/src/screen.rs @@ -4,22 +4,25 @@ use std::collections::BTreeMap; use std::os::unix::io::RawFd; use std::str; -use crate::common::input::options::Options; -use crate::common::pty::{PtyInstruction, VteBytes}; -use crate::common::thread_bus::Bus; -use crate::errors::ContextType; -use crate::layout::Layout; -use crate::panes::PaneId; -use crate::panes::PositionAndSize; -use crate::server::ServerInstruction; -use crate::tab::Tab; -use crate::wasm_vm::PluginInstruction; - +use crate::{ + panes::PaneId, + pty::{PtyInstruction, VteBytes}, + tab::Tab, + thread_bus::Bus, + ui::layout::Layout, + wasm_vm::PluginInstruction, + ServerInstruction, +}; use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PluginCapabilities, TabInfo}; +use zellij_utils::{ + errors::{ContextType, ScreenContext}, + input::options::Options, + pane_size::PositionAndSize, +}; /// Instructions that can be sent to the [`Screen`]. #[derive(Debug, Clone)] -pub enum ScreenInstruction { +pub(crate) enum ScreenInstruction { PtyBytes(RawFd, VteBytes), Render, NewPane(PaneId), @@ -63,9 +66,61 @@ pub enum ScreenInstruction { ChangeMode(ModeInfo), } +impl From<&ScreenInstruction> for ScreenContext { + fn from(screen_instruction: &ScreenInstruction) -> Self { + match *screen_instruction { + ScreenInstruction::PtyBytes(..) => ScreenContext::HandlePtyBytes, + 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::SwitchFocus => ScreenContext::SwitchFocus, + ScreenInstruction::FocusNextPane => ScreenContext::FocusNextPane, + ScreenInstruction::FocusPreviousPane => ScreenContext::FocusPreviousPane, + ScreenInstruction::MoveFocusLeft => ScreenContext::MoveFocusLeft, + ScreenInstruction::MoveFocusLeftOrPreviousTab => { + ScreenContext::MoveFocusLeftOrPreviousTab + } + ScreenInstruction::MoveFocusDown => ScreenContext::MoveFocusDown, + ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp, + ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight, + ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab, + ScreenInstruction::Exit => ScreenContext::Exit, + ScreenInstruction::ScrollUp => ScreenContext::ScrollUp, + ScreenInstruction::ScrollDown => ScreenContext::ScrollDown, + ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp, + ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown, + ScreenInstruction::ClearScroll => ScreenContext::ClearScroll, + ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane, + ScreenInstruction::ToggleActiveTerminalFullscreen => { + ScreenContext::ToggleActiveTerminalFullscreen + } + ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable, + ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders, + ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight, + ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane, + ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout, + ScreenInstruction::NewTab(_) => ScreenContext::NewTab, + ScreenInstruction::SwitchTabNext => ScreenContext::SwitchTabNext, + ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev, + ScreenInstruction::CloseTab => ScreenContext::CloseTab, + ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab, + ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName, + ScreenInstruction::TerminalResize(_) => ScreenContext::TerminalResize, + ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode, + ScreenInstruction::ToggleActiveSyncTab => ScreenContext::ToggleActiveSyncTab, + } + } +} + /// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes). /// It only directly controls which tab is active, delegating the rest to the individual `Tab`. -pub struct Screen { +pub(crate) struct Screen { /// A Bus for sending and receiving messages with the other threads. pub bus: Bus, /// An optional maximal amount of panes allowed per [`Tab`] in this [`Screen`] instance. @@ -325,7 +380,7 @@ impl Screen { } } -pub fn screen_thread_main( +pub(crate) fn screen_thread_main( bus: Bus, max_panes: Option, full_screen_ws: PositionAndSize, diff --git a/src/client/tab.rs b/zellij-server/src/tab.rs similarity index 99% rename from src/client/tab.rs rename to zellij-server/src/tab.rs index 29a41530c8..e41cb530dd 100644 --- a/src/client/tab.rs +++ b/zellij-server/src/tab.rs @@ -1,17 +1,15 @@ //! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size, //! as well as how they should be resized -use crate::client::pane_resizer::PaneResizer; -use crate::common::input::handler::parse_keys; -use crate::common::thread_bus::ThreadSenders; -use crate::layout::Layout; -use crate::os_input_output::ServerOsApi; -use crate::panes::{PaneId, PositionAndSize, TerminalPane}; -use crate::pty::{PtyInstruction, VteBytes}; -use crate::server::ServerInstruction; -use crate::utils::shared::adjust_to_size; -use crate::wasm_vm::PluginInstruction; -use crate::{boundaries::Boundaries, panes::PluginPane}; +use crate::{ + os_input_output::ServerOsApi, + panes::{PaneId, PluginPane, TerminalPane}, + pty::{PtyInstruction, VteBytes}, + thread_bus::ThreadSenders, + ui::{boundaries::Boundaries, layout::Layout, pane_resizer::PaneResizer}, + wasm_vm::PluginInstruction, + ServerInstruction, +}; use serde::{Deserialize, Serialize}; use std::os::unix::io::RawFd; use std::sync::mpsc::channel; @@ -21,6 +19,7 @@ use std::{ collections::{BTreeMap, HashSet}, }; use zellij_tile::data::{Event, InputMode, ModeInfo, Palette}; +use zellij_utils::{input::parse_keys, pane_size::PositionAndSize, shared::adjust_to_size}; const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this @@ -59,7 +58,7 @@ fn split_horizontally_with_gap(rect: &PositionAndSize) -> (PositionAndSize, Posi (first_rect, second_rect) } -pub struct Tab { +pub(crate) struct Tab { pub index: usize, pub position: usize, pub name: String, @@ -79,7 +78,7 @@ pub struct Tab { } #[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct TabData { +pub(crate) struct TabData { /* subset of fields to publish to plugins */ pub position: usize, pub name: String, diff --git a/zellij-server/src/thread_bus.rs b/zellij-server/src/thread_bus.rs new file mode 100644 index 0000000000..afc1d875b9 --- /dev/null +++ b/zellij-server/src/thread_bus.rs @@ -0,0 +1,80 @@ +//! Definitions and helpers for sending and receiving messages between threads. + +use crate::{ + os_input_output::ServerOsApi, pty::PtyInstruction, screen::ScreenInstruction, + wasm_vm::PluginInstruction, ServerInstruction, +}; +use std::sync::mpsc; +use zellij_utils::{channels::SenderWithContext, errors::ErrorContext}; + +/// A container for senders to the different threads in zellij on the server side +#[derive(Clone)] +pub(crate) struct ThreadSenders { + pub to_screen: Option>, + pub to_pty: Option>, + pub to_plugin: Option>, + pub to_server: Option>, +} + +impl ThreadSenders { + pub fn send_to_screen( + &self, + instruction: ScreenInstruction, + ) -> Result<(), mpsc::SendError<(ScreenInstruction, ErrorContext)>> { + self.to_screen.as_ref().unwrap().send(instruction) + } + + pub fn send_to_pty( + &self, + instruction: PtyInstruction, + ) -> Result<(), mpsc::SendError<(PtyInstruction, ErrorContext)>> { + self.to_pty.as_ref().unwrap().send(instruction) + } + + pub fn send_to_plugin( + &self, + instruction: PluginInstruction, + ) -> Result<(), mpsc::SendError<(PluginInstruction, ErrorContext)>> { + self.to_plugin.as_ref().unwrap().send(instruction) + } + + pub fn send_to_server( + &self, + instruction: ServerInstruction, + ) -> Result<(), mpsc::SendError<(ServerInstruction, ErrorContext)>> { + self.to_server.as_ref().unwrap().send(instruction) + } +} + +/// A container for a receiver, OS input and the senders to a given thread +pub(crate) struct Bus { + pub receiver: mpsc::Receiver<(T, ErrorContext)>, + pub senders: ThreadSenders, + pub os_input: Option>, +} + +impl Bus { + pub fn new( + receiver: mpsc::Receiver<(T, ErrorContext)>, + to_screen: Option<&SenderWithContext>, + to_pty: Option<&SenderWithContext>, + to_plugin: Option<&SenderWithContext>, + to_server: Option<&SenderWithContext>, + os_input: Option>, + ) -> Self { + Bus { + receiver, + senders: ThreadSenders { + to_screen: to_screen.cloned(), + to_pty: to_pty.cloned(), + to_plugin: to_plugin.cloned(), + to_server: to_server.cloned(), + }, + os_input: os_input.clone(), + } + } + + pub fn recv(&self) -> Result<(T, ErrorContext), mpsc::RecvError> { + self.receiver.recv() + } +} diff --git a/src/client/boundaries.rs b/zellij-server/src/ui/boundaries.rs similarity index 99% rename from src/client/boundaries.rs rename to zellij-server/src/ui/boundaries.rs index 86fb37fcbd..984b137629 100644 --- a/src/client/boundaries.rs +++ b/zellij-server/src/ui/boundaries.rs @@ -1,8 +1,8 @@ use crate::tab::Pane; -use crate::utils::shared::colors; use ansi_term::Colour::{Fixed, RGB}; use std::collections::HashMap; use zellij_tile::data::{InputMode, Palette, PaletteColor}; +use zellij_utils::shared::colors; use std::fmt::{Display, Error, Formatter}; pub mod boundary_type { @@ -19,10 +19,10 @@ pub mod boundary_type { pub const CROSS: &str = "┼"; } -pub type BoundaryType = &'static str; // easy way to refer to boundary_type above +pub(crate) type BoundaryType = &'static str; // easy way to refer to boundary_type above #[derive(Clone, Copy, Debug)] -pub struct BoundarySymbol { +pub(crate) struct BoundarySymbol { boundary_type: BoundaryType, invisible: bool, color: Option, @@ -392,7 +392,7 @@ fn combine_symbols( } #[derive(PartialEq, Eq, Hash, Debug)] -pub struct Coordinates { +pub(crate) struct Coordinates { x: usize, y: usize, } @@ -403,7 +403,7 @@ impl Coordinates { } } -pub trait Rect { +pub(crate) trait Rect { fn x(&self) -> usize; fn y(&self) -> usize; fn rows(&self) -> usize; diff --git a/src/client/layout.rs b/zellij-server/src/ui/layout.rs similarity index 98% rename from src/client/layout.rs rename to zellij-server/src/ui/layout.rs index 3648ece904..9edf50474b 100644 --- a/src/client/layout.rs +++ b/zellij-server/src/ui/layout.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; use std::{fs::File, io::prelude::*}; -use crate::panes::PositionAndSize; +use zellij_utils::pane_size::PositionAndSize; fn split_space_to_parts_vertically( space_to_split: &PositionAndSize, @@ -167,19 +167,19 @@ fn split_space( } #[derive(Debug, Serialize, Deserialize, Clone)] -pub enum Direction { +pub(crate) enum Direction { Horizontal, Vertical, } #[derive(Debug, Serialize, Deserialize, Clone, Copy)] -pub enum SplitSize { +pub(crate) enum SplitSize { Percent(u8), // 1 to 100 Fixed(u16), // An absolute number of columns or rows } #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Layout { +pub(crate) struct Layout { pub direction: Direction, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub parts: Vec, diff --git a/zellij-server/src/ui/mod.rs b/zellij-server/src/ui/mod.rs new file mode 100644 index 0000000000..1e4c85fd3b --- /dev/null +++ b/zellij-server/src/ui/mod.rs @@ -0,0 +1,3 @@ +pub mod boundaries; +pub mod layout; +pub mod pane_resizer; diff --git a/src/client/pane_resizer.rs b/zellij-server/src/ui/pane_resizer.rs similarity index 99% rename from src/client/pane_resizer.rs rename to zellij-server/src/ui/pane_resizer.rs index 73678499c9..b2001945eb 100644 --- a/src/client/pane_resizer.rs +++ b/zellij-server/src/ui/pane_resizer.rs @@ -1,12 +1,11 @@ -use crate::os_input_output::ServerOsApi; -use crate::panes::{PaneId, PositionAndSize}; -use crate::tab::Pane; +use crate::{os_input_output::ServerOsApi, panes::PaneId, tab::Pane}; use std::{ cmp::Ordering, collections::{BTreeMap, HashSet}, }; +use zellij_utils::pane_size::PositionAndSize; -pub struct PaneResizer<'a> { +pub(crate) struct PaneResizer<'a> { panes: &'a mut BTreeMap>, os_api: &'a mut Box, } diff --git a/src/common/wasm_vm.rs b/zellij-server/src/wasm_vm.rs similarity index 91% rename from src/common/wasm_vm.rs rename to zellij-server/src/wasm_vm.rs index 51eb4ed8dc..65f5358add 100644 --- a/src/common/wasm_vm.rs +++ b/zellij-server/src/wasm_vm.rs @@ -15,14 +15,16 @@ use wasmer::{ use wasmer_wasi::{Pipe, WasiEnv, WasiState}; use zellij_tile::data::{Event, EventType, PluginIds}; -use crate::common::errors::ContextType; -use crate::common::pty::PtyInstruction; -use crate::common::screen::ScreenInstruction; -use crate::common::thread_bus::{Bus, ThreadSenders}; -use crate::common::PaneId; +use crate::{ + panes::PaneId, + pty::PtyInstruction, + screen::ScreenInstruction, + thread_bus::{Bus, ThreadSenders}, +}; +use zellij_utils::errors::{ContextType, PluginContext}; #[derive(Clone, Debug)] -pub enum PluginInstruction { +pub(crate) enum PluginInstruction { Load(Sender, PathBuf), Update(Option, Event), // Focused plugin / broadcast, event data Render(Sender, u32, usize, usize), // String buffer, plugin id, rows, cols @@ -30,8 +32,20 @@ pub enum PluginInstruction { Exit, } +impl From<&PluginInstruction> for PluginContext { + fn from(plugin_instruction: &PluginInstruction) -> Self { + match *plugin_instruction { + PluginInstruction::Load(..) => PluginContext::Load, + PluginInstruction::Update(..) => PluginContext::Update, + PluginInstruction::Render(..) => PluginContext::Render, + PluginInstruction::Unload(_) => PluginContext::Unload, + PluginInstruction::Exit => PluginContext::Exit, + } + } +} + #[derive(WasmerEnv, Clone)] -pub struct PluginEnv { +pub(crate) struct PluginEnv { pub plugin_id: u32, pub senders: ThreadSenders, pub wasi_env: WasiEnv, @@ -39,7 +53,7 @@ pub struct PluginEnv { } // Thread main -------------------------------------------------------------------------------------------------------- -pub fn wasm_thread_main(bus: Bus, store: Store, data_dir: PathBuf) { +pub(crate) fn wasm_thread_main(bus: Bus, store: Store, data_dir: PathBuf) { let mut plugin_id = 0; let mut plugin_map = HashMap::new(); loop { @@ -126,7 +140,7 @@ pub fn wasm_thread_main(bus: Bus, store: Store, data_dir: Pat // Plugin API --------------------------------------------------------------------------------------------------------- -pub fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObject { +pub(crate) fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObject { macro_rules! zellij_export { ($($host_function:ident),+ $(,)?) => { imports! { diff --git a/zellij-utils/Cargo.toml b/zellij-utils/Cargo.toml new file mode 100644 index 0000000000..d33ac659dd --- /dev/null +++ b/zellij-utils/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "zellij-utils" +version = "0.12.0" +authors = ["Kunal Mohan "] +edition = "2018" +description = "A utility library for Zellij client and server" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +backtrace = "0.3.55" +bincode = "1.3.1" +interprocess = "1.1.1" +structopt = "0.3" +serde = { version = "1.0", features = ["derive"] } +zellij-tile = { path = "../zellij-tile/", version = "0.12.0" } +names = "0.11.0" +colors-transform = "0.2.5" +strip-ansi-escapes = "0.1.0" +strum = "0.20.0" +serde_yaml = "0.8" +nix = "0.19.1" +lazy_static = "1.4.0" +directories-next = "2.0" +termion = "1.5.0" + +[dependencies.async-std] +version = "1.3.0" +features = ["unstable"] + +[dev-dependencies] +tempfile = "3.2.0" + +[features] +test = [] diff --git a/zellij-utils/src/channels.rs b/zellij-utils/src/channels.rs new file mode 100644 index 0000000000..8a97fa7d8a --- /dev/null +++ b/zellij-utils/src/channels.rs @@ -0,0 +1,65 @@ +//! Definitions and helpers for sending and receiving messages between threads. + +use async_std::task_local; +use std::cell::RefCell; +use std::sync::mpsc; + +use crate::errors::{get_current_ctx, ErrorContext}; + +/// An [MPSC](mpsc) asynchronous channel with added error context. +pub type ChannelWithContext = ( + mpsc::Sender<(T, ErrorContext)>, + mpsc::Receiver<(T, ErrorContext)>, +); +/// An [MPSC](mpsc) synchronous channel with added error context. +pub type SyncChannelWithContext = ( + mpsc::SyncSender<(T, ErrorContext)>, + mpsc::Receiver<(T, ErrorContext)>, +); + +/// Wrappers around the two standard [MPSC](mpsc) sender types, [`mpsc::Sender`] and [`mpsc::SyncSender`], with an additional [`ErrorContext`]. +#[derive(Clone)] +pub enum SenderType { + /// A wrapper around an [`mpsc::Sender`], adding an [`ErrorContext`]. + Sender(mpsc::Sender<(T, ErrorContext)>), + /// A wrapper around an [`mpsc::SyncSender`], adding an [`ErrorContext`]. + SyncSender(mpsc::SyncSender<(T, ErrorContext)>), +} + +/// Sends messages on an [MPSC](std::sync::mpsc) channel, along with an [`ErrorContext`], +/// synchronously or asynchronously depending on the underlying [`SenderType`]. +#[derive(Clone)] +pub struct SenderWithContext { + sender: SenderType, +} + +impl SenderWithContext { + pub fn new(sender: SenderType) -> Self { + Self { sender } + } + + /// Sends an event, along with the current [`ErrorContext`], on this + /// [`SenderWithContext`]'s channel. + pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> { + let err_ctx = get_current_ctx(); + match self.sender { + SenderType::Sender(ref s) => s.send((event, err_ctx)), + SenderType::SyncSender(ref s) => s.send((event, err_ctx)), + } + } +} + +unsafe impl Send for SenderWithContext {} +unsafe impl Sync for SenderWithContext {} + +thread_local!( + /// A key to some thread local storage (TLS) that holds a representation of the thread's call + /// stack in the form of an [`ErrorContext`]. + pub static OPENCALLS: RefCell = RefCell::default() +); + +task_local! { + /// A key to some task local storage that holds a representation of the task's call + /// stack in the form of an [`ErrorContext`]. + pub static ASYNCOPENCALLS: RefCell = RefCell::default() +} diff --git a/src/cli.rs b/zellij-utils/src/cli.rs similarity index 90% rename from src/cli.rs rename to zellij-utils/src/cli.rs index 9ea84374c6..861a736cdf 100644 --- a/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -1,6 +1,6 @@ -use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; -use crate::common::input::options::Options; -use crate::common::setup::Setup; +use crate::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; +use crate::input::options::Options; +use crate::setup::Setup; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use structopt::StructOpt; diff --git a/src/common/utils/consts.rs b/zellij-utils/src/consts.rs similarity index 97% rename from src/common/utils/consts.rs rename to zellij-utils/src/consts.rs index 42843eb89f..799e29132e 100644 --- a/src/common/utils/consts.rs +++ b/zellij-utils/src/consts.rs @@ -1,6 +1,6 @@ //! Zellij program-wide constants. -use crate::os_input_output::set_permissions; +use crate::shared::set_permissions; use directories_next::ProjectDirs; use lazy_static::lazy_static; use nix::unistd::Uid; diff --git a/src/common/errors.rs b/zellij-utils/src/errors.rs similarity index 55% rename from src/common/errors.rs rename to zellij-utils/src/errors.rs index 262dfd6bc3..94a894c464 100644 --- a/src/common/errors.rs +++ b/zellij-utils/src/errors.rs @@ -1,43 +1,20 @@ //! Error context system based on a thread-local representation of the call stack, itself based on //! the instructions that are sent between threads. +use crate::channels::{SenderWithContext, ASYNCOPENCALLS, OPENCALLS}; use serde::{Deserialize, Serialize}; - use std::fmt::{Display, Error, Formatter}; - -use crate::client::ClientInstruction; -use crate::common::thread_bus::{ASYNCOPENCALLS, OPENCALLS}; -use crate::pty::PtyInstruction; -use crate::screen::ScreenInstruction; -use crate::server::ServerInstruction; +use std::panic::PanicInfo; /// The maximum amount of calls an [`ErrorContext`] will keep track /// of in its stack representation. This is a per-thread maximum. const MAX_THREAD_CALL_STACK: usize = 6; -#[cfg(not(test))] -use super::thread_bus::SenderWithContext; -#[cfg(not(test))] -use std::panic::PanicInfo; - pub trait ErrorInstruction { fn error(err: String) -> Self; } -impl ErrorInstruction for ClientInstruction { - fn error(err: String) -> Self { - ClientInstruction::Error(err) - } -} - -impl ErrorInstruction for ServerInstruction { - fn error(err: String) -> Self { - ServerInstruction::Error(err) - } -} - /// Custom panic handler/hook. Prints the [`ErrorContext`]. -#[cfg(not(test))] pub fn handle_panic(info: &PanicInfo<'_>, sender: &SenderWithContext) where T: ErrorInstruction + Clone, @@ -243,59 +220,6 @@ pub enum ScreenContext { ChangeMode, } -// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!! -impl From<&ScreenInstruction> for ScreenContext { - fn from(screen_instruction: &ScreenInstruction) -> Self { - match *screen_instruction { - ScreenInstruction::PtyBytes(..) => ScreenContext::HandlePtyBytes, - 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::SwitchFocus => ScreenContext::SwitchFocus, - ScreenInstruction::FocusNextPane => ScreenContext::FocusNextPane, - ScreenInstruction::FocusPreviousPane => ScreenContext::FocusPreviousPane, - ScreenInstruction::MoveFocusLeft => ScreenContext::MoveFocusLeft, - ScreenInstruction::MoveFocusLeftOrPreviousTab => { - ScreenContext::MoveFocusLeftOrPreviousTab - } - ScreenInstruction::MoveFocusDown => ScreenContext::MoveFocusDown, - ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp, - ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight, - ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab, - ScreenInstruction::Exit => ScreenContext::Exit, - ScreenInstruction::ScrollUp => ScreenContext::ScrollUp, - ScreenInstruction::ScrollDown => ScreenContext::ScrollDown, - ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp, - ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown, - ScreenInstruction::ClearScroll => ScreenContext::ClearScroll, - ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane, - ScreenInstruction::ToggleActiveTerminalFullscreen => { - ScreenContext::ToggleActiveTerminalFullscreen - } - ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable, - ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders, - ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight, - ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane, - ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout, - ScreenInstruction::NewTab(_) => ScreenContext::NewTab, - ScreenInstruction::SwitchTabNext => ScreenContext::SwitchTabNext, - ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev, - ScreenInstruction::CloseTab => ScreenContext::CloseTab, - ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab, - ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName, - ScreenInstruction::TerminalResize(_) => ScreenContext::TerminalResize, - ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode, - ScreenInstruction::ToggleActiveSyncTab => ScreenContext::ToggleActiveSyncTab, - } - } -} - /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum PtyContext { @@ -308,24 +232,6 @@ pub enum PtyContext { Exit, } -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::CloseTab(_) => PtyContext::CloseTab, - PtyInstruction::NewTab => PtyContext::NewTab, - PtyInstruction::Exit => PtyContext::Exit, - } - } -} - -// FIXME: This whole pattern *needs* a macro eventually, it's soul-crushing to write - -use crate::wasm_vm::PluginInstruction; - /// Stack call representations corresponding to the different types of [`PluginInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum PluginContext { @@ -336,18 +242,6 @@ pub enum PluginContext { Exit, } -impl From<&PluginInstruction> for PluginContext { - fn from(plugin_instruction: &PluginInstruction) -> Self { - match *plugin_instruction { - PluginInstruction::Load(..) => PluginContext::Load, - PluginInstruction::Update(..) => PluginContext::Update, - PluginInstruction::Render(..) => PluginContext::Render, - PluginInstruction::Unload(_) => PluginContext::Unload, - PluginInstruction::Exit => PluginContext::Exit, - } - } -} - /// Stack call representations corresponding to the different types of [`ClientInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum ClientContext { @@ -358,18 +252,6 @@ pub enum ClientContext { ServerError, } -impl From<&ClientInstruction> for ClientContext { - fn from(client_instruction: &ClientInstruction) -> Self { - match *client_instruction { - ClientInstruction::Exit => ClientContext::Exit, - ClientInstruction::Error(_) => ClientContext::Error, - ClientInstruction::ServerError(_) => ClientContext::ServerError, - ClientInstruction::Render(_) => ClientContext::Render, - ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread, - } - } -} - /// Stack call representations corresponding to the different types of [`ServerInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum ServerContext { @@ -379,15 +261,3 @@ pub enum ServerContext { ClientExit, Error, } - -impl From<&ServerInstruction> for ServerContext { - fn from(server_instruction: &ServerInstruction) -> Self { - match *server_instruction { - ServerInstruction::NewClient(..) => ServerContext::NewClient, - ServerInstruction::Render(_) => ServerContext::Render, - ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread, - ServerInstruction::ClientExit => ServerContext::ClientExit, - ServerInstruction::Error(_) => ServerContext::Error, - } - } -} diff --git a/src/common/input/actions.rs b/zellij-utils/src/input/actions.rs similarity index 100% rename from src/common/input/actions.rs rename to zellij-utils/src/input/actions.rs diff --git a/src/common/input/config.rs b/zellij-utils/src/input/config.rs similarity index 98% rename from src/common/input/config.rs rename to zellij-utils/src/input/config.rs index 3dffe71cf8..a034168905 100644 --- a/src/common/input/config.rs +++ b/zellij-utils/src/input/config.rs @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf}; use super::keybinds::{Keybinds, KeybindsFromYaml}; use super::options::Options; use crate::cli::{CliArgs, ConfigCli}; -use crate::common::setup; +use crate::setup; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; @@ -177,7 +177,7 @@ mod config_test { #[test] fn try_from_cli_args_with_option_clean() { - use crate::common::setup::Setup; + use crate::setup::Setup; let mut opts = CliArgs::default(); opts.option = Some(ConfigCli::Setup(Setup { clean: true, diff --git a/src/common/input/keybinds.rs b/zellij-utils/src/input/keybinds.rs similarity index 100% rename from src/common/input/keybinds.rs rename to zellij-utils/src/input/keybinds.rs diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs new file mode 100644 index 0000000000..2747205b69 --- /dev/null +++ b/zellij-utils/src/input/mod.rs @@ -0,0 +1,87 @@ +//! The way terminal input is handled. + +pub mod actions; +pub mod config; +pub mod keybinds; +pub mod options; + +use termion::input::TermRead; +use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities}; + +/// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds +/// (as pairs of [`String`]s). +// TODO this should probably be automatically generated in some way +pub fn get_mode_info( + mode: InputMode, + palette: Palette, + capabilities: PluginCapabilities, +) -> ModeInfo { + let mut keybinds: Vec<(String, String)> = vec![]; + match mode { + InputMode::Normal | InputMode::Locked => {} + InputMode::Resize => { + keybinds.push(("←↓↑→".to_string(), "Resize".to_string())); + } + InputMode::Pane => { + keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); + keybinds.push(("p".to_string(), "Next".to_string())); + keybinds.push(("n".to_string(), "New".to_string())); + keybinds.push(("d".to_string(), "Down split".to_string())); + keybinds.push(("r".to_string(), "Right split".to_string())); + keybinds.push(("x".to_string(), "Close".to_string())); + keybinds.push(("f".to_string(), "Fullscreen".to_string())); + } + InputMode::Tab => { + keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); + keybinds.push(("n".to_string(), "New".to_string())); + keybinds.push(("x".to_string(), "Close".to_string())); + keybinds.push(("r".to_string(), "Rename".to_string())); + keybinds.push(("s".to_string(), "Sync".to_string())); + } + InputMode::Scroll => { + keybinds.push(("↓↑".to_string(), "Scroll".to_string())); + keybinds.push(("PgUp/PgDn".to_string(), "Scroll Page".to_string())); + } + InputMode::RenameTab => { + keybinds.push(("Enter".to_string(), "when done".to_string())); + } + } + ModeInfo { + mode, + keybinds, + palette, + capabilities, + } +} + +pub fn parse_keys(input_bytes: &[u8]) -> Vec { + input_bytes.keys().flatten().map(cast_termion_key).collect() +} + +// FIXME: This is an absolutely cursed function that should be destroyed as soon +// as an alternative that doesn't touch zellij-tile can be developed... +pub fn cast_termion_key(event: termion::event::Key) -> Key { + match event { + termion::event::Key::Backspace => Key::Backspace, + termion::event::Key::Left => Key::Left, + termion::event::Key::Right => Key::Right, + termion::event::Key::Up => Key::Up, + termion::event::Key::Down => Key::Down, + termion::event::Key::Home => Key::Home, + termion::event::Key::End => Key::End, + termion::event::Key::PageUp => Key::PageUp, + termion::event::Key::PageDown => Key::PageDown, + termion::event::Key::BackTab => Key::BackTab, + termion::event::Key::Delete => Key::Delete, + termion::event::Key::Insert => Key::Insert, + termion::event::Key::F(n) => Key::F(n), + termion::event::Key::Char(c) => Key::Char(c), + termion::event::Key::Alt(c) => Key::Alt(c), + termion::event::Key::Ctrl(c) => Key::Ctrl(c), + termion::event::Key::Null => Key::Null, + termion::event::Key::Esc => Key::Esc, + _ => { + unimplemented!("Encountered an unknown key!") + } + } +} diff --git a/src/common/input/options.rs b/zellij-utils/src/input/options.rs similarity index 100% rename from src/common/input/options.rs rename to zellij-utils/src/input/options.rs diff --git a/src/common/input/unit/keybinds_test.rs b/zellij-utils/src/input/unit/keybinds_test.rs similarity index 100% rename from src/common/input/unit/keybinds_test.rs rename to zellij-utils/src/input/unit/keybinds_test.rs diff --git a/src/common/ipc.rs b/zellij-utils/src/ipc.rs similarity index 98% rename from src/common/ipc.rs rename to zellij-utils/src/ipc.rs index 129727a1ac..6d36481c62 100644 --- a/src/common/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -1,11 +1,11 @@ //! IPC stuff for starting to split things into a client and server model. use crate::cli::CliArgs; -use crate::common::{ +use crate::pane_size::PositionAndSize; +use crate::{ errors::{get_current_ctx, ErrorContext}, input::{actions::Action, options::Options}, }; -use crate::panes::PositionAndSize; use interprocess::local_socket::LocalSocketStream; use nix::unistd::dup; use serde::{Deserialize, Serialize}; diff --git a/zellij-utils/src/lib.rs b/zellij-utils/src/lib.rs new file mode 100644 index 0000000000..35f27244a3 --- /dev/null +++ b/zellij-utils/src/lib.rs @@ -0,0 +1,10 @@ +pub mod channels; +pub mod cli; +pub mod consts; +pub mod errors; +pub mod input; +pub mod ipc; +pub mod logging; +pub mod pane_size; +pub mod setup; +pub mod shared; diff --git a/src/common/utils/logging.rs b/zellij-utils/src/logging.rs similarity index 94% rename from src/common/utils/logging.rs rename to zellij-utils/src/logging.rs index 0dd382d672..d2c57612dd 100644 --- a/src/common/utils/logging.rs +++ b/zellij-utils/src/logging.rs @@ -7,8 +7,8 @@ use std::{ path::{Path, PathBuf}, }; -use crate::os_input_output::set_permissions; -use crate::utils::consts::{ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE}; +use crate::consts::{ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE}; +use crate::shared::set_permissions; pub fn atomic_create_file(file_name: &Path) -> io::Result<()> { let _ = fs::OpenOptions::new() diff --git a/zellij-utils/src/pane_size.rs b/zellij-utils/src/pane_size.rs new file mode 100644 index 0000000000..2744c43fa7 --- /dev/null +++ b/zellij-utils/src/pane_size.rs @@ -0,0 +1,24 @@ +use nix::pty::Winsize; +use serde::{Deserialize, Serialize}; + +/// Contains the position and size of a [`Pane`], or more generally of any terminal, measured +/// in character rows and columns. +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] +pub struct PositionAndSize { + pub x: usize, + pub y: usize, + pub rows: usize, + pub columns: usize, + pub max_rows: Option, + pub max_columns: Option, +} + +impl From for PositionAndSize { + fn from(winsize: Winsize) -> PositionAndSize { + PositionAndSize { + columns: winsize.ws_col as usize, + rows: winsize.ws_row as usize, + ..Default::default() + } + } +} diff --git a/src/common/setup.rs b/zellij-utils/src/setup.rs similarity index 93% rename from src/common/setup.rs rename to zellij-utils/src/setup.rs index 2e07677672..ef51b2e573 100644 --- a/src/common/setup.rs +++ b/zellij-utils/src/setup.rs @@ -1,8 +1,8 @@ use crate::cli::CliArgs; -use crate::common::utils::consts::{ +use crate::consts::{ FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, ZELLIJ_PROJ_DIR, }; -use crate::os_input_output::set_permissions; +use crate::shared::set_permissions; use directories_next::BaseDirs; use serde::{Deserialize, Serialize}; use std::io::Write; @@ -32,13 +32,13 @@ pub mod install { pub fn populate_data_dir(data_dir: &Path) { // First run installation of default plugins & layouts let mut assets = asset_map! { - "assets/layouts/default.yaml" => "layouts/default.yaml", - "assets/layouts/strider.yaml" => "layouts/strider.yaml", + "../assets/layouts/default.yaml" => "layouts/default.yaml", + "../assets/layouts/strider.yaml" => "layouts/strider.yaml", }; assets.extend(asset_map! { - "assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm", - "assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm", - "assets/plugins/strider.wasm" => "plugins/strider.wasm", + "../assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm", + "../assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm", + "../assets/plugins/strider.wasm" => "plugins/strider.wasm", }); assets.insert("VERSION", VERSION.as_bytes().to_vec()); @@ -57,7 +57,7 @@ pub mod install { } } -#[cfg(not(test))] +#[cfg(not(any(feature = "test", test)))] /// Goes through a predefined list and checks for an already /// existing config directory, returns the first match pub fn find_default_config_dir() -> Option { @@ -68,7 +68,7 @@ pub fn find_default_config_dir() -> Option { .flatten() } -#[cfg(test)] +#[cfg(any(feature = "test", test))] pub fn find_default_config_dir() -> Option { None } @@ -119,7 +119,7 @@ pub fn dump_asset(asset: &[u8]) -> std::io::Result<()> { pub const DEFAULT_CONFIG: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/", - "assets/config/default.yaml" + "../assets/config/default.yaml" )); pub fn dump_default_config() -> std::io::Result<()> { @@ -192,7 +192,7 @@ impl Setup { } } if let Some(config_file) = config_file { - use crate::common::input::config::Config; + use crate::input::config::Config; message.push_str(&format!("[CONFIG FILE]: {:?}\n", config_file)); match Config::new(&config_file) { Ok(_) => message.push_str(&"[CONFIG FILE]: Well defined.\n"), diff --git a/src/common/utils/shared.rs b/zellij-utils/src/shared.rs similarity index 91% rename from src/common/utils/shared.rs rename to zellij-utils/src/shared.rs index 26a2f90ac0..bc8b677115 100644 --- a/src/common/utils/shared.rs +++ b/zellij-utils/src/shared.rs @@ -5,8 +5,19 @@ use std::{iter, str::from_utf8}; use strip_ansi_escapes::strip; use colors_transform::{Color, Rgb}; +use std::os::unix::fs::PermissionsExt; +use std::path::Path; +use std::{fs, io}; use zellij_tile::data::{Palette, PaletteColor, PaletteSource, Theme}; +const UNIX_PERMISSIONS: u32 = 0o700; + +pub fn set_permissions(path: &Path) -> io::Result<()> { + let mut permissions = fs::metadata(path)?.permissions(); + permissions.set_mode(UNIX_PERMISSIONS); + fs::set_permissions(path, permissions) +} + fn ansi_len(s: &str) -> usize { from_utf8(&strip(s.as_bytes()).unwrap()) .unwrap()