Big refactor: separate crates for client, server and utilities
This commit is contained in:
parent
28212f5430
commit
2038947a14
99 changed files with 1027 additions and 983 deletions
164
Cargo.lock
generated
164
Cargo.lock
generated
|
|
@ -222,18 +222,6 @@ version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
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]]
|
[[package]]
|
||||||
name = "blocking"
|
name = "blocking"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
@ -620,12 +608,6 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "funty"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.14"
|
version = "0.3.14"
|
||||||
|
|
@ -950,19 +932,6 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a"
|
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]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.93"
|
version = "0.2.93"
|
||||||
|
|
@ -987,9 +956,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.3"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176"
|
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
@ -1074,19 +1043,6 @@ dependencies = [
|
||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
|
@ -1226,12 +1182,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "radium"
|
|
||||||
version = "0.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.3.23"
|
version = "0.3.23"
|
||||||
|
|
@ -1542,12 +1492,6 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "static_assertions"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "status-bar"
|
name = "status-bar"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -1651,12 +1595,6 @@ dependencies = [
|
||||||
"zellij-tile-utils",
|
"zellij-tile-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tap"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
|
|
@ -1699,15 +1637,6 @@ dependencies = [
|
||||||
"redox_termios",
|
"redox_termios",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termios"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
@ -1810,15 +1739,6 @@ version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
|
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]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
|
@ -2253,12 +2173,6 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wyz"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yaml-rust"
|
name = "yaml-rust"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
|
|
@ -2272,37 +2186,52 @@ dependencies = [
|
||||||
name = "zellij"
|
name = "zellij"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.12.1",
|
|
||||||
"async-std",
|
|
||||||
"backtrace",
|
|
||||||
"bincode",
|
|
||||||
"colors-transform",
|
|
||||||
"daemonize",
|
|
||||||
"directories-next",
|
|
||||||
"futures",
|
|
||||||
"insta",
|
"insta",
|
||||||
"interprocess",
|
"interprocess",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"names",
|
|
||||||
"nix",
|
"nix",
|
||||||
"nom",
|
"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",
|
||||||
|
"daemonize",
|
||||||
|
"insta",
|
||||||
|
"interprocess",
|
||||||
|
"libc",
|
||||||
|
"nix",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"strip-ansi-escapes",
|
|
||||||
"structopt",
|
|
||||||
"strum",
|
|
||||||
"tempfile",
|
|
||||||
"termion",
|
"termion",
|
||||||
"termios",
|
|
||||||
"unicode-truncate",
|
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"vte 0.10.1",
|
"vte 0.10.1",
|
||||||
"wasmer",
|
"wasmer",
|
||||||
"wasmer-wasi",
|
"wasmer-wasi",
|
||||||
"zellij-tile",
|
"zellij-tile",
|
||||||
|
"zellij-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2321,3 +2250,26 @@ version = "0.12.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.12.1",
|
"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",
|
||||||
|
]
|
||||||
|
|
|
||||||
46
Cargo.toml
46
Cargo.toml
|
|
@ -8,52 +8,34 @@ license = "MIT"
|
||||||
repository = "https://github.com/zellij-org/zellij"
|
repository = "https://github.com/zellij-org/zellij"
|
||||||
homepage = "https://zellij.dev"
|
homepage = "https://zellij.dev"
|
||||||
include = ["src/**/*", "assets/plugins/*", "assets/layouts/*", "assets/config/*", "LICENSE.md", "README.md", "!**/*_test.*", "!**/tests/**/*"]
|
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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ansi_term = "0.12.1"
|
zellij-utils = { path = "zellij-utils/", version = "0.12.0" }
|
||||||
backtrace = "0.3.55"
|
zellij-client = { path = "zellij-client/", version = "0.12.0" }
|
||||||
bincode = "1.3.1"
|
zellij-server = { path = "zellij-server/", version = "0.12.0" }
|
||||||
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"
|
|
||||||
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" }
|
zellij-tile = { path = "zellij-tile/", version = "0.12.0" }
|
||||||
|
structopt = "0.3"
|
||||||
[dependencies.async-std]
|
interprocess = "1.1.1"
|
||||||
version = "1.3.0"
|
vte = "0.10.1"
|
||||||
features = ["unstable"]
|
nix = "0.19.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
insta = "1.6.0"
|
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]
|
[build-dependencies]
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
"zellij-client",
|
||||||
|
"zellij-server",
|
||||||
|
"zellij-utils",
|
||||||
"zellij-tile",
|
"zellij-tile",
|
||||||
"zellij-tile-utils",
|
"zellij-tile-utils",
|
||||||
"default-plugins/status-bar",
|
"default-plugins/status-bar",
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
[env]
|
[env]
|
||||||
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
||||||
CARGO_TARGET_DIR = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target"
|
CARGO_TARGET_DIR = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target"
|
||||||
|
CARGO_MAKE_WORKSPACE_SKIP_MEMBERS = ["zellij-utils", "zellij-server", "zellij-tile", "zellij-client", "zellij-tile-utils"]
|
||||||
SKIP_TEST = false
|
SKIP_TEST = false
|
||||||
|
|
||||||
# Add clippy to the default flow
|
# Add clippy to the default flow
|
||||||
|
|
@ -24,6 +25,7 @@ env = { "SKIP_TEST" = true }
|
||||||
[tasks.test]
|
[tasks.test]
|
||||||
condition = { env_false = ["SKIP_TEST"] }
|
condition = { env_false = ["SKIP_TEST"] }
|
||||||
dependencies = ["pre-test"]
|
dependencies = ["pre-test"]
|
||||||
|
args = ["test", "--all-features", "--workspace"]
|
||||||
|
|
||||||
[tasks.post-test]
|
[tasks.post-test]
|
||||||
env = { "SKIP_TEST" = false }
|
env = { "SKIP_TEST" = false }
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
|
|
@ -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;
|
|
||||||
|
|
@ -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<T> = (
|
|
||||||
mpsc::Sender<(T, ErrorContext)>,
|
|
||||||
mpsc::Receiver<(T, ErrorContext)>,
|
|
||||||
);
|
|
||||||
/// An [MPSC](mpsc) synchronous channel with added error context.
|
|
||||||
pub type SyncChannelWithContext<T> = (
|
|
||||||
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<T: Clone> {
|
|
||||||
/// 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<T: Clone> {
|
|
||||||
sender: SenderType<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> SenderWithContext<T> {
|
|
||||||
pub fn new(sender: SenderType<T>) -> 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<T: Clone> Send for SenderWithContext<T> {}
|
|
||||||
unsafe impl<T: Clone> Sync for SenderWithContext<T> {}
|
|
||||||
|
|
||||||
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<ErrorContext> = 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<ErrorContext> = 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<SenderWithContext<ScreenInstruction>>,
|
|
||||||
pub to_pty: Option<SenderWithContext<PtyInstruction>>,
|
|
||||||
pub to_plugin: Option<SenderWithContext<PluginInstruction>>,
|
|
||||||
pub to_server: Option<SenderWithContext<ServerInstruction>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<T> {
|
|
||||||
pub receiver: mpsc::Receiver<(T, ErrorContext)>,
|
|
||||||
pub senders: ThreadSenders,
|
|
||||||
pub os_input: Option<Box<dyn ServerOsApi>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Bus<T> {
|
|
||||||
pub fn new(
|
|
||||||
receiver: mpsc::Receiver<(T, ErrorContext)>,
|
|
||||||
to_screen: Option<&SenderWithContext<ScreenInstruction>>,
|
|
||||||
to_pty: Option<&SenderWithContext<PtyInstruction>>,
|
|
||||||
to_plugin: Option<&SenderWithContext<PluginInstruction>>,
|
|
||||||
to_server: Option<&SenderWithContext<ServerInstruction>>,
|
|
||||||
os_input: Option<Box<dyn ServerOsApi>>,
|
|
||||||
) -> 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
//! Zellij utilities.
|
|
||||||
|
|
||||||
pub mod consts;
|
|
||||||
pub mod logging;
|
|
||||||
pub mod shared;
|
|
||||||
31
src/main.rs
31
src/main.rs
|
|
@ -1,31 +1,22 @@
|
||||||
mod cli;
|
|
||||||
mod client;
|
|
||||||
mod common;
|
|
||||||
mod server;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
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 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::{
|
|
||||||
consts::{ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR},
|
|
||||||
logging::*,
|
|
||||||
};
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let opts = CliArgs::from_args();
|
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");
|
Setup::from_cli(&setup, opts).expect("Failed to print to stdout");
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -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 interprocess::local_socket::LocalSocketStream;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
@ -6,15 +7,16 @@ use std::os::unix::io::RawFd;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{mpsc, Arc, Condvar, Mutex};
|
use std::sync::{mpsc, Arc, Condvar, Mutex};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
use zellij_client::os_input_output::ClientOsApi;
|
||||||
use crate::common::ipc::{ClientToServerMsg, ServerToClientMsg};
|
use zellij_server::os_input_output::ServerOsApi;
|
||||||
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_tile::data::Palette;
|
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);
|
const MIN_TIME_BETWEEN_SNAPSHOTS: Duration = Duration::from_millis(150);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::panes::PositionAndSize;
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
use zellij_utils::input::config::Config;
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
CLOSE_PANE_IN_PANE_MODE, ESC, MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT,
|
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,
|
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,
|
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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(fake_win_size.clone())
|
FakeInputOutput::new(fake_win_size.clone())
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
use ::std::collections::HashMap;
|
use ::std::collections::HashMap;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::possible_tty_inputs::Bytes;
|
use crate::tests::possible_tty_inputs::Bytes;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::QUIT;
|
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.
|
* These tests are general compatibility tests for non-trivial scenarios running in the terminal.
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::commands::QUIT;
|
use crate::tests::utils::commands::QUIT;
|
||||||
use crate::tests::utils::get_output_frame_snapshots;
|
use crate::tests::utils::get_output_frame_snapshots;
|
||||||
use crate::CliArgs;
|
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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(fake_win_size.clone())
|
FakeInputOutput::new(fake_win_size.clone())
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
MOVE_FOCUS_DOWN_IN_PANE_MODE, MOVE_FOCUS_UP_IN_PANE_MODE, PANE_MODE, QUIT,
|
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,
|
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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
ENTER, MOVE_FOCUS_LEFT_IN_NORMAL_MODE, MOVE_FOCUS_LEFT_IN_PANE_MODE,
|
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,
|
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,
|
SPLIT_RIGHT_IN_PANE_MODE, TAB_MODE,
|
||||||
};
|
};
|
||||||
|
use zellij_utils::input::config::Config;
|
||||||
|
|
||||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
ENTER, MOVE_FOCUS_LEFT_IN_PANE_MODE, MOVE_FOCUS_RIGHT_IN_NORMAL_MODE,
|
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,
|
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,
|
SPLIT_RIGHT_IN_PANE_MODE, TAB_MODE,
|
||||||
};
|
};
|
||||||
|
use zellij_utils::input::config::Config;
|
||||||
|
|
||||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
MOVE_FOCUS_DOWN_IN_PANE_MODE, MOVE_FOCUS_UP_IN_PANE_MODE, PANE_MODE, QUIT,
|
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,
|
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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE,
|
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,
|
RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE,
|
||||||
SPLIT_RIGHT_IN_PANE_MODE,
|
SPLIT_RIGHT_IN_PANE_MODE,
|
||||||
};
|
};
|
||||||
|
use zellij_utils::input::config::Config;
|
||||||
|
|
||||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE,
|
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,
|
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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_MODE, RESIZE_RIGHT_IN_RESIZE_MODE,
|
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,
|
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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE,
|
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,
|
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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,17 @@ use insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
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::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
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::{
|
use crate::tests::utils::commands::{
|
||||||
CLOSE_TAB_IN_TAB_MODE, NEW_TAB_IN_TAB_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE,
|
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,
|
SWITCH_NEXT_TAB_IN_TAB_MODE, SWITCH_PREV_TAB_IN_TAB_MODE, TAB_MODE,
|
||||||
TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_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 {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use ::insta::assert_snapshot;
|
use ::insta::assert_snapshot;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::commands::QUIT;
|
use crate::tests::utils::commands::QUIT;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::input::config::Config;
|
||||||
|
|
||||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(fake_win_size.clone())
|
FakeInputOutput::new(fake_win_size.clone())
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use crate::tests::fakes::FakeInputOutput;
|
use crate::tests::fakes::FakeInputOutput;
|
||||||
use crate::tests::start;
|
use crate::tests::start;
|
||||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||||
use crate::CliArgs;
|
use crate::CliArgs;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use crate::common::input::config::Config;
|
|
||||||
use crate::tests::utils::commands::{
|
use crate::tests::utils::commands::{
|
||||||
MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
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,
|
TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE,
|
||||||
};
|
};
|
||||||
|
use zellij_utils::input::config::Config;
|
||||||
|
|
||||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||||
FakeInputOutput::new(*fake_win_size)
|
FakeInputOutput::new(*fake_win_size)
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,10 @@ pub mod possible_tty_inputs;
|
||||||
pub mod tty_inputs;
|
pub mod tty_inputs;
|
||||||
pub mod utils;
|
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 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(
|
pub fn start(
|
||||||
client_os_input: Box<dyn ClientOsApi>,
|
client_os_input: Box<dyn ClientOsApi>,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::panes::PositionAndSize;
|
use zellij_server::{panes::TerminalPane, tab::Pane};
|
||||||
use crate::panes::TerminalPane;
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
pub fn get_output_frame_snapshots(
|
pub fn get_output_frame_snapshots(
|
||||||
output_frames: &[Vec<u8>],
|
output_frames: &[Vec<u8>],
|
||||||
|
|
|
||||||
21
zellij-client/Cargo.toml
Normal file
21
zellij-client/Cargo.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "zellij-client"
|
||||||
|
version = "0.12.0"
|
||||||
|
authors = ["Kunal Mohan <kunalmohan99@gmail.com>"]
|
||||||
|
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"]
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CommandIsExecuting {
|
pub(crate) struct CommandIsExecuting {
|
||||||
input_thread: Arc<(Mutex<bool>, Condvar)>,
|
input_thread: Arc<(Mutex<bool>, Condvar)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
//! Main input logic.
|
//! Main input logic.
|
||||||
|
|
||||||
use super::actions::Action;
|
use crate::{
|
||||||
use super::keybinds::Keybinds;
|
ClientInstruction,
|
||||||
use crate::client::ClientInstruction;
|
CommandIsExecuting,
|
||||||
use crate::common::input::config::Config;
|
os_input_output::ClientOsApi,
|
||||||
use crate::common::ipc::ClientToServerMsg;
|
};
|
||||||
use crate::common::thread_bus::{SenderWithContext, OPENCALLS};
|
use zellij_utils::{
|
||||||
use crate::errors::ContextType;
|
channels::{SenderWithContext, OPENCALLS},
|
||||||
use crate::os_input_output::ClientOsApi;
|
errors::ContextType,
|
||||||
use crate::CommandIsExecuting;
|
input::{actions::Action, cast_termion_key, config::Config, keybinds::Keybinds},
|
||||||
|
ipc::ClientToServerMsg,
|
||||||
|
};
|
||||||
|
|
||||||
use termion::input::{TermRead, TermReadEventsAndRaw};
|
use termion::input::TermReadEventsAndRaw;
|
||||||
use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities};
|
use zellij_tile::data::{InputMode, Key};
|
||||||
|
|
||||||
/// Handles the dispatching of [`Action`]s according to the current
|
/// Handles the dispatching of [`Action`]s according to the current
|
||||||
/// [`InputMode`], and keep tracks of the current [`InputMode`].
|
/// [`InputMode`], and keep tracks of the current [`InputMode`].
|
||||||
|
|
@ -172,55 +174,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
|
/// Entry point to the module. Instantiates an [`InputHandler`] and starts
|
||||||
/// its [`InputHandler::handle_input()`] loop.
|
/// its [`InputHandler::handle_input()`] loop.
|
||||||
pub fn input_loop(
|
pub(crate) fn input_loop(
|
||||||
os_input: Box<dyn ClientOsApi>,
|
os_input: Box<dyn ClientOsApi>,
|
||||||
config: Config,
|
config: Config,
|
||||||
command_is_executing: CommandIsExecuting,
|
command_is_executing: CommandIsExecuting,
|
||||||
|
|
@ -234,35 +190,3 @@ pub fn input_loop(
|
||||||
)
|
)
|
||||||
.handle_input();
|
.handle_input();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_keys(input_bytes: &[u8]) -> Vec<Key> {
|
|
||||||
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!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
pub mod boundaries;
|
pub mod os_input_output;
|
||||||
pub mod layout;
|
|
||||||
pub mod pane_resizer;
|
mod command_is_executing;
|
||||||
pub mod panes;
|
mod input_handler;
|
||||||
pub mod tab;
|
|
||||||
|
|
||||||
use std::env::current_exe;
|
use std::env::current_exe;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
@ -11,22 +10,20 @@ use std::process::Command;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use crate::cli::CliArgs;
|
use crate::{command_is_executing::CommandIsExecuting, input_handler::input_loop, os_input_output::ClientOsApi};
|
||||||
use crate::common::{
|
use zellij_utils::cli::CliArgs;
|
||||||
command_is_executing::CommandIsExecuting,
|
use zellij_utils::{
|
||||||
errors::ContextType,
|
channels::{SenderType, SenderWithContext, SyncChannelWithContext},
|
||||||
|
consts::ZELLIJ_IPC_PIPE,
|
||||||
|
errors::{ClientContext, ContextType, ErrorInstruction},
|
||||||
input::config::Config,
|
input::config::Config,
|
||||||
input::handler::input_loop,
|
|
||||||
input::options::Options,
|
input::options::Options,
|
||||||
ipc::{ClientToServerMsg, ServerToClientMsg},
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ClientInstruction {
|
pub(crate) enum ClientInstruction {
|
||||||
Error(String),
|
Error(String),
|
||||||
Render(Option<String>),
|
Render(Option<String>),
|
||||||
UnblockInputThread,
|
UnblockInputThread,
|
||||||
|
|
@ -45,6 +42,24 @@ impl From<ServerToClientMsg> 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<()> {
|
fn spawn_server(socket_path: &Path) -> io::Result<()> {
|
||||||
let status = Command::new(current_exe()?)
|
let status = Command::new(current_exe()?)
|
||||||
.arg("--server")
|
.arg("--server")
|
||||||
|
|
@ -77,7 +92,7 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
|
||||||
.unwrap();
|
.unwrap();
|
||||||
std::env::set_var(&"ZELLIJ", "0");
|
std::env::set_var(&"ZELLIJ", "0");
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(feature = "test", test)))]
|
||||||
spawn_server(&*ZELLIJ_IPC_PIPE).unwrap();
|
spawn_server(&*ZELLIJ_IPC_PIPE).unwrap();
|
||||||
|
|
||||||
let mut command_is_executing = CommandIsExecuting::new();
|
let mut command_is_executing = CommandIsExecuting::new();
|
||||||
|
|
@ -103,9 +118,9 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
|
||||||
let send_client_instructions =
|
let send_client_instructions =
|
||||||
SenderWithContext::new(SenderType::SyncSender(send_client_instructions));
|
SenderWithContext::new(SenderType::SyncSender(send_client_instructions));
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(feature = "test", test)))]
|
||||||
std::panic::set_hook({
|
std::panic::set_hook({
|
||||||
use crate::errors::handle_panic;
|
use zellij_utils::errors::handle_panic;
|
||||||
let send_client_instructions = send_client_instructions.clone();
|
let send_client_instructions = send_client_instructions.clone();
|
||||||
Box::new(move |info| {
|
Box::new(move |info| {
|
||||||
handle_panic(info, &send_client_instructions);
|
handle_panic(info, &send_client_instructions);
|
||||||
174
zellij-client/src/os_input_output.rs
Normal file
174
zellij-client/src/os_input_output.rs
Normal file
|
|
@ -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<Mutex<termios::Termios>>,
|
||||||
|
send_instructions_to_server: Arc<Mutex<Option<IpcSenderWithContext<ClientToServerMsg>>>>,
|
||||||
|
receive_instructions_from_server: Arc<Mutex<Option<IpcReceiverWithContext<ServerToClientMsg>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<dyn io::Write>;
|
||||||
|
/// Returns the raw contents of standard input.
|
||||||
|
fn read_from_stdin(&self) -> Vec<u8>;
|
||||||
|
/// Returns a [`Box`] pointer to this [`ClientOsApi`] struct.
|
||||||
|
fn box_clone(&self) -> Box<dyn ClientOsApi>;
|
||||||
|
/// 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<dyn Fn()>, quit_cb: Box<dyn Fn()>);
|
||||||
|
/// 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<dyn ClientOsApi> {
|
||||||
|
Box::new((*self).clone())
|
||||||
|
}
|
||||||
|
fn read_from_stdin(&self) -> Vec<u8> {
|
||||||
|
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<dyn io::Write> {
|
||||||
|
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<dyn Fn()>, quit_cb: Box<dyn Fn()>) {
|
||||||
|
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<dyn ClientOsApi> {
|
||||||
|
fn clone(&self) -> Box<dyn ClientOsApi> {
|
||||||
|
self.box_clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_client_os_input() -> Result<ClientOsInputOutput, nix::Error> {
|
||||||
|
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)),
|
||||||
|
})
|
||||||
|
}
|
||||||
37
zellij-server/Cargo.toml
Normal file
37
zellij-server/Cargo.toml
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
[package]
|
||||||
|
name = "zellij-server"
|
||||||
|
version = "0.12.0"
|
||||||
|
authors = ["Kunal Mohan <kunalmohan99@gmail.com>"]
|
||||||
|
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"]
|
||||||
|
|
@ -1,4 +1,13 @@
|
||||||
pub mod route;
|
pub mod panes;
|
||||||
|
pub mod tab;
|
||||||
|
pub mod os_input_output;
|
||||||
|
|
||||||
|
mod pty;
|
||||||
|
mod route;
|
||||||
|
mod screen;
|
||||||
|
mod thread_bus;
|
||||||
|
mod ui;
|
||||||
|
mod wasm_vm;
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
@ -6,27 +15,28 @@ use std::{path::PathBuf, sync::mpsc};
|
||||||
use wasmer::Store;
|
use wasmer::Store;
|
||||||
use zellij_tile::data::PluginCapabilities;
|
use zellij_tile::data::PluginCapabilities;
|
||||||
|
|
||||||
use crate::cli::CliArgs;
|
use crate::{
|
||||||
use crate::common::thread_bus::{Bus, ThreadSenders};
|
|
||||||
use crate::common::{
|
|
||||||
errors::ContextType,
|
|
||||||
input::options::Options,
|
|
||||||
ipc::{ClientToServerMsg, ServerToClientMsg},
|
|
||||||
os_input_output::ServerOsApi,
|
|
||||||
pty::{pty_thread_main, Pty, PtyInstruction},
|
pty::{pty_thread_main, Pty, PtyInstruction},
|
||||||
screen::{screen_thread_main, ScreenInstruction},
|
screen::{screen_thread_main, ScreenInstruction},
|
||||||
setup::{get_default_data_dir, install::populate_data_dir},
|
thread_bus::{Bus, ThreadSenders},
|
||||||
thread_bus::{ChannelWithContext, SenderType, SenderWithContext, SyncChannelWithContext},
|
ui::layout::Layout,
|
||||||
wasm_vm::{wasm_thread_main, PluginInstruction},
|
wasm_vm::{wasm_thread_main, PluginInstruction},
|
||||||
|
os_input_output::ServerOsApi,
|
||||||
};
|
};
|
||||||
use crate::layout::Layout;
|
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use route::route_thread_main;
|
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
|
/// Instructions related to server-side application
|
||||||
/// ones sent by client to server
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ServerInstruction {
|
pub(crate) enum ServerInstruction {
|
||||||
NewClient(PositionAndSize, CliArgs, Options),
|
NewClient(PositionAndSize, CliArgs, Options),
|
||||||
Render(Option<String>),
|
Render(Option<String>),
|
||||||
UnblockInputThread,
|
UnblockInputThread,
|
||||||
|
|
@ -46,7 +56,25 @@ impl From<ClientToServerMsg> 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 senders: ThreadSenders,
|
||||||
pub capabilities: PluginCapabilities,
|
pub capabilities: PluginCapabilities,
|
||||||
screen_thread: Option<thread::JoinHandle<()>>,
|
screen_thread: Option<thread::JoinHandle<()>>,
|
||||||
|
|
@ -66,7 +94,7 @@ impl Drop for SessionMetaData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(feature = "test", test)))]
|
||||||
daemonize::Daemonize::new()
|
daemonize::Daemonize::new()
|
||||||
.working_directory(std::env::var("HOME").unwrap())
|
.working_directory(std::env::var("HOME").unwrap())
|
||||||
.umask(0o077)
|
.umask(0o077)
|
||||||
|
|
@ -80,16 +108,16 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
let to_server = SenderWithContext::new(SenderType::SyncSender(to_server));
|
let to_server = SenderWithContext::new(SenderType::SyncSender(to_server));
|
||||||
let sessions: Arc<RwLock<Option<SessionMetaData>>> = Arc::new(RwLock::new(None));
|
let sessions: Arc<RwLock<Option<SessionMetaData>>> = Arc::new(RwLock::new(None));
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(feature = "test", test)))]
|
||||||
std::panic::set_hook({
|
std::panic::set_hook({
|
||||||
use crate::errors::handle_panic;
|
use zellij_utils::errors::handle_panic;
|
||||||
let to_server = to_server.clone();
|
let to_server = to_server.clone();
|
||||||
Box::new(move |info| {
|
Box::new(move |info| {
|
||||||
handle_panic(info, &to_server);
|
handle_panic(info, &to_server);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(any(feature = "test", test))]
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("server_router".to_string())
|
.name("server_router".to_string())
|
||||||
.spawn({
|
.spawn({
|
||||||
|
|
@ -100,12 +128,12 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
move || route_thread_main(sessions, os_input, to_server)
|
move || route_thread_main(sessions, os_input, to_server)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(feature = "test", test)))]
|
||||||
let _ = thread::Builder::new()
|
let _ = thread::Builder::new()
|
||||||
.name("server_listener".to_string())
|
.name("server_listener".to_string())
|
||||||
.spawn({
|
.spawn({
|
||||||
use crate::common::os_input_output::set_permissions;
|
|
||||||
use interprocess::local_socket::LocalSocketListener;
|
use interprocess::local_socket::LocalSocketListener;
|
||||||
|
use zellij_utils::shared::set_permissions;
|
||||||
|
|
||||||
let os_input = os_input.clone();
|
let os_input = os_input.clone();
|
||||||
let sessions = sessions.clone();
|
let sessions = sessions.clone();
|
||||||
|
|
@ -180,7 +208,7 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(feature = "test", test)))]
|
||||||
drop(std::fs::remove_file(&socket_path));
|
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
|
// 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"));
|
let default_layout = Some(PathBuf::from("default"));
|
||||||
#[cfg(test)]
|
#[cfg(any(feature = "test", test))]
|
||||||
let default_layout = None;
|
let default_layout = None;
|
||||||
let maybe_layout = opts
|
let maybe_layout = opts
|
||||||
.layout
|
.layout
|
||||||
|
|
@ -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 interprocess::local_socket::LocalSocketStream;
|
||||||
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
||||||
use nix::pty::{forkpty, Winsize};
|
use nix::pty::{forkpty, Winsize};
|
||||||
|
|
@ -11,56 +5,20 @@ use nix::sys::signal::{kill, Signal};
|
||||||
use nix::sys::termios;
|
use nix::sys::termios;
|
||||||
use nix::sys::wait::waitpid;
|
use nix::sys::wait::waitpid;
|
||||||
use nix::unistd::{self, ForkResult, Pid};
|
use nix::unistd::{self, ForkResult, Pid};
|
||||||
use signal_hook::{consts::signal::*, iterator::Signals};
|
use signal_hook::consts::*;
|
||||||
use std::io::prelude::*;
|
use std::env;
|
||||||
use std::os::unix::{fs::PermissionsExt, io::RawFd};
|
use std::os::unix::io::RawFd;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::process::{Child, Command};
|
use std::process::{Child, Command};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{env, fs, io};
|
|
||||||
use zellij_tile::data::Palette;
|
use zellij_tile::data::Palette;
|
||||||
|
use zellij_utils::errors::ErrorContext;
|
||||||
const UNIX_PERMISSIONS: u32 = 0o700;
|
use zellij_utils::ipc::{
|
||||||
|
ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg,
|
||||||
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),
|
|
||||||
};
|
};
|
||||||
}
|
use zellij_utils::shared::default_palette;
|
||||||
|
|
||||||
fn unset_raw_mode(pid: RawFd, orig_termios: termios::Termios) {
|
pub(crate) fn set_terminal_size_using_fd(fd: RawFd, columns: u16, rows: u16) {
|
||||||
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) {
|
|
||||||
// TODO: do this with the nix ioctl
|
// TODO: do this with the nix ioctl
|
||||||
use libc::ioctl;
|
use libc::ioctl;
|
||||||
use libc::TIOCSWINSZ;
|
use libc::TIOCSWINSZ;
|
||||||
|
|
@ -284,131 +242,3 @@ pub fn get_server_os_input() -> Result<ServerOsInputOutput, nix::Error> {
|
||||||
send_instructions_to_client: Arc::new(Mutex::new(None)),
|
send_instructions_to_client: Arc::new(Mutex::new(None)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ClientOsInputOutput {
|
|
||||||
orig_termios: Arc<Mutex<termios::Termios>>,
|
|
||||||
send_instructions_to_server: Arc<Mutex<Option<IpcSenderWithContext<ClientToServerMsg>>>>,
|
|
||||||
receive_instructions_from_server: Arc<Mutex<Option<IpcReceiverWithContext<ServerToClientMsg>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<dyn io::Write>;
|
|
||||||
/// Returns the raw contents of standard input.
|
|
||||||
fn read_from_stdin(&self) -> Vec<u8>;
|
|
||||||
/// Returns a [`Box`] pointer to this [`ClientOsApi`] struct.
|
|
||||||
fn box_clone(&self) -> Box<dyn ClientOsApi>;
|
|
||||||
/// 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<dyn Fn()>, quit_cb: Box<dyn Fn()>);
|
|
||||||
/// 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<dyn ClientOsApi> {
|
|
||||||
Box::new((*self).clone())
|
|
||||||
}
|
|
||||||
fn read_from_stdin(&self) -> Vec<u8> {
|
|
||||||
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<dyn io::Write> {
|
|
||||||
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<dyn Fn()>, quit_cb: Box<dyn Fn()>) {
|
|
||||||
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<dyn ClientOsApi> {
|
|
||||||
fn clone(&self) -> Box<dyn ClientOsApi> {
|
|
||||||
self.box_clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_client_os_input() -> Result<ClientOsInputOutput, nix::Error> {
|
|
||||||
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)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -9,9 +9,7 @@ use vte::{Params, Perform};
|
||||||
const TABSTOP_WIDTH: usize = 8; // TODO: is this always right?
|
const TABSTOP_WIDTH: usize = 8; // TODO: is this always right?
|
||||||
const SCROLL_BACK: usize = 10_000;
|
const SCROLL_BACK: usize = 10_000;
|
||||||
|
|
||||||
use crate::utils::consts::VERSION;
|
use zellij_utils::{consts::VERSION, logging::debug_log_to_file, shared::version_number};
|
||||||
use crate::utils::logging::debug_log_to_file;
|
|
||||||
use crate::utils::shared::version_number;
|
|
||||||
|
|
||||||
use crate::panes::terminal_character::{
|
use crate::panes::terminal_character::{
|
||||||
CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset, TerminalCharacter,
|
CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset, TerminalCharacter,
|
||||||
|
|
@ -1347,7 +1345,7 @@ impl Perform for Grid {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
|
let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
|
||||||
#[cfg(not(test))]
|
#[cfg(not(any(feature = "test", test)))]
|
||||||
result.unwrap();
|
result.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,6 @@ mod terminal_character;
|
||||||
mod terminal_pane;
|
mod terminal_pane;
|
||||||
|
|
||||||
pub use grid::*;
|
pub use grid::*;
|
||||||
pub use plugin_pane::*;
|
pub(crate) use plugin_pane::*;
|
||||||
pub use terminal_character::*;
|
pub use terminal_character::*;
|
||||||
pub use terminal_pane::*;
|
pub use terminal_pane::*;
|
||||||
|
|
@ -2,13 +2,13 @@ use std::sync::mpsc::channel;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::unimplemented;
|
use std::unimplemented;
|
||||||
|
|
||||||
use crate::common::thread_bus::SenderWithContext;
|
use crate::panes::PaneId;
|
||||||
use crate::panes::{PaneId, PositionAndSize};
|
|
||||||
use crate::pty::VteBytes;
|
use crate::pty::VteBytes;
|
||||||
use crate::tab::Pane;
|
use crate::tab::Pane;
|
||||||
use crate::wasm_vm::PluginInstruction;
|
use crate::wasm_vm::PluginInstruction;
|
||||||
|
use zellij_utils::{channels::SenderWithContext, pane_size::PositionAndSize};
|
||||||
|
|
||||||
pub struct PluginPane {
|
pub(crate) struct PluginPane {
|
||||||
pub pid: u32,
|
pub pid: u32,
|
||||||
pub should_render: bool,
|
pub should_render: bool,
|
||||||
pub selectable: bool,
|
pub selectable: bool,
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
|
|
||||||
use crate::utils::logging::debug_log_to_file;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use vte::ParamsIter;
|
use vte::ParamsIter;
|
||||||
|
use zellij_utils::logging::debug_log_to_file;
|
||||||
|
|
||||||
pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter {
|
pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter {
|
||||||
character: ' ',
|
character: ' ',
|
||||||
|
|
@ -1,45 +1,23 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
use nix::pty::Winsize;
|
use crate::panes::{
|
||||||
use serde::{Deserialize, Serialize};
|
grid::Grid,
|
||||||
|
terminal_character::{
|
||||||
use crate::panes::grid::Grid;
|
|
||||||
use crate::panes::terminal_character::{
|
|
||||||
CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use crate::pty::VteBytes;
|
use crate::pty::VteBytes;
|
||||||
use crate::tab::Pane;
|
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 {
|
pub enum PaneId {
|
||||||
Terminal(RawFd),
|
Terminal(RawFd),
|
||||||
Plugin(u32), // FIXME: Drop the trait object, make this a wrapper for the struct?
|
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<usize>,
|
|
||||||
pub max_columns: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Winsize> 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 struct TerminalPane {
|
||||||
pub grid: Grid,
|
pub grid: Grid,
|
||||||
pub pid: RawFd,
|
pub pid: RawFd,
|
||||||
|
|
@ -354,7 +332,7 @@ impl TerminalPane {
|
||||||
pub fn read_buffer_as_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
pub fn read_buffer_as_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
||||||
self.grid.as_character_lines()
|
self.grid.as_character_lines()
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(any(feature = "test", test))]
|
||||||
pub fn cursor_coordinates(&self) -> Option<(usize, usize)> {
|
pub fn cursor_coordinates(&self) -> Option<(usize, usize)> {
|
||||||
// (x, y)
|
// (x, y)
|
||||||
self.grid.cursor_coordinates()
|
self.grid.cursor_coordinates()
|
||||||
|
|
@ -3,7 +3,7 @@ use ::insta::assert_snapshot;
|
||||||
|
|
||||||
fn read_fixture(fixture_name: &str) -> Vec<u8> {
|
fn read_fixture(fixture_name: &str) -> Vec<u8> {
|
||||||
let mut path_to_file = std::path::PathBuf::new();
|
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("tests");
|
||||||
path_to_file.push("fixtures");
|
path_to_file.push("fixtures");
|
||||||
path_to_file.push(fixture_name);
|
path_to_file.push(fixture_name);
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -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)"
|
expression: "format!(\"{:?}\", grid . pending_messages_to_pty)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/grid.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/grid.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/grid.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/grid.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/grid.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/grid.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: src/client/panes/./unit/grid_tests.rs
|
source: zellij-server/src/panes/./unit/grid_tests.rs
|
||||||
expression: "format!(\"{:?}\", grid)"
|
expression: "format!(\"{:?}\", grid)"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -7,15 +7,19 @@ use std::path::PathBuf;
|
||||||
use std::pin::*;
|
use std::pin::*;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::client::panes::PaneId;
|
use crate::{
|
||||||
use crate::common::errors::{get_current_ctx, ContextType};
|
panes::PaneId,
|
||||||
use crate::common::screen::ScreenInstruction;
|
screen::ScreenInstruction,
|
||||||
use crate::common::thread_bus::{Bus, ThreadSenders};
|
thread_bus::{Bus, ThreadSenders},
|
||||||
use crate::layout::Layout;
|
ui::layout::Layout,
|
||||||
use crate::os_input_output::ServerOsApi;
|
wasm_vm::PluginInstruction,
|
||||||
use crate::server::ServerInstruction;
|
ServerInstruction,
|
||||||
use crate::utils::logging::debug_to_file;
|
os_input_output::ServerOsApi,
|
||||||
use crate::wasm_vm::PluginInstruction;
|
};
|
||||||
|
use zellij_utils::{
|
||||||
|
errors::{get_current_ctx, ContextType, PtyContext},
|
||||||
|
logging::debug_to_file,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct ReadFromPid {
|
pub struct ReadFromPid {
|
||||||
pid: RawFd,
|
pid: RawFd,
|
||||||
|
|
@ -67,7 +71,7 @@ pub type VteBytes = Vec<u8>;
|
||||||
|
|
||||||
/// Instructions related to PTYs (pseudoterminals).
|
/// Instructions related to PTYs (pseudoterminals).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum PtyInstruction {
|
pub(crate) enum PtyInstruction {
|
||||||
SpawnTerminal(Option<PathBuf>),
|
SpawnTerminal(Option<PathBuf>),
|
||||||
SpawnTerminalVertically(Option<PathBuf>),
|
SpawnTerminalVertically(Option<PathBuf>),
|
||||||
SpawnTerminalHorizontally(Option<PathBuf>),
|
SpawnTerminalHorizontally(Option<PathBuf>),
|
||||||
|
|
@ -77,14 +81,28 @@ pub enum PtyInstruction {
|
||||||
Exit,
|
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<PtyInstruction>,
|
pub bus: Bus<PtyInstruction>,
|
||||||
pub id_to_child_pid: HashMap<RawFd, RawFd>,
|
pub id_to_child_pid: HashMap<RawFd, RawFd>,
|
||||||
debug_to_file: bool,
|
debug_to_file: bool,
|
||||||
task_handles: HashMap<RawFd, JoinHandle<()>>,
|
task_handles: HashMap<RawFd, JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pty_thread_main(mut pty: Pty, maybe_layout: Option<Layout>) {
|
pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option<Layout>) {
|
||||||
loop {
|
loop {
|
||||||
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
|
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
|
||||||
err_ctx.add_call(ContextType::Pty((&event).into()));
|
err_ctx.add_call(ContextType::Pty((&event).into()));
|
||||||
|
|
@ -196,7 +214,7 @@ fn stream_terminal_bytes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
senders.send_to_screen(ScreenInstruction::Render).unwrap();
|
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
|
// 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
|
// 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
|
// a better solution would be to fix the test fakes, but this will do for now
|
||||||
|
|
@ -2,15 +2,19 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use zellij_tile::data::Event;
|
use zellij_tile::data::Event;
|
||||||
|
|
||||||
use crate::common::input::actions::{Action, Direction};
|
use crate::{
|
||||||
use crate::common::input::handler::get_mode_info;
|
pty::PtyInstruction, screen::ScreenInstruction, wasm_vm::PluginInstruction, ServerInstruction,
|
||||||
use crate::common::ipc::ClientToServerMsg;
|
SessionMetaData,
|
||||||
use crate::common::os_input_output::ServerOsApi;
|
os_input_output::ServerOsApi,
|
||||||
use crate::common::pty::PtyInstruction;
|
};
|
||||||
use crate::common::screen::ScreenInstruction;
|
use zellij_utils::{
|
||||||
use crate::common::thread_bus::SenderWithContext;
|
channels::SenderWithContext,
|
||||||
use crate::common::wasm_vm::PluginInstruction;
|
input::{
|
||||||
use crate::server::{ServerInstruction, SessionMetaData};
|
actions::{Action, Direction},
|
||||||
|
get_mode_info,
|
||||||
|
},
|
||||||
|
ipc::ClientToServerMsg,
|
||||||
|
};
|
||||||
|
|
||||||
fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn ServerOsApi) {
|
fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn ServerOsApi) {
|
||||||
match action {
|
match action {
|
||||||
|
|
@ -181,7 +185,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<RwLock<Option<SessionMetaData>>>,
|
sessions: Arc<RwLock<Option<SessionMetaData>>>,
|
||||||
mut os_input: Box<dyn ServerOsApi>,
|
mut os_input: Box<dyn ServerOsApi>,
|
||||||
to_server: SenderWithContext<ServerInstruction>,
|
to_server: SenderWithContext<ServerInstruction>,
|
||||||
|
|
@ -4,22 +4,25 @@ use std::collections::BTreeMap;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use crate::common::input::options::Options;
|
use crate::{
|
||||||
use crate::common::pty::{PtyInstruction, VteBytes};
|
panes::PaneId,
|
||||||
use crate::common::thread_bus::Bus;
|
pty::{PtyInstruction, VteBytes},
|
||||||
use crate::errors::ContextType;
|
tab::Tab,
|
||||||
use crate::layout::Layout;
|
thread_bus::Bus,
|
||||||
use crate::panes::PaneId;
|
ui::layout::Layout,
|
||||||
use crate::panes::PositionAndSize;
|
wasm_vm::PluginInstruction,
|
||||||
use crate::server::ServerInstruction;
|
ServerInstruction,
|
||||||
use crate::tab::Tab;
|
};
|
||||||
use crate::wasm_vm::PluginInstruction;
|
|
||||||
|
|
||||||
use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PluginCapabilities, TabInfo};
|
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`].
|
/// Instructions that can be sent to the [`Screen`].
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ScreenInstruction {
|
pub(crate) enum ScreenInstruction {
|
||||||
PtyBytes(RawFd, VteBytes),
|
PtyBytes(RawFd, VteBytes),
|
||||||
Render,
|
Render,
|
||||||
NewPane(PaneId),
|
NewPane(PaneId),
|
||||||
|
|
@ -63,9 +66,61 @@ pub enum ScreenInstruction {
|
||||||
ChangeMode(ModeInfo),
|
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).
|
/// 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`.
|
/// 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.
|
/// A Bus for sending and receiving messages with the other threads.
|
||||||
pub bus: Bus<ScreenInstruction>,
|
pub bus: Bus<ScreenInstruction>,
|
||||||
/// An optional maximal amount of panes allowed per [`Tab`] in this [`Screen`] instance.
|
/// 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<ScreenInstruction>,
|
bus: Bus<ScreenInstruction>,
|
||||||
max_panes: Option<usize>,
|
max_panes: Option<usize>,
|
||||||
full_screen_ws: PositionAndSize,
|
full_screen_ws: PositionAndSize,
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
//! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size,
|
//! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size,
|
||||||
//! as well as how they should be resized
|
//! as well as how they should be resized
|
||||||
|
|
||||||
use crate::client::pane_resizer::PaneResizer;
|
use crate::{
|
||||||
use crate::common::input::handler::parse_keys;
|
panes::{PaneId, PluginPane, TerminalPane},
|
||||||
use crate::common::thread_bus::ThreadSenders;
|
pty::{PtyInstruction, VteBytes},
|
||||||
use crate::layout::Layout;
|
thread_bus::ThreadSenders,
|
||||||
use crate::os_input_output::ServerOsApi;
|
ui::{boundaries::Boundaries, layout::Layout, pane_resizer::PaneResizer},
|
||||||
use crate::panes::{PaneId, PositionAndSize, TerminalPane};
|
wasm_vm::PluginInstruction,
|
||||||
use crate::pty::{PtyInstruction, VteBytes};
|
ServerInstruction,
|
||||||
use crate::server::ServerInstruction;
|
os_input_output::ServerOsApi,
|
||||||
use crate::utils::shared::adjust_to_size;
|
};
|
||||||
use crate::wasm_vm::PluginInstruction;
|
|
||||||
use crate::{boundaries::Boundaries, panes::PluginPane};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
|
|
@ -21,6 +19,10 @@ use std::{
|
||||||
collections::{BTreeMap, HashSet},
|
collections::{BTreeMap, HashSet},
|
||||||
};
|
};
|
||||||
use zellij_tile::data::{Event, InputMode, ModeInfo, Palette};
|
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
|
const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this
|
||||||
|
|
||||||
|
|
@ -59,7 +61,7 @@ fn split_horizontally_with_gap(rect: &PositionAndSize) -> (PositionAndSize, Posi
|
||||||
(first_rect, second_rect)
|
(first_rect, second_rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tab {
|
pub(crate) struct Tab {
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
pub position: usize,
|
pub position: usize,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -79,7 +81,7 @@ pub struct Tab {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct TabData {
|
pub(crate) struct TabData {
|
||||||
/* subset of fields to publish to plugins */
|
/* subset of fields to publish to plugins */
|
||||||
pub position: usize,
|
pub position: usize,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
81
zellij-server/src/thread_bus.rs
Normal file
81
zellij-server/src/thread_bus.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
//! Definitions and helpers for sending and receiving messages between threads.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
pty::PtyInstruction, screen::ScreenInstruction, wasm_vm::PluginInstruction, ServerInstruction, os_input_output::ServerOsApi
|
||||||
|
};
|
||||||
|
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<SenderWithContext<ScreenInstruction>>,
|
||||||
|
pub to_pty: Option<SenderWithContext<PtyInstruction>>,
|
||||||
|
pub to_plugin: Option<SenderWithContext<PluginInstruction>>,
|
||||||
|
pub to_server: Option<SenderWithContext<ServerInstruction>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<T> {
|
||||||
|
pub receiver: mpsc::Receiver<(T, ErrorContext)>,
|
||||||
|
pub senders: ThreadSenders,
|
||||||
|
pub os_input: Option<Box<dyn ServerOsApi>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Bus<T> {
|
||||||
|
pub fn new(
|
||||||
|
receiver: mpsc::Receiver<(T, ErrorContext)>,
|
||||||
|
to_screen: Option<&SenderWithContext<ScreenInstruction>>,
|
||||||
|
to_pty: Option<&SenderWithContext<PtyInstruction>>,
|
||||||
|
to_plugin: Option<&SenderWithContext<PluginInstruction>>,
|
||||||
|
to_server: Option<&SenderWithContext<ServerInstruction>>,
|
||||||
|
os_input: Option<Box<dyn ServerOsApi>>,
|
||||||
|
) -> 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::tab::Pane;
|
use crate::tab::Pane;
|
||||||
use crate::utils::shared::colors;
|
|
||||||
use ansi_term::Colour::{Fixed, RGB};
|
use ansi_term::Colour::{Fixed, RGB};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use zellij_tile::data::{InputMode, Palette, PaletteColor};
|
use zellij_tile::data::{InputMode, Palette, PaletteColor};
|
||||||
|
use zellij_utils::shared::colors;
|
||||||
|
|
||||||
use std::fmt::{Display, Error, Formatter};
|
use std::fmt::{Display, Error, Formatter};
|
||||||
pub mod boundary_type {
|
pub mod boundary_type {
|
||||||
|
|
@ -19,10 +19,10 @@ pub mod boundary_type {
|
||||||
pub const CROSS: &str = "┼";
|
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)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct BoundarySymbol {
|
pub(crate) struct BoundarySymbol {
|
||||||
boundary_type: BoundaryType,
|
boundary_type: BoundaryType,
|
||||||
invisible: bool,
|
invisible: bool,
|
||||||
color: Option<PaletteColor>,
|
color: Option<PaletteColor>,
|
||||||
|
|
@ -392,7 +392,7 @@ fn combine_symbols(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct Coordinates {
|
pub(crate) struct Coordinates {
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +403,7 @@ impl Coordinates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Rect {
|
pub(crate) trait Rect {
|
||||||
fn x(&self) -> usize;
|
fn x(&self) -> usize;
|
||||||
fn y(&self) -> usize;
|
fn y(&self) -> usize;
|
||||||
fn rows(&self) -> usize;
|
fn rows(&self) -> usize;
|
||||||
|
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{fs::File, io::prelude::*};
|
use std::{fs::File, io::prelude::*};
|
||||||
|
|
||||||
use crate::panes::PositionAndSize;
|
use zellij_utils::pane_size::PositionAndSize;
|
||||||
|
|
||||||
fn split_space_to_parts_vertically(
|
fn split_space_to_parts_vertically(
|
||||||
space_to_split: &PositionAndSize,
|
space_to_split: &PositionAndSize,
|
||||||
|
|
@ -167,19 +167,19 @@ fn split_space(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub enum Direction {
|
pub(crate) enum Direction {
|
||||||
Horizontal,
|
Horizontal,
|
||||||
Vertical,
|
Vertical,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
pub enum SplitSize {
|
pub(crate) enum SplitSize {
|
||||||
Percent(u8), // 1 to 100
|
Percent(u8), // 1 to 100
|
||||||
Fixed(u16), // An absolute number of columns or rows
|
Fixed(u16), // An absolute number of columns or rows
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Layout {
|
pub(crate) struct Layout {
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
pub parts: Vec<Layout>,
|
pub parts: Vec<Layout>,
|
||||||
3
zellij-server/src/ui/mod.rs
Normal file
3
zellij-server/src/ui/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod boundaries;
|
||||||
|
pub mod layout;
|
||||||
|
pub mod pane_resizer;
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
use crate::os_input_output::ServerOsApi;
|
use crate::{panes::PaneId, os_input_output::ServerOsApi, tab::Pane};
|
||||||
use crate::panes::{PaneId, PositionAndSize};
|
|
||||||
use crate::tab::Pane;
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::{BTreeMap, HashSet},
|
collections::{BTreeMap, HashSet},
|
||||||
};
|
};
|
||||||
|
use zellij_utils::{pane_size::PositionAndSize};
|
||||||
|
|
||||||
pub struct PaneResizer<'a> {
|
pub(crate) struct PaneResizer<'a> {
|
||||||
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
panes: &'a mut BTreeMap<PaneId, Box<dyn Pane>>,
|
||||||
os_api: &'a mut Box<dyn ServerOsApi>,
|
os_api: &'a mut Box<dyn ServerOsApi>,
|
||||||
}
|
}
|
||||||
|
|
@ -15,14 +15,16 @@ use wasmer::{
|
||||||
use wasmer_wasi::{Pipe, WasiEnv, WasiState};
|
use wasmer_wasi::{Pipe, WasiEnv, WasiState};
|
||||||
use zellij_tile::data::{Event, EventType, PluginIds};
|
use zellij_tile::data::{Event, EventType, PluginIds};
|
||||||
|
|
||||||
use crate::common::errors::ContextType;
|
use crate::{
|
||||||
use crate::common::pty::PtyInstruction;
|
panes::PaneId,
|
||||||
use crate::common::screen::ScreenInstruction;
|
pty::PtyInstruction,
|
||||||
use crate::common::thread_bus::{Bus, ThreadSenders};
|
screen::ScreenInstruction,
|
||||||
use crate::common::PaneId;
|
thread_bus::{Bus, ThreadSenders},
|
||||||
|
};
|
||||||
|
use zellij_utils::errors::{ContextType, PluginContext};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum PluginInstruction {
|
pub(crate) enum PluginInstruction {
|
||||||
Load(Sender<u32>, PathBuf),
|
Load(Sender<u32>, PathBuf),
|
||||||
Update(Option<u32>, Event), // Focused plugin / broadcast, event data
|
Update(Option<u32>, Event), // Focused plugin / broadcast, event data
|
||||||
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
||||||
|
|
@ -30,8 +32,20 @@ pub enum PluginInstruction {
|
||||||
Exit,
|
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)]
|
#[derive(WasmerEnv, Clone)]
|
||||||
pub struct PluginEnv {
|
pub(crate) struct PluginEnv {
|
||||||
pub plugin_id: u32,
|
pub plugin_id: u32,
|
||||||
pub senders: ThreadSenders,
|
pub senders: ThreadSenders,
|
||||||
pub wasi_env: WasiEnv,
|
pub wasi_env: WasiEnv,
|
||||||
|
|
@ -39,7 +53,7 @@ pub struct PluginEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread main --------------------------------------------------------------------------------------------------------
|
// Thread main --------------------------------------------------------------------------------------------------------
|
||||||
pub fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_dir: PathBuf) {
|
pub(crate) fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_dir: PathBuf) {
|
||||||
let mut plugin_id = 0;
|
let mut plugin_id = 0;
|
||||||
let mut plugin_map = HashMap::new();
|
let mut plugin_map = HashMap::new();
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -126,7 +140,7 @@ pub fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_dir: Pat
|
||||||
|
|
||||||
// Plugin API ---------------------------------------------------------------------------------------------------------
|
// 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 {
|
macro_rules! zellij_export {
|
||||||
($($host_function:ident),+ $(,)?) => {
|
($($host_function:ident),+ $(,)?) => {
|
||||||
imports! {
|
imports! {
|
||||||
36
zellij-utils/Cargo.toml
Normal file
36
zellij-utils/Cargo.toml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
[package]
|
||||||
|
name = "zellij-utils"
|
||||||
|
version = "0.12.0"
|
||||||
|
authors = ["Kunal Mohan <kunalmohan99@gmail.com>"]
|
||||||
|
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 = []
|
||||||
65
zellij-utils/src/channels.rs
Normal file
65
zellij-utils/src/channels.rs
Normal file
|
|
@ -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<T> = (
|
||||||
|
mpsc::Sender<(T, ErrorContext)>,
|
||||||
|
mpsc::Receiver<(T, ErrorContext)>,
|
||||||
|
);
|
||||||
|
/// An [MPSC](mpsc) synchronous channel with added error context.
|
||||||
|
pub type SyncChannelWithContext<T> = (
|
||||||
|
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<T: Clone> {
|
||||||
|
/// 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<T: Clone> {
|
||||||
|
sender: SenderType<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> SenderWithContext<T> {
|
||||||
|
pub fn new(sender: SenderType<T>) -> 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<T: Clone> Send for SenderWithContext<T> {}
|
||||||
|
unsafe impl<T: Clone> Sync for SenderWithContext<T> {}
|
||||||
|
|
||||||
|
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<ErrorContext> = 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<ErrorContext> = RefCell::default()
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV};
|
use crate::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV};
|
||||||
use crate::common::input::options::Options;
|
use crate::input::options::Options;
|
||||||
use crate::common::setup::Setup;
|
use crate::setup::Setup;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Zellij program-wide constants.
|
//! Zellij program-wide constants.
|
||||||
|
|
||||||
use crate::os_input_output::set_permissions;
|
use crate::shared::set_permissions;
|
||||||
use directories_next::ProjectDirs;
|
use directories_next::ProjectDirs;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use nix::unistd::Uid;
|
use nix::unistd::Uid;
|
||||||
|
|
@ -1,43 +1,20 @@
|
||||||
//! Error context system based on a thread-local representation of the call stack, itself based on
|
//! Error context system based on a thread-local representation of the call stack, itself based on
|
||||||
//! the instructions that are sent between threads.
|
//! the instructions that are sent between threads.
|
||||||
|
|
||||||
|
use crate::channels::{ASYNCOPENCALLS, OPENCALLS, SenderWithContext};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use std::fmt::{Display, Error, Formatter};
|
use std::fmt::{Display, Error, Formatter};
|
||||||
|
use std::panic::PanicInfo;
|
||||||
use crate::client::ClientInstruction;
|
|
||||||
use crate::common::thread_bus::{ASYNCOPENCALLS, OPENCALLS};
|
|
||||||
use crate::pty::PtyInstruction;
|
|
||||||
use crate::screen::ScreenInstruction;
|
|
||||||
use crate::server::ServerInstruction;
|
|
||||||
|
|
||||||
/// The maximum amount of calls an [`ErrorContext`] will keep track
|
/// The maximum amount of calls an [`ErrorContext`] will keep track
|
||||||
/// of in its stack representation. This is a per-thread maximum.
|
/// of in its stack representation. This is a per-thread maximum.
|
||||||
const MAX_THREAD_CALL_STACK: usize = 6;
|
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 {
|
pub trait ErrorInstruction {
|
||||||
fn error(err: String) -> Self;
|
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`].
|
/// Custom panic handler/hook. Prints the [`ErrorContext`].
|
||||||
#[cfg(not(test))]
|
|
||||||
pub fn handle_panic<T>(info: &PanicInfo<'_>, sender: &SenderWithContext<T>)
|
pub fn handle_panic<T>(info: &PanicInfo<'_>, sender: &SenderWithContext<T>)
|
||||||
where
|
where
|
||||||
T: ErrorInstruction + Clone,
|
T: ErrorInstruction + Clone,
|
||||||
|
|
@ -243,59 +220,6 @@ pub enum ScreenContext {
|
||||||
ChangeMode,
|
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.
|
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum PtyContext {
|
pub enum PtyContext {
|
||||||
|
|
@ -308,24 +232,6 @@ pub enum PtyContext {
|
||||||
Exit,
|
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.
|
/// Stack call representations corresponding to the different types of [`PluginInstruction`]s.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum PluginContext {
|
pub enum PluginContext {
|
||||||
|
|
@ -336,18 +242,6 @@ pub enum PluginContext {
|
||||||
Exit,
|
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.
|
/// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ClientContext {
|
pub enum ClientContext {
|
||||||
|
|
@ -358,18 +252,6 @@ pub enum ClientContext {
|
||||||
ServerError,
|
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.
|
/// Stack call representations corresponding to the different types of [`ServerInstruction`]s.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ServerContext {
|
pub enum ServerContext {
|
||||||
|
|
@ -379,15 +261,3 @@ pub enum ServerContext {
|
||||||
ClientExit,
|
ClientExit,
|
||||||
Error,
|
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,7 +8,7 @@ use std::path::{Path, PathBuf};
|
||||||
use super::keybinds::{Keybinds, KeybindsFromYaml};
|
use super::keybinds::{Keybinds, KeybindsFromYaml};
|
||||||
use super::options::Options;
|
use super::options::Options;
|
||||||
use crate::cli::{CliArgs, ConfigCli};
|
use crate::cli::{CliArgs, ConfigCli};
|
||||||
use crate::common::setup;
|
use crate::setup;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
@ -177,7 +177,7 @@ mod config_test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn try_from_cli_args_with_option_clean() {
|
fn try_from_cli_args_with_option_clean() {
|
||||||
use crate::common::setup::Setup;
|
use crate::setup::Setup;
|
||||||
let mut opts = CliArgs::default();
|
let mut opts = CliArgs::default();
|
||||||
opts.option = Some(ConfigCli::Setup(Setup {
|
opts.option = Some(ConfigCli::Setup(Setup {
|
||||||
clean: true,
|
clean: true,
|
||||||
87
zellij-utils/src/input/mod.rs
Normal file
87
zellij-utils/src/input/mod.rs
Normal file
|
|
@ -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<Key> {
|
||||||
|
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!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
//! IPC stuff for starting to split things into a client and server model.
|
//! IPC stuff for starting to split things into a client and server model.
|
||||||
|
|
||||||
use crate::cli::CliArgs;
|
use crate::cli::CliArgs;
|
||||||
use crate::common::{
|
use crate::pane_size::PositionAndSize;
|
||||||
|
use crate::{
|
||||||
errors::{get_current_ctx, ErrorContext},
|
errors::{get_current_ctx, ErrorContext},
|
||||||
input::{actions::Action, options::Options},
|
input::{actions::Action, options::Options},
|
||||||
};
|
};
|
||||||
use crate::panes::PositionAndSize;
|
|
||||||
use interprocess::local_socket::LocalSocketStream;
|
use interprocess::local_socket::LocalSocketStream;
|
||||||
use nix::unistd::dup;
|
use nix::unistd::dup;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
10
zellij-utils/src/lib.rs
Normal file
10
zellij-utils/src/lib.rs
Normal file
|
|
@ -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;
|
||||||
|
|
@ -7,8 +7,8 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::os_input_output::set_permissions;
|
use crate::consts::{ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE};
|
||||||
use crate::utils::consts::{ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE};
|
use crate::shared::set_permissions;
|
||||||
|
|
||||||
pub fn atomic_create_file(file_name: &Path) -> io::Result<()> {
|
pub fn atomic_create_file(file_name: &Path) -> io::Result<()> {
|
||||||
let _ = fs::OpenOptions::new()
|
let _ = fs::OpenOptions::new()
|
||||||
24
zellij-utils/src/pane_size.rs
Normal file
24
zellij-utils/src/pane_size.rs
Normal file
|
|
@ -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<usize>,
|
||||||
|
pub max_columns: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Winsize> for PositionAndSize {
|
||||||
|
fn from(winsize: Winsize) -> PositionAndSize {
|
||||||
|
PositionAndSize {
|
||||||
|
columns: winsize.ws_col as usize,
|
||||||
|
rows: winsize.ws_row as usize,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::cli::CliArgs;
|
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,
|
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 directories_next::BaseDirs;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
@ -32,13 +32,13 @@ pub mod install {
|
||||||
pub fn populate_data_dir(data_dir: &Path) {
|
pub fn populate_data_dir(data_dir: &Path) {
|
||||||
// First run installation of default plugins & layouts
|
// First run installation of default plugins & layouts
|
||||||
let mut assets = asset_map! {
|
let mut assets = asset_map! {
|
||||||
"assets/layouts/default.yaml" => "layouts/default.yaml",
|
"../assets/layouts/default.yaml" => "layouts/default.yaml",
|
||||||
"assets/layouts/strider.yaml" => "layouts/strider.yaml",
|
"../assets/layouts/strider.yaml" => "layouts/strider.yaml",
|
||||||
};
|
};
|
||||||
assets.extend(asset_map! {
|
assets.extend(asset_map! {
|
||||||
"assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm",
|
"../assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm",
|
||||||
"assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm",
|
"../assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm",
|
||||||
"assets/plugins/strider.wasm" => "plugins/strider.wasm",
|
"../assets/plugins/strider.wasm" => "plugins/strider.wasm",
|
||||||
});
|
});
|
||||||
assets.insert("VERSION", VERSION.as_bytes().to_vec());
|
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
|
/// Goes through a predefined list and checks for an already
|
||||||
/// existing config directory, returns the first match
|
/// existing config directory, returns the first match
|
||||||
pub fn find_default_config_dir() -> Option<PathBuf> {
|
pub fn find_default_config_dir() -> Option<PathBuf> {
|
||||||
|
|
@ -68,7 +68,7 @@ pub fn find_default_config_dir() -> Option<PathBuf> {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(any(feature = "test", test))]
|
||||||
pub fn find_default_config_dir() -> Option<PathBuf> {
|
pub fn find_default_config_dir() -> Option<PathBuf> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +119,7 @@ pub fn dump_asset(asset: &[u8]) -> std::io::Result<()> {
|
||||||
pub const DEFAULT_CONFIG: &[u8] = include_bytes!(concat!(
|
pub const DEFAULT_CONFIG: &[u8] = include_bytes!(concat!(
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
"/",
|
"/",
|
||||||
"assets/config/default.yaml"
|
"../assets/config/default.yaml"
|
||||||
));
|
));
|
||||||
|
|
||||||
pub fn dump_default_config() -> std::io::Result<()> {
|
pub fn dump_default_config() -> std::io::Result<()> {
|
||||||
|
|
@ -192,7 +192,7 @@ impl Setup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(config_file) = config_file {
|
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));
|
message.push_str(&format!("[CONFIG FILE]: {:?}\n", config_file));
|
||||||
match Config::new(&config_file) {
|
match Config::new(&config_file) {
|
||||||
Ok(_) => message.push_str(&"[CONFIG FILE]: Well defined.\n"),
|
Ok(_) => message.push_str(&"[CONFIG FILE]: Well defined.\n"),
|
||||||
|
|
@ -6,6 +6,17 @@ use strip_ansi_escapes::strip;
|
||||||
|
|
||||||
use colors_transform::{Color, Rgb};
|
use colors_transform::{Color, Rgb};
|
||||||
use zellij_tile::data::{Palette, PaletteColor, PaletteSource, Theme};
|
use zellij_tile::data::{Palette, PaletteColor, PaletteSource, Theme};
|
||||||
|
use std::os::unix::{fs::PermissionsExt};
|
||||||
|
use std::path::{Path};
|
||||||
|
use std::{fs, io};
|
||||||
|
|
||||||
|
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 {
|
fn ansi_len(s: &str) -> usize {
|
||||||
from_utf8(&strip(s.as_bytes()).unwrap())
|
from_utf8(&strip(s.as_bytes()).unwrap())
|
||||||
Loading…
Add table
Reference in a new issue