diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2443c060..744bfdb0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,10 +16,18 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Add WASM target run: rustup target add wasm32-wasi - name: Install cargo-make - run: cargo install --debug cargo-make + run: test -x "${HOME}/.cargo/bin/cargo-make" || cargo install --debug cargo-make - name: Build run: cargo make build - name: Test @@ -31,8 +39,16 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Install cargo-make - run: cargo install --debug cargo-make + run: test -x "${HOME}/.cargo/bin/cargo-make" || cargo install --debug cargo-make - name: Check Format run: cargo make check-format @@ -42,7 +58,15 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Install cargo-make - run: cargo install --debug cargo-make + run: test -x "${HOME}/.cargo/bin/cargo-make" || cargo install --debug cargo-make - name: Check Lints run: cargo make clippy -D clippy::all diff --git a/CHANGELOG.md b/CHANGELOG.md index 536e1012..a039d478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] * Remove unused imports (https://github.com/zellij-org/zellij/pull/504) * More Infrastructure changes for the upcoming session detach feature: run server and client in separate processes (https://github.com/zellij-org/zellij/pull/499) +* Restructuring cargo workspace: Separate client, server and utils into separate crates (https://github.com/zellij-org/zellij/pull/515) +* Terminal compatibility: handle most OSC sequences (https://github.com/zellij-org/zellij/pull/517) ## [0.11.0] - 2021-05-15 diff --git a/Cargo.lock b/Cargo.lock index 92b2d0ca..31c5e709 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,7 +132,7 @@ dependencies = [ "event-listener", "futures-lite", "once_cell", - "signal-hook", + "signal-hook 0.3.8", "winapi", ] @@ -222,18 +222,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "blocking" version = "1.0.2" @@ -463,6 +451,31 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossterm" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e86d73f2a0b407b5768d10a8c720cf5d2df49a9efc10ca09176d201ead4b7fb" +dependencies = [ + "bitflags", + "crossterm_winapi", + "lazy_static", + "libc", + "mio", + "parking_lot", + "signal-hook 0.1.17", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db" +dependencies = [ + "winapi", +] + [[package]] name = "ctor" version = "0.1.20" @@ -620,12 +633,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futures" version = "0.3.14" @@ -950,19 +957,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" -[[package]] -name = "lexical-core" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.0", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.93" @@ -987,9 +981,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ "scopeguard", ] @@ -1047,6 +1041,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mio" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + [[package]] name = "more-asserts" version = "0.2.1" @@ -1075,16 +1091,12 @@ dependencies = [ ] [[package]] -name = "nom" -version = "6.1.2" +name = "ntapi" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "bitvec", - "funty", - "lexical-core", - "memchr", - "version_check", + "winapi", ] [[package]] @@ -1131,6 +1143,31 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "pin-project-lite" version = "0.2.6" @@ -1226,12 +1263,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "rand" version = "0.3.23" @@ -1480,6 +1511,17 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "signal-hook" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" +dependencies = [ + "libc", + "mio", + "signal-hook-registry", +] + [[package]] name = "signal-hook" version = "0.3.8" @@ -1542,12 +1584,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "status-bar" version = "0.1.0" @@ -1651,12 +1687,6 @@ dependencies = [ "zellij-tile-utils", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "target-lexicon" version = "0.11.2" @@ -1677,6 +1707,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "termbg" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133c09f40b7a6a10616bb46d2b7d78d50cb8c6c475c84f3c02fe261957d9e0e0" +dependencies = [ + "crossterm", + "thiserror", + "winapi", +] + [[package]] name = "terminal_size" version = "0.1.16" @@ -1699,15 +1740,6 @@ dependencies = [ "redox_termios", ] -[[package]] -name = "termios" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" -dependencies = [ - "libc", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -1810,15 +1842,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" -[[package]] -name = "unicode-truncate" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a04be5ca5f7a4a7270ffea82bc41c59b87c611ed04f20e77c338e8d3c2348e42" -dependencies = [ - "unicode-width", -] - [[package]] name = "unicode-width" version = "0.1.8" @@ -2253,12 +2276,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "yaml-rust" version = "0.4.5" @@ -2272,37 +2289,53 @@ dependencies = [ name = "zellij" version = "0.12.0" dependencies = [ - "ansi_term 0.12.1", - "async-std", - "backtrace", - "bincode", - "colors-transform", - "daemonize", - "directories-next", - "futures", "insta", "interprocess", - "lazy_static", - "libc", - "names", "nix", - "nom", + "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 0.3.8", + "termbg", + "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_json", "serde_yaml", - "signal-hook", - "strip-ansi-escapes", - "structopt", - "strum", - "tempfile", + "signal-hook 0.3.8", "termion", - "termios", - "unicode-truncate", "unicode-width", "vte 0.10.1", "wasmer", "wasmer-wasi", "zellij-tile", + "zellij-utils", ] [[package]] @@ -2321,3 +2354,26 @@ version = "0.12.0" dependencies = [ "ansi_term 0.12.1", ] + +[[package]] +name = "zellij-utils" +version = "0.12.0" +dependencies = [ + "async-std", + "backtrace", + "bincode", + "colors-transform", + "directories-next", + "interprocess", + "lazy_static", + "names", + "nix", + "serde", + "serde_yaml", + "strip-ansi-escapes", + "structopt", + "strum", + "tempfile", + "termion", + "zellij-tile", +] diff --git a/Cargo.toml b/Cargo.toml index 099d17f6..231b480a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,52 +8,34 @@ license = "MIT" repository = "https://github.com/zellij-org/zellij" homepage = "https://zellij.dev" include = ["src/**/*", "assets/plugins/*", "assets/layouts/*", "assets/config/*", "LICENSE.md", "README.md", "!**/*_test.*", "!**/tests/**/*"] +resolver = "2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ansi_term = "0.12.1" -backtrace = "0.3.55" -bincode = "1.3.1" -daemonize = "0.4.1" -directories-next = "2.0" -futures = "0.3.5" -libc = "0.2" -nix = "0.19.1" -nom = "6.0.1" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_yaml = "0.8" -signal-hook = "0.3" -strip-ansi-escapes = "0.1.0" -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-utils = { path = "zellij-utils/", version = "0.12.0" } +zellij-client = { path = "zellij-client/", version = "0.12.0" } +zellij-server = { path = "zellij-server/", version = "0.12.0" } zellij-tile = { path = "zellij-tile/", version = "0.12.0" } - -[dependencies.async-std] -version = "1.3.0" -features = ["unstable"] +structopt = "0.3" +interprocess = "1.1.1" +vte = "0.10.1" +nix = "0.19.1" [dev-dependencies] insta = "1.6.0" -tempfile = "3.2.0" +zellij-utils = { path = "zellij-utils/", version = "*", features = ["test"] } +zellij-client = { path = "zellij-client/", version = "*", features = ["test"] } +zellij-server = { path = "zellij-server/", version = "*", features = ["test"] } [build-dependencies] structopt = "0.3" [workspace] members = [ + "zellij-client", + "zellij-server", + "zellij-utils", "zellij-tile", "zellij-tile-utils", "default-plugins/status-bar", diff --git a/Makefile.toml b/Makefile.toml index 75f78b25..6decb0de 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -24,6 +24,7 @@ env = { "SKIP_TEST" = true } [tasks.test] condition = { env_false = ["SKIP_TEST"] } dependencies = ["pre-test"] +args = ["test"] [tasks.post-test] env = { "SKIP_TEST" = false } @@ -37,6 +38,12 @@ run_task = "launch" [tasks.build-workspace] run_task = { name = "build", fork = true } +[tasks.build] +args = ["build"] + +[tasks.build-release] +args = ["build", "--release"] + [tasks.build-dev-data-dir] script_runner = "@duckscript" script = ''' diff --git a/README.md b/README.md index a1a41fe6..916f6720 100644 --- a/README.md +++ b/README.md @@ -36,15 +36,14 @@ cargo install zellij Or you can download a prebuilt binary from our [Releases](https://github.com/zellij-org/zellij/releases). -As the default plugins make use of characters that are mostly only found in [nerdfonts](https://www.nerdfonts.com/), -you get the best experience either with installing nerdfonts, or telling the plugins that you request a ui, that -does not rely on such characters with `zellij options --simplified-ui`, or putting `simplified_ui: true` in the -config file. +The default plugins make use of characters that are mostly found in [nerdfonts](https://www.nerdfonts.com/). +To get the best experience either install nerdfonts, or use the simplified ui by starting Zellij with `zellij options --simplified-ui`, or putting `simplified_ui: true` in the config file. ## How do I hack on it? (Contributing) * Clone the project * Install cargo-make with `cargo install --force cargo-make` * In the project folder, for debug builds run: `cargo make run` +* To run all tests: `cargo make test` For more build commands, see [`Contributing.md`](CONTRIBUTING.md). diff --git a/default-plugins/status-bar/src/main.rs b/default-plugins/status-bar/src/main.rs index bb56c279..cf9445d6 100644 --- a/default-plugins/status-bar/src/main.rs +++ b/default-plugins/status-bar/src/main.rs @@ -72,55 +72,61 @@ pub struct ColoredElements { // that can be defined in the config perhaps fn color_elements(palette: Palette) -> ColoredElements { match palette.source { + // "cyan" here is used as a background as a dirty hack + // this is because the Palette struct doesn't have a "gray" section + // and we can't use its "bg" because that is now dynamically taken from the terminal + // and might often not actually fit the rest of the colorscheme + // + // to fix this, we need to restructure the Palette struct PaletteSource::Default => ColoredElements { - selected_prefix_separator: style!(palette.bg, palette.green), + selected_prefix_separator: style!(palette.cyan, palette.green), selected_char_left_separator: style!(palette.black, palette.green).bold(), selected_char_shortcut: style!(palette.red, palette.green).bold(), selected_char_right_separator: style!(palette.black, palette.green).bold(), selected_styled_text: style!(palette.black, palette.green).bold(), - selected_suffix_separator: style!(palette.green, palette.bg).bold(), - unselected_prefix_separator: style!(palette.bg, palette.fg), + selected_suffix_separator: style!(palette.green, palette.cyan).bold(), + unselected_prefix_separator: style!(palette.cyan, palette.fg), unselected_char_left_separator: style!(palette.black, palette.fg).bold(), unselected_char_shortcut: style!(palette.red, palette.fg).bold(), unselected_char_right_separator: style!(palette.black, palette.fg).bold(), unselected_styled_text: style!(palette.black, palette.fg).bold(), - unselected_suffix_separator: style!(palette.fg, palette.bg), - disabled_prefix_separator: style!(palette.bg, palette.fg), - disabled_styled_text: style!(palette.bg, palette.fg).dimmed(), - disabled_suffix_separator: style!(palette.fg, palette.bg), - selected_single_letter_prefix_separator: style!(palette.bg, palette.green), + unselected_suffix_separator: style!(palette.fg, palette.cyan), + disabled_prefix_separator: style!(palette.cyan, palette.fg), + disabled_styled_text: style!(palette.cyan, palette.fg).dimmed(), + disabled_suffix_separator: style!(palette.fg, palette.cyan), + selected_single_letter_prefix_separator: style!(palette.cyan, palette.green), selected_single_letter_char_shortcut: style!(palette.red, palette.green).bold(), - selected_single_letter_suffix_separator: style!(palette.green, palette.bg), - unselected_single_letter_prefix_separator: style!(palette.bg, palette.fg), + selected_single_letter_suffix_separator: style!(palette.green, palette.cyan), + unselected_single_letter_prefix_separator: style!(palette.cyan, palette.fg), unselected_single_letter_char_shortcut: style!(palette.red, palette.fg).bold(), - unselected_single_letter_suffix_separator: style!(palette.fg, palette.bg), - superkey_prefix: style!(palette.white, palette.bg).bold(), - superkey_suffix_separator: style!(palette.bg, palette.bg), + unselected_single_letter_suffix_separator: style!(palette.fg, palette.cyan), + superkey_prefix: style!(palette.white, palette.cyan).bold(), + superkey_suffix_separator: style!(palette.cyan, palette.cyan), }, PaletteSource::Xresources => ColoredElements { - selected_prefix_separator: style!(palette.bg, palette.green), + selected_prefix_separator: style!(palette.cyan, palette.green), selected_char_left_separator: style!(palette.fg, palette.green).bold(), selected_char_shortcut: style!(palette.red, palette.green).bold(), selected_char_right_separator: style!(palette.fg, palette.green).bold(), - selected_styled_text: style!(palette.bg, palette.green).bold(), - selected_suffix_separator: style!(palette.green, palette.bg).bold(), - unselected_prefix_separator: style!(palette.bg, palette.fg), - unselected_char_left_separator: style!(palette.bg, palette.fg).bold(), + selected_styled_text: style!(palette.cyan, palette.green).bold(), + selected_suffix_separator: style!(palette.green, palette.cyan).bold(), + unselected_prefix_separator: style!(palette.cyan, palette.fg), + unselected_char_left_separator: style!(palette.cyan, palette.fg).bold(), unselected_char_shortcut: style!(palette.red, palette.fg).bold(), - unselected_char_right_separator: style!(palette.bg, palette.fg).bold(), - unselected_styled_text: style!(palette.bg, palette.fg).bold(), - unselected_suffix_separator: style!(palette.fg, palette.bg), - disabled_prefix_separator: style!(palette.bg, palette.fg), - disabled_styled_text: style!(palette.bg, palette.fg).dimmed(), - disabled_suffix_separator: style!(palette.fg, palette.bg), + unselected_char_right_separator: style!(palette.cyan, palette.fg).bold(), + unselected_styled_text: style!(palette.cyan, palette.fg).bold(), + unselected_suffix_separator: style!(palette.fg, palette.cyan), + disabled_prefix_separator: style!(palette.cyan, palette.fg), + disabled_styled_text: style!(palette.cyan, palette.fg).dimmed(), + disabled_suffix_separator: style!(palette.fg, palette.cyan), selected_single_letter_prefix_separator: style!(palette.fg, palette.green), selected_single_letter_char_shortcut: style!(palette.red, palette.green).bold(), selected_single_letter_suffix_separator: style!(palette.green, palette.fg), - unselected_single_letter_prefix_separator: style!(palette.fg, palette.bg), + unselected_single_letter_prefix_separator: style!(palette.fg, palette.cyan), unselected_single_letter_char_shortcut: style!(palette.red, palette.fg).bold(), - unselected_single_letter_suffix_separator: style!(palette.fg, palette.bg), - superkey_prefix: style!(palette.bg, palette.fg).bold(), - superkey_suffix_separator: style!(palette.fg, palette.bg), + unselected_single_letter_suffix_separator: style!(palette.fg, palette.cyan), + superkey_prefix: style!(palette.cyan, palette.fg).bold(), + superkey_suffix_separator: style!(palette.fg, palette.cyan), }, } } @@ -155,7 +161,7 @@ impl ZellijPlugin for State { // [48;5;238m is gray background, [0K is so that it fills the rest of the line // [m is background reset, [0K is so that it clears the rest of the line - match self.mode_info.palette.bg { + match self.mode_info.palette.cyan { PaletteColor::Rgb((r, g, b)) => { println!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", first_line, r, g, b); } diff --git a/default-plugins/tab-bar/src/line.rs b/default-plugins/tab-bar/src/line.rs index 574edb78..fce8982d 100644 --- a/default-plugins/tab-bar/src/line.rs +++ b/default-plugins/tab-bar/src/line.rs @@ -62,11 +62,11 @@ fn left_more_message(tab_count_to_the_left: usize, palette: Palette, separator: }; // 238 let more_text_len = more_text.chars().count() + 2; // 2 for the arrows - let left_separator = style!(palette.bg, palette.orange).paint(separator); + let left_separator = style!(palette.cyan, palette.orange).paint(separator); let more_styled_text = style!(palette.black, palette.orange) .bold() .paint(more_text); - let right_separator = style!(palette.orange, palette.bg).paint(separator); + let right_separator = style!(palette.orange, palette.cyan).paint(separator); let more_styled_text = format!( "{}", ANSIStrings(&[left_separator, more_styled_text, right_separator,]) @@ -94,11 +94,11 @@ fn right_more_message( " +many → ".to_string() }; let more_text_len = more_text.chars().count() + 1; // 2 for the arrow - let left_separator = style!(palette.bg, palette.orange).paint(separator); + let left_separator = style!(palette.cyan, palette.orange).paint(separator); let more_styled_text = style!(palette.black, palette.orange) .bold() .paint(more_text); - let right_separator = style!(palette.orange, palette.bg).paint(separator); + let right_separator = style!(palette.orange, palette.cyan).paint(separator); let more_styled_text = format!( "{}", ANSIStrings(&[left_separator, more_styled_text, right_separator,]) @@ -147,7 +147,9 @@ fn add_next_tabs_msg( fn tab_line_prefix(palette: Palette) -> LinePart { let prefix_text = " Zellij ".to_string(); let prefix_text_len = prefix_text.chars().count(); - let prefix_styled_text = style!(palette.white, palette.bg).bold().paint(prefix_text); + let prefix_styled_text = style!(palette.white, palette.cyan) + .bold() + .paint(prefix_text); LinePart { part: format!("{}", prefix_styled_text), len: prefix_text_len, diff --git a/default-plugins/tab-bar/src/main.rs b/default-plugins/tab-bar/src/main.rs index 00ff4bd9..46336be3 100644 --- a/default-plugins/tab-bar/src/main.rs +++ b/default-plugins/tab-bar/src/main.rs @@ -75,7 +75,7 @@ impl ZellijPlugin for State { for bar_part in tab_line { s = format!("{}{}", s, bar_part.part); } - match self.mode_info.palette.bg { + match self.mode_info.palette.cyan { PaletteColor::Rgb((r, g, b)) => { println!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", s, r, g, b); } diff --git a/default-plugins/tab-bar/src/tab.rs b/default-plugins/tab-bar/src/tab.rs index 85e2c378..fb8e377d 100644 --- a/default-plugins/tab-bar/src/tab.rs +++ b/default-plugins/tab-bar/src/tab.rs @@ -4,12 +4,12 @@ use zellij_tile::prelude::*; use zellij_tile_utils::style; pub fn active_tab(text: String, palette: Palette, separator: &str) -> LinePart { - let left_separator = style!(palette.bg, palette.green).paint(separator); + let left_separator = style!(palette.cyan, palette.green).paint(separator); let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the text padding let tab_styled_text = style!(palette.black, palette.green) .bold() .paint(format!(" {} ", text)); - let right_separator = style!(palette.green, palette.bg).paint(separator); + let right_separator = style!(palette.green, palette.cyan).paint(separator); let tab_styled_text = format!( "{}", ANSIStrings(&[left_separator, tab_styled_text, right_separator,]) @@ -21,12 +21,12 @@ pub fn active_tab(text: String, palette: Palette, separator: &str) -> LinePart { } pub fn non_active_tab(text: String, palette: Palette, separator: &str) -> LinePart { - let left_separator = style!(palette.bg, palette.fg).paint(separator); + let left_separator = style!(palette.cyan, palette.fg).paint(separator); let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the padding let tab_styled_text = style!(palette.black, palette.fg) .bold() .paint(format!(" {} ", text)); - let right_separator = style!(palette.fg, palette.bg).paint(separator); + let right_separator = style!(palette.fg, palette.cyan).paint(separator); let tab_styled_text = format!( "{}", ANSIStrings(&[left_separator, tab_styled_text, right_separator,]) diff --git a/src/common/input/mod.rs b/src/common/input/mod.rs deleted file mode 100644 index f30ccf23..00000000 --- a/src/common/input/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! The way terminal input is handled. - -pub mod actions; -pub mod config; -pub mod handler; -pub mod keybinds; -pub mod options; diff --git a/src/common/mod.rs b/src/common/mod.rs deleted file mode 100644 index c91e1e05..00000000 --- a/src/common/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod command_is_executing; -pub mod errors; -pub mod input; -pub mod ipc; -pub mod os_input_output; -pub mod pty; -pub mod screen; -pub mod setup; -pub mod thread_bus; -pub mod utils; -pub mod wasm_vm; - -use crate::panes::PaneId; -use crate::server::ServerInstruction; diff --git a/src/common/thread_bus.rs b/src/common/thread_bus.rs deleted file mode 100644 index 8827d068..00000000 --- a/src/common/thread_bus.rs +++ /dev/null @@ -1,142 +0,0 @@ -//! Definitions and helpers for sending and receiving messages between threads. - -use async_std::task_local; -use std::cell::RefCell; -use std::sync::mpsc; - -use crate::common::pty::PtyInstruction; -use crate::common::ServerInstruction; -use crate::errors::{get_current_ctx, ErrorContext}; -use crate::os_input_output::ServerOsApi; -use crate::screen::ScreenInstruction; -use crate::wasm_vm::PluginInstruction; - -/// An [MPSC](mpsc) asynchronous channel with added error context. -pub type ChannelWithContext = ( - mpsc::Sender<(T, ErrorContext)>, - mpsc::Receiver<(T, ErrorContext)>, -); -/// An [MPSC](mpsc) synchronous channel with added error context. -pub type SyncChannelWithContext = ( - mpsc::SyncSender<(T, ErrorContext)>, - mpsc::Receiver<(T, ErrorContext)>, -); - -/// Wrappers around the two standard [MPSC](mpsc) sender types, [`mpsc::Sender`] and [`mpsc::SyncSender`], with an additional [`ErrorContext`]. -#[derive(Clone)] -pub enum SenderType { - /// A wrapper around an [`mpsc::Sender`], adding an [`ErrorContext`]. - Sender(mpsc::Sender<(T, ErrorContext)>), - /// A wrapper around an [`mpsc::SyncSender`], adding an [`ErrorContext`]. - SyncSender(mpsc::SyncSender<(T, ErrorContext)>), -} - -/// Sends messages on an [MPSC](std::sync::mpsc) channel, along with an [`ErrorContext`], -/// synchronously or asynchronously depending on the underlying [`SenderType`]. -#[derive(Clone)] -pub struct SenderWithContext { - sender: SenderType, -} - -impl SenderWithContext { - pub fn new(sender: SenderType) -> Self { - Self { sender } - } - - /// Sends an event, along with the current [`ErrorContext`], on this - /// [`SenderWithContext`]'s channel. - pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> { - let err_ctx = get_current_ctx(); - match self.sender { - SenderType::Sender(ref s) => s.send((event, err_ctx)), - SenderType::SyncSender(ref s) => s.send((event, err_ctx)), - } - } -} - -unsafe impl Send for SenderWithContext {} -unsafe impl Sync for SenderWithContext {} - -thread_local!( - /// A key to some thread local storage (TLS) that holds a representation of the thread's call - /// stack in the form of an [`ErrorContext`]. - pub static OPENCALLS: RefCell = RefCell::default() -); - -task_local! { - /// A key to some task local storage that holds a representation of the task's call - /// stack in the form of an [`ErrorContext`]. - pub static ASYNCOPENCALLS: RefCell = RefCell::default() -} - -/// A container for senders to the different threads in zellij on the server side -#[derive(Clone)] -pub struct ThreadSenders { - pub to_screen: Option>, - pub to_pty: Option>, - pub to_plugin: Option>, - pub to_server: Option>, -} - -impl ThreadSenders { - pub fn send_to_screen( - &self, - instruction: ScreenInstruction, - ) -> Result<(), mpsc::SendError<(ScreenInstruction, ErrorContext)>> { - self.to_screen.as_ref().unwrap().send(instruction) - } - - pub fn send_to_pty( - &self, - instruction: PtyInstruction, - ) -> Result<(), mpsc::SendError<(PtyInstruction, ErrorContext)>> { - self.to_pty.as_ref().unwrap().send(instruction) - } - - pub fn send_to_plugin( - &self, - instruction: PluginInstruction, - ) -> Result<(), mpsc::SendError<(PluginInstruction, ErrorContext)>> { - self.to_plugin.as_ref().unwrap().send(instruction) - } - - pub fn send_to_server( - &self, - instruction: ServerInstruction, - ) -> Result<(), mpsc::SendError<(ServerInstruction, ErrorContext)>> { - self.to_server.as_ref().unwrap().send(instruction) - } -} - -/// A container for a receiver, OS input and the senders to a given thread -pub struct Bus { - pub receiver: mpsc::Receiver<(T, ErrorContext)>, - pub senders: ThreadSenders, - pub os_input: Option>, -} - -impl Bus { - pub fn new( - receiver: mpsc::Receiver<(T, ErrorContext)>, - to_screen: Option<&SenderWithContext>, - to_pty: Option<&SenderWithContext>, - to_plugin: Option<&SenderWithContext>, - to_server: Option<&SenderWithContext>, - os_input: Option>, - ) -> Self { - Bus { - receiver, - senders: ThreadSenders { - to_screen: to_screen.cloned(), - to_pty: to_pty.cloned(), - to_plugin: to_plugin.cloned(), - to_server: to_server.cloned(), - }, - os_input: os_input.clone(), - } - } - - pub fn recv(&self) -> Result<(T, ErrorContext), mpsc::RecvError> { - self.receiver.recv() - } -} diff --git a/src/common/utils/mod.rs b/src/common/utils/mod.rs deleted file mode 100644 index 1cb4df27..00000000 --- a/src/common/utils/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Zellij utilities. - -pub mod consts; -pub mod logging; -pub mod shared; diff --git a/src/main.rs b/src/main.rs index 49e42ffb..1e1d4764 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,22 @@ -mod cli; -mod client; -mod common; -mod server; #[cfg(test)] mod tests; -use client::{boundaries, layout, panes, start_client, tab}; -use common::{ - command_is_executing, errors, os_input_output, pty, screen, setup::Setup, utils, wasm_vm, -}; -use server::start_server; -use 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 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() { let opts = CliArgs::from_args(); - if let Some(crate::cli::ConfigCli::Setup(setup)) = opts.option.clone() { + if let Some(ConfigCli::Setup(setup)) = opts.option.clone() { Setup::from_cli(&setup, opts).expect("Failed to print to stdout"); std::process::exit(0); } else { @@ -39,10 +30,22 @@ pub fn main() { atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap(); atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap(); if let Some(path) = opts.server { - let os_input = get_server_os_input(); + let os_input = match get_server_os_input() { + Ok(server_os_input) => server_os_input, + Err(e) => { + eprintln!("failed to open terminal:\n{}", e); + std::process::exit(1); + } + }; start_server(Box::new(os_input), path); } else { - let os_input = get_client_os_input(); + let os_input = match get_client_os_input() { + Ok(os_input) => os_input, + Err(e) => { + eprintln!("failed to open terminal:\n{}", e); + std::process::exit(1); + } + }; start_client(Box::new(os_input), opts, config); } } diff --git a/src/tests/fakes.rs b/src/tests/fakes.rs index 98ec694a..09cc2ba3 100644 --- a/src/tests/fakes.rs +++ b/src/tests/fakes.rs @@ -1,4 +1,5 @@ -use crate::panes::PositionAndSize; +use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes}; +use crate::tests::utils::commands::{QUIT, SLEEP}; use interprocess::local_socket::LocalSocketStream; use std::collections::{HashMap, VecDeque}; use std::io::Write; @@ -6,15 +7,16 @@ use std::os::unix::io::RawFd; use std::path::PathBuf; use std::sync::{mpsc, Arc, Condvar, Mutex}; use std::time::{Duration, Instant}; - -use crate::common::ipc::{ClientToServerMsg, ServerToClientMsg}; -use crate::common::thread_bus::{ChannelWithContext, SenderType, SenderWithContext}; -use crate::errors::ErrorContext; -use crate::os_input_output::{ClientOsApi, ServerOsApi}; -use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes}; -use crate::tests::utils::commands::{QUIT, SLEEP}; -use crate::utils::shared::default_palette; +use zellij_client::os_input_output::ClientOsApi; +use zellij_server::os_input_output::ServerOsApi; use zellij_tile::data::Palette; +use zellij_utils::{ + channels::{ChannelWithContext, SenderType, SenderWithContext}, + errors::ErrorContext, + ipc::{ClientToServerMsg, ServerToClientMsg}, + pane_size::PositionAndSize, + shared::default_palette, +}; const MIN_TIME_BETWEEN_SNAPSHOTS: Duration = Duration::from_millis(150); @@ -217,6 +219,9 @@ impl ClientOsApi for FakeInputOutput { } } fn connect_to_server(&self, _path: &std::path::Path) {} + fn load_palette(&self) -> Palette { + default_palette() + } } impl ServerOsApi for FakeInputOutput { diff --git a/src/tests/integration/basic.rs b/src/tests/integration/basic.rs index bb581eb1..640b1c55 100644 --- a/src/tests/integration/basic.rs +++ b/src/tests/integration/basic.rs @@ -1,7 +1,6 @@ -use crate::panes::PositionAndSize; use ::insta::assert_snapshot; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::commands::{ @@ -12,6 +11,7 @@ use crate::tests::utils::commands::{ }; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/close_pane.rs b/src/tests/integration/close_pane.rs index cfb912ee..b5ba7f19 100644 --- a/src/tests/integration/close_pane.rs +++ b/src/tests/integration/close_pane.rs @@ -1,17 +1,17 @@ -use crate::panes::PositionAndSize; use ::insta::assert_snapshot; +use zellij_utils::pane_size::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ CLOSE_PANE_IN_PANE_MODE, ESC, MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/compatibility.rs b/src/tests/integration/compatibility.rs index 06222a3a..3b28a970 100644 --- a/src/tests/integration/compatibility.rs +++ b/src/tests/integration/compatibility.rs @@ -1,15 +1,15 @@ use ::insta::assert_snapshot; use ::std::collections::HashMap; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::possible_tty_inputs::Bytes; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::QUIT; +use zellij_utils::input::config::Config; /* * These tests are general compatibility tests for non-trivial scenarios running in the terminal. diff --git a/src/tests/integration/layouts.rs b/src/tests/integration/layouts.rs index fa46e9f7..e6986924 100644 --- a/src/tests/integration/layouts.rs +++ b/src/tests/integration/layouts.rs @@ -1,13 +1,13 @@ use insta::assert_snapshot; use std::path::PathBuf; -use crate::common::input::config::Config; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::commands::QUIT; use crate::tests::utils::get_output_frame_snapshots; use crate::CliArgs; +use zellij_utils::input::config::Config; +use zellij_utils::pane_size::PositionAndSize; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/move_focus_down.rs b/src/tests/integration/move_focus_down.rs index b1032bd0..2f18ab62 100644 --- a/src/tests/integration/move_focus_down.rs +++ b/src/tests/integration/move_focus_down.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_DOWN_IN_PANE_MODE, MOVE_FOCUS_UP_IN_PANE_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/move_focus_left.rs b/src/tests/integration/move_focus_left.rs index 4842f342..a9fca49e 100644 --- a/src/tests/integration/move_focus_left.rs +++ b/src/tests/integration/move_focus_left.rs @@ -1,17 +1,17 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ ENTER, MOVE_FOCUS_LEFT_IN_NORMAL_MODE, MOVE_FOCUS_LEFT_IN_PANE_MODE, MOVE_FOCUS_RIGHT_IN_PANE_MODE, NEW_TAB_IN_TAB_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, TAB_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/move_focus_right.rs b/src/tests/integration/move_focus_right.rs index 6ff6e21a..c85d5b96 100644 --- a/src/tests/integration/move_focus_right.rs +++ b/src/tests/integration/move_focus_right.rs @@ -1,17 +1,17 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ ENTER, MOVE_FOCUS_LEFT_IN_PANE_MODE, MOVE_FOCUS_RIGHT_IN_NORMAL_MODE, MOVE_FOCUS_RIGHT_IN_PANE_MODE, NEW_TAB_IN_TAB_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, TAB_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/move_focus_up.rs b/src/tests/integration/move_focus_up.rs index 068ded52..d161ff8a 100644 --- a/src/tests/integration/move_focus_up.rs +++ b/src/tests/integration/move_focus_up.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_DOWN_IN_PANE_MODE, MOVE_FOCUS_UP_IN_PANE_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_down.rs b/src/tests/integration/resize_down.rs index cc4b9ec4..4ef45a06 100644 --- a/src/tests/integration/resize_down.rs +++ b/src/tests/integration/resize_down.rs @@ -1,17 +1,17 @@ use insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_left.rs b/src/tests/integration/resize_left.rs index c5ba5427..1b820501 100644 --- a/src/tests/integration/resize_left.rs +++ b/src/tests/integration/resize_left.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_right.rs b/src/tests/integration/resize_right.rs index 43409ec1..44601f2c 100644 --- a/src/tests/integration/resize_right.rs +++ b/src/tests/integration/resize_right.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_MODE, RESIZE_RIGHT_IN_RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/resize_up.rs b/src/tests/integration/resize_up.rs index 200fcc6e..9aca8d5a 100644 --- a/src/tests/integration/resize_up.rs +++ b/src/tests/integration/resize_up.rs @@ -1,16 +1,16 @@ use ::insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/tabs.rs b/src/tests/integration/tabs.rs index 0995d16c..90f82c6d 100644 --- a/src/tests/integration/tabs.rs +++ b/src/tests/integration/tabs.rs @@ -2,16 +2,17 @@ use insta::assert_snapshot; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; +use crate::tests::utils::commands::CLOSE_PANE_IN_PANE_MODE; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; -use crate::{panes::PositionAndSize, tests::utils::commands::CLOSE_PANE_IN_PANE_MODE}; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ CLOSE_TAB_IN_TAB_MODE, NEW_TAB_IN_TAB_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SWITCH_NEXT_TAB_IN_TAB_MODE, SWITCH_PREV_TAB_IN_TAB_MODE, TAB_MODE, TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; +use zellij_utils::pane_size::PositionAndSize; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/integration/terminal_window_resize.rs b/src/tests/integration/terminal_window_resize.rs index 2e56300f..2be41c3a 100644 --- a/src/tests/integration/terminal_window_resize.rs +++ b/src/tests/integration/terminal_window_resize.rs @@ -1,12 +1,12 @@ -use crate::panes::PositionAndSize; use ::insta::assert_snapshot; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::commands::QUIT; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(fake_win_size.clone()) diff --git a/src/tests/integration/toggle_fullscreen.rs b/src/tests/integration/toggle_fullscreen.rs index 00d98170..80257982 100644 --- a/src/tests/integration/toggle_fullscreen.rs +++ b/src/tests/integration/toggle_fullscreen.rs @@ -1,16 +1,16 @@ use insta::assert_snapshot; -use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::start; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; use crate::CliArgs; +use zellij_utils::pane_size::PositionAndSize; -use crate::common::input::config::Config; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, }; +use zellij_utils::input::config::Config; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { FakeInputOutput::new(*fake_win_size) diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 7aaad79f..3e548db7 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -4,12 +4,10 @@ pub mod possible_tty_inputs; pub mod tty_inputs; pub mod utils; -use crate::cli::CliArgs; -use crate::client::start_client; -use crate::common::input::config::Config; -use crate::os_input_output::{ClientOsApi, ServerOsApi}; -use crate::server::start_server; use std::path::PathBuf; +use zellij_client::{os_input_output::ClientOsApi, start_client}; +use zellij_server::{os_input_output::ServerOsApi, start_server}; +use zellij_utils::{cli::CliArgs, input::config::Config}; pub fn start( client_os_input: Box, diff --git a/src/tests/utils.rs b/src/tests/utils.rs index f01c1ac5..441f9bce 100644 --- a/src/tests/utils.rs +++ b/src/tests/utils.rs @@ -1,5 +1,6 @@ -use crate::panes::PositionAndSize; -use crate::panes::TerminalPane; +use zellij_server::{panes::TerminalPane, tab::Pane}; +use zellij_tile::data::Palette; +use zellij_utils::pane_size::PositionAndSize; pub fn get_output_frame_snapshots( output_frames: &[Vec], @@ -7,7 +8,7 @@ pub fn get_output_frame_snapshots( ) -> Vec { let mut vte_parser = vte::Parser::new(); let main_pid = 0; - let mut terminal_output = TerminalPane::new(main_pid, *win_size); + let mut terminal_output = TerminalPane::new(main_pid, *win_size, Palette::default()); let mut snapshots = vec![]; for frame in output_frames.iter() { diff --git a/zellij-client/Cargo.toml b/zellij-client/Cargo.toml new file mode 100644 index 00000000..5d7efddd --- /dev/null +++ b/zellij-client/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "zellij-client" +version = "0.12.0" +authors = ["Kunal Mohan "] +edition = "2018" +description = "The client-side library for Zellij" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +zellij-utils = { path = "../zellij-utils/", version = "0.12.0" } +zellij-tile = { path = "../zellij-tile/", version = "0.12.0" } +termion = "1.5.0" +signal-hook = "0.3" +nix = "0.19.1" +interprocess = "1.1.1" +libc = "0.2" +termbg = "0.2.0" + +[features] +test = ["zellij-utils/test"] diff --git a/src/common/command_is_executing.rs b/zellij-client/src/command_is_executing.rs similarity index 96% rename from src/common/command_is_executing.rs rename to zellij-client/src/command_is_executing.rs index ad032557..3d672d9a 100644 --- a/src/common/command_is_executing.rs +++ b/zellij-client/src/command_is_executing.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, Condvar, Mutex}; #[derive(Clone)] -pub struct CommandIsExecuting { +pub(crate) struct CommandIsExecuting { input_thread: Arc<(Mutex, Condvar)>, } diff --git a/src/common/input/handler.rs b/zellij-client/src/input_handler.rs similarity index 65% rename from src/common/input/handler.rs rename to zellij-client/src/input_handler.rs index 4ac2cf83..e67bdf82 100644 --- a/src/common/input/handler.rs +++ b/zellij-client/src/input_handler.rs @@ -1,17 +1,15 @@ //! Main input logic. -use super::actions::Action; -use super::keybinds::Keybinds; -use crate::client::ClientInstruction; -use crate::common::input::config::Config; -use crate::common::ipc::ClientToServerMsg; -use crate::common::thread_bus::{SenderWithContext, OPENCALLS}; -use crate::errors::ContextType; -use crate::os_input_output::ClientOsApi; -use crate::CommandIsExecuting; +use crate::{os_input_output::ClientOsApi, ClientInstruction, CommandIsExecuting}; +use zellij_utils::{ + channels::{SenderWithContext, OPENCALLS}, + errors::ContextType, + input::{actions::Action, cast_termion_key, config::Config, keybinds::Keybinds}, + ipc::ClientToServerMsg, +}; -use termion::input::{TermRead, TermReadEventsAndRaw}; -use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities}; +use termion::input::TermReadEventsAndRaw; +use zellij_tile::data::{InputMode, Key}; /// Handles the dispatching of [`Action`]s according to the current /// [`InputMode`], and keep tracks of the current [`InputMode`]. @@ -172,55 +170,9 @@ impl InputHandler { } } -/// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds -/// (as pairs of [`String`]s). -// TODO this should probably be automatically generated in some way -pub fn get_mode_info( - mode: InputMode, - palette: Palette, - capabilities: PluginCapabilities, -) -> ModeInfo { - let mut keybinds: Vec<(String, String)> = vec![]; - match mode { - InputMode::Normal | InputMode::Locked => {} - InputMode::Resize => { - keybinds.push(("←↓↑→".to_string(), "Resize".to_string())); - } - InputMode::Pane => { - keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); - keybinds.push(("p".to_string(), "Next".to_string())); - keybinds.push(("n".to_string(), "New".to_string())); - keybinds.push(("d".to_string(), "Down split".to_string())); - keybinds.push(("r".to_string(), "Right split".to_string())); - keybinds.push(("x".to_string(), "Close".to_string())); - keybinds.push(("f".to_string(), "Fullscreen".to_string())); - } - InputMode::Tab => { - keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); - keybinds.push(("n".to_string(), "New".to_string())); - keybinds.push(("x".to_string(), "Close".to_string())); - keybinds.push(("r".to_string(), "Rename".to_string())); - keybinds.push(("s".to_string(), "Sync".to_string())); - } - InputMode::Scroll => { - keybinds.push(("↓↑".to_string(), "Scroll".to_string())); - keybinds.push(("PgUp/PgDn".to_string(), "Scroll Page".to_string())); - } - InputMode::RenameTab => { - keybinds.push(("Enter".to_string(), "when done".to_string())); - } - } - ModeInfo { - mode, - keybinds, - palette, - capabilities, - } -} - /// Entry point to the module. Instantiates an [`InputHandler`] and starts /// its [`InputHandler::handle_input()`] loop. -pub fn input_loop( +pub(crate) fn input_loop( os_input: Box, config: Config, command_is_executing: CommandIsExecuting, @@ -234,35 +186,3 @@ pub fn input_loop( ) .handle_input(); } - -pub fn parse_keys(input_bytes: &[u8]) -> Vec { - input_bytes.keys().flatten().map(cast_termion_key).collect() -} - -// FIXME: This is an absolutely cursed function that should be destroyed as soon -// as an alternative that doesn't touch zellij-tile can be developed... -fn cast_termion_key(event: termion::event::Key) -> Key { - match event { - termion::event::Key::Backspace => Key::Backspace, - termion::event::Key::Left => Key::Left, - termion::event::Key::Right => Key::Right, - termion::event::Key::Up => Key::Up, - termion::event::Key::Down => Key::Down, - termion::event::Key::Home => Key::Home, - termion::event::Key::End => Key::End, - termion::event::Key::PageUp => Key::PageUp, - termion::event::Key::PageDown => Key::PageDown, - termion::event::Key::BackTab => Key::BackTab, - termion::event::Key::Delete => Key::Delete, - termion::event::Key::Insert => Key::Insert, - termion::event::Key::F(n) => Key::F(n), - termion::event::Key::Char(c) => Key::Char(c), - termion::event::Key::Alt(c) => Key::Alt(c), - termion::event::Key::Ctrl(c) => Key::Ctrl(c), - termion::event::Key::Null => Key::Null, - termion::event::Key::Esc => Key::Esc, - _ => { - unimplemented!("Encountered an unknown key!") - } - } -} diff --git a/src/client/mod.rs b/zellij-client/src/lib.rs similarity index 83% rename from src/client/mod.rs rename to zellij-client/src/lib.rs index f148a50a..9deb415e 100644 --- a/src/client/mod.rs +++ b/zellij-client/src/lib.rs @@ -1,8 +1,7 @@ -pub mod boundaries; -pub mod layout; -pub mod pane_resizer; -pub mod panes; -pub mod tab; +pub mod os_input_output; + +mod command_is_executing; +mod input_handler; use std::env::current_exe; use std::io::{self, Write}; @@ -11,22 +10,23 @@ use std::process::Command; use std::sync::mpsc; use std::thread; -use crate::cli::CliArgs; -use crate::common::{ - command_is_executing::CommandIsExecuting, - errors::ContextType, - input::config::Config, - input::handler::input_loop, - input::options::Options, - ipc::{ClientToServerMsg, ServerToClientMsg}, +use crate::{ + command_is_executing::CommandIsExecuting, input_handler::input_loop, os_input_output::ClientOsApi, - thread_bus::{SenderType, SenderWithContext, SyncChannelWithContext}, - utils::consts::ZELLIJ_IPC_PIPE, +}; +use zellij_utils::cli::CliArgs; +use zellij_utils::{ + channels::{SenderType, SenderWithContext, SyncChannelWithContext}, + consts::ZELLIJ_IPC_PIPE, + errors::{ClientContext, ContextType, ErrorInstruction}, + input::config::Config, + input::options::Options, + ipc::{ClientAttributes, ClientToServerMsg, ServerToClientMsg}, }; -/// Instructions related to the client-side application and sent from server to client +/// Instructions related to the client-side application #[derive(Debug, Clone)] -pub enum ClientInstruction { +pub(crate) enum ClientInstruction { Error(String), Render(Option), UnblockInputThread, @@ -45,6 +45,24 @@ impl From for ClientInstruction { } } +impl From<&ClientInstruction> for ClientContext { + fn from(client_instruction: &ClientInstruction) -> Self { + match *client_instruction { + ClientInstruction::Exit => ClientContext::Exit, + ClientInstruction::Error(_) => ClientContext::Error, + ClientInstruction::ServerError(_) => ClientContext::ServerError, + ClientInstruction::Render(_) => ClientContext::Render, + ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread, + } + } +} + +impl ErrorInstruction for ClientInstruction { + fn error(err: String) -> Self { + ClientInstruction::Error(err) + } +} + fn spawn_server(socket_path: &Path) -> io::Result<()> { let status = Command::new(current_exe()?) .arg("--server") @@ -67,6 +85,7 @@ pub fn start_client(mut os_input: Box, opts: CliArgs, config: C let take_snapshot = "\u{1b}[?1049h"; let bracketed_paste = "\u{1b}[?2004h"; os_input.unset_raw_mode(0); + let palette = os_input.load_palette(); let _ = os_input .get_stdout_writer() .write(take_snapshot.as_bytes()) @@ -77,7 +96,7 @@ pub fn start_client(mut os_input: Box, opts: CliArgs, config: C .unwrap(); std::env::set_var(&"ZELLIJ", "0"); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] spawn_server(&*ZELLIJ_IPC_PIPE).unwrap(); let mut command_is_executing = CommandIsExecuting::new(); @@ -85,9 +104,13 @@ pub fn start_client(mut os_input: Box, opts: CliArgs, config: C let config_options = Options::from_cli(&config.options, opts.option.clone()); let full_screen_ws = os_input.get_terminal_size_using_fd(0); + let client_attributes = ClientAttributes { + position_and_size: full_screen_ws, + palette, + }; os_input.connect_to_server(&*ZELLIJ_IPC_PIPE); os_input.send_to_server(ClientToServerMsg::NewClient( - full_screen_ws, + client_attributes, Box::new(opts), Box::new(config_options), )); @@ -103,9 +126,9 @@ pub fn start_client(mut os_input: Box, opts: CliArgs, config: C let send_client_instructions = SenderWithContext::new(SenderType::SyncSender(send_client_instructions)); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] std::panic::set_hook({ - use crate::errors::handle_panic; + use zellij_utils::errors::handle_panic; let send_client_instructions = send_client_instructions.clone(); Box::new(move |info| { handle_panic(info, &send_client_instructions); diff --git a/zellij-client/src/os_input_output.rs b/zellij-client/src/os_input_output.rs new file mode 100644 index 00000000..02a516e8 --- /dev/null +++ b/zellij-client/src/os_input_output.rs @@ -0,0 +1,188 @@ +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_tile::data::{Palette, PaletteColor}; +use zellij_utils::errors::ErrorContext; +use zellij_utils::ipc::{ + ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg, +}; +use zellij_utils::pane_size::PositionAndSize; +use zellij_utils::shared::default_palette; + +fn into_raw_mode(pid: RawFd) { + let mut tio = termios::tcgetattr(pid).expect("could not get terminal attribute"); + termios::cfmakeraw(&mut tio); + match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &tio) { + Ok(_) => {} + Err(e) => panic!("error {:?}", e), + }; +} + +fn unset_raw_mode(pid: RawFd, orig_termios: termios::Termios) { + match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &orig_termios) { + Ok(_) => {} + Err(e) => panic!("error {:?}", e), + }; +} + +pub(crate) fn get_terminal_size_using_fd(fd: RawFd) -> PositionAndSize { + // TODO: do this with the nix ioctl + use libc::ioctl; + use libc::TIOCGWINSZ; + + let mut winsize = Winsize { + ws_row: 0, + ws_col: 0, + ws_xpixel: 0, + ws_ypixel: 0, + }; + + unsafe { ioctl(fd, TIOCGWINSZ, &mut winsize) }; + PositionAndSize::from(winsize) +} + +#[derive(Clone)] +pub struct ClientOsInputOutput { + orig_termios: Arc>, + send_instructions_to_server: Arc>>>, + receive_instructions_from_server: Arc>>>, +} + +/// The `ClientOsApi` trait represents an abstract interface to the features of an operating system that +/// Zellij client requires. +pub trait ClientOsApi: Send + Sync { + /// Returns the size of the terminal associated to file descriptor `fd`. + fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize; + /// Set the terminal associated to file descriptor `fd` to + /// [raw mode](https://en.wikipedia.org/wiki/Terminal_mode). + fn set_raw_mode(&mut self, fd: RawFd); + /// Set the terminal associated to file descriptor `fd` to + /// [cooked mode](https://en.wikipedia.org/wiki/Terminal_mode). + fn unset_raw_mode(&self, fd: RawFd); + /// Returns the writer that allows writing to standard output. + fn get_stdout_writer(&self) -> Box; + /// Returns the raw contents of standard input. + fn read_from_stdin(&self) -> Vec; + /// Returns a [`Box`] pointer to this [`ClientOsApi`] struct. + fn box_clone(&self) -> Box; + /// Sends a message to the server. + fn send_to_server(&self, msg: ClientToServerMsg); + /// Receives a message on client-side IPC channel + // This should be called from the client-side router thread only. + fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext); + fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box); + /// Establish a connection with the server socket. + fn connect_to_server(&self, path: &Path); + fn load_palette(&self) -> Palette; +} + +impl ClientOsApi for ClientOsInputOutput { + fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize { + get_terminal_size_using_fd(fd) + } + fn set_raw_mode(&mut self, fd: RawFd) { + into_raw_mode(fd); + } + fn unset_raw_mode(&self, fd: RawFd) { + let orig_termios = self.orig_termios.lock().unwrap(); + unset_raw_mode(fd, orig_termios.clone()); + } + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } + fn read_from_stdin(&self) -> Vec { + let stdin = std::io::stdin(); + let mut stdin = stdin.lock(); + let buffer = stdin.fill_buf().unwrap(); + let length = buffer.len(); + let read_bytes = Vec::from(buffer); + stdin.consume(length); + read_bytes + } + fn get_stdout_writer(&self) -> Box { + let stdout = ::std::io::stdout(); + Box::new(stdout) + } + fn send_to_server(&self, msg: ClientToServerMsg) { + self.send_instructions_to_server + .lock() + .unwrap() + .as_mut() + .unwrap() + .send(msg); + } + fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext) { + self.receive_instructions_from_server + .lock() + .unwrap() + .as_mut() + .unwrap() + .recv() + } + fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box) { + let mut signals = Signals::new(&[SIGWINCH, SIGTERM, SIGINT, SIGQUIT, SIGHUP]).unwrap(); + for signal in signals.forever() { + match signal { + SIGWINCH => { + sigwinch_cb(); + } + SIGTERM | SIGINT | SIGQUIT | SIGHUP => { + quit_cb(); + break; + } + _ => unreachable!(), + } + } + } + fn connect_to_server(&self, path: &Path) { + let socket; + loop { + match LocalSocketStream::connect(path) { + Ok(sock) => { + socket = sock; + break; + } + Err(_) => { + std::thread::sleep(std::time::Duration::from_millis(50)); + } + } + } + let sender = IpcSenderWithContext::new(socket); + let receiver = sender.get_receiver(); + *self.send_instructions_to_server.lock().unwrap() = Some(sender); + *self.receive_instructions_from_server.lock().unwrap() = Some(receiver); + } + fn load_palette(&self) -> Palette { + let timeout = std::time::Duration::from_millis(100); + let mut palette = default_palette(); + if let Ok(rgb) = termbg::rgb(timeout) { + palette.bg = PaletteColor::Rgb((rgb.r as u8, rgb.g as u8, rgb.b as u8)); + // TODO: also dynamically get all other colors from the user's terminal + // this should be done in the same method (OSC ]11), but there might be other + // considerations here, hence using the library + }; + palette + } +} + +impl Clone for Box { + fn clone(&self) -> Box { + self.box_clone() + } +} + +pub fn get_client_os_input() -> Result { + let current_termios = termios::tcgetattr(0)?; + let orig_termios = Arc::new(Mutex::new(current_termios)); + Ok(ClientOsInputOutput { + orig_termios, + send_instructions_to_server: Arc::new(Mutex::new(None)), + receive_instructions_from_server: Arc::new(Mutex::new(None)), + }) +} diff --git a/zellij-server/Cargo.toml b/zellij-server/Cargo.toml new file mode 100644 index 00000000..97930c75 --- /dev/null +++ b/zellij-server/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "zellij-server" +version = "0.12.0" +authors = ["Kunal Mohan "] +edition = "2018" +description = "The server-side library for Zellij" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +wasmer = "1.0.0" +wasmer-wasi = "1.0.0" +zellij-tile = { path = "../zellij-tile/", version = "0.12.0" } +zellij-utils = { path = "../zellij-utils/", version = "0.12.0" } +vte = "0.10.1" +unicode-width = "0.1.8" +ansi_term = "0.12.1" +serde_yaml = "0.8" +nix = "0.19.1" +termion = "1.5.0" +signal-hook = "0.3" +libc = "0.2" +serde_json = "1.0" +daemonize = "0.4.1" +interprocess = "1.1.1" + +[dependencies.async-std] +version = "1.3.0" +features = ["unstable"] + +[dev-dependencies] +insta = "1.6.0" + +[features] +test = ["zellij-utils/test"] diff --git a/src/server/mod.rs b/zellij-server/src/lib.rs similarity index 81% rename from src/server/mod.rs rename to zellij-server/src/lib.rs index 12cc2229..8d82313d 100644 --- a/src/server/mod.rs +++ b/zellij-server/src/lib.rs @@ -1,4 +1,13 @@ -pub mod route; +pub mod os_input_output; +pub mod panes; +pub mod tab; + +mod pty; +mod route; +mod screen; +mod thread_bus; +mod ui; +mod wasm_vm; use std::sync::{Arc, RwLock}; use std::thread; @@ -6,28 +15,28 @@ use std::{path::PathBuf, sync::mpsc}; use wasmer::Store; use zellij_tile::data::PluginCapabilities; -use crate::cli::CliArgs; -use crate::common::thread_bus::{Bus, ThreadSenders}; -use crate::common::{ - errors::ContextType, - input::options::Options, - ipc::{ClientToServerMsg, ServerToClientMsg}, +use crate::{ os_input_output::ServerOsApi, pty::{pty_thread_main, Pty, PtyInstruction}, screen::{screen_thread_main, ScreenInstruction}, - setup::{get_default_data_dir, install::populate_data_dir}, - thread_bus::{ChannelWithContext, SenderType, SenderWithContext, SyncChannelWithContext}, + thread_bus::{Bus, ThreadSenders}, + ui::layout::Layout, wasm_vm::{wasm_thread_main, PluginInstruction}, }; -use crate::layout::Layout; -use crate::panes::PositionAndSize; use route::route_thread_main; +use zellij_utils::{ + channels::{ChannelWithContext, SenderType, SenderWithContext, SyncChannelWithContext}, + cli::CliArgs, + errors::{ContextType, ErrorInstruction, ServerContext}, + input::options::Options, + ipc::{ClientAttributes, ClientToServerMsg, ServerToClientMsg}, + setup::{get_default_data_dir, install::populate_data_dir}, +}; -/// Instructions related to server-side application including the -/// ones sent by client to server +/// Instructions related to server-side application #[derive(Debug, Clone)] -pub enum ServerInstruction { - NewClient(PositionAndSize, Box, Box), +pub(crate) enum ServerInstruction { + NewClient(ClientAttributes, Box, Box), Render(Option), UnblockInputThread, ClientExit, @@ -46,7 +55,25 @@ impl From for ServerInstruction { } } -pub struct SessionMetaData { +impl From<&ServerInstruction> for ServerContext { + fn from(server_instruction: &ServerInstruction) -> Self { + match *server_instruction { + ServerInstruction::NewClient(..) => ServerContext::NewClient, + ServerInstruction::Render(_) => ServerContext::Render, + ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread, + ServerInstruction::ClientExit => ServerContext::ClientExit, + ServerInstruction::Error(_) => ServerContext::Error, + } + } +} + +impl ErrorInstruction for ServerInstruction { + fn error(err: String) -> Self { + ServerInstruction::Error(err) + } +} + +pub(crate) struct SessionMetaData { pub senders: ThreadSenders, pub capabilities: PluginCapabilities, screen_thread: Option>, @@ -66,9 +93,9 @@ impl Drop for SessionMetaData { } pub fn start_server(os_input: Box, socket_path: PathBuf) { - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] daemonize::Daemonize::new() - .working_directory(std::env::var("HOME").unwrap()) + .working_directory(std::env::current_dir().unwrap()) .umask(0o077) .start() .expect("could not daemonize the server process"); @@ -80,16 +107,16 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { let to_server = SenderWithContext::new(SenderType::SyncSender(to_server)); let sessions: Arc>> = Arc::new(RwLock::new(None)); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] std::panic::set_hook({ - use crate::errors::handle_panic; + use zellij_utils::errors::handle_panic; let to_server = to_server.clone(); Box::new(move |info| { handle_panic(info, &to_server); }) }); - #[cfg(test)] + #[cfg(any(feature = "test", test))] thread::Builder::new() .name("server_router".to_string()) .spawn({ @@ -100,12 +127,12 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { move || route_thread_main(sessions, os_input, to_server) }) .unwrap(); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] let _ = thread::Builder::new() .name("server_listener".to_string()) .spawn({ - use crate::common::os_input_output::set_permissions; use interprocess::local_socket::LocalSocketListener; + use zellij_utils::shared::set_permissions; let os_input = os_input.clone(); let sessions = sessions.clone(); @@ -145,13 +172,13 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { let (instruction, mut err_ctx) = server_receiver.recv().unwrap(); err_ctx.add_call(ContextType::IPCServer((&instruction).into())); match instruction { - ServerInstruction::NewClient(full_screen_ws, opts, config_options) => { + ServerInstruction::NewClient(client_attributes, opts, config_options) => { let session_data = init_session( os_input.clone(), opts, config_options, to_server.clone(), - full_screen_ws, + client_attributes, ); *sessions.write().unwrap() = Some(session_data); sessions @@ -180,7 +207,7 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { } } } - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] drop(std::fs::remove_file(&socket_path)); } @@ -189,7 +216,7 @@ fn init_session( opts: Box, config_options: Box, to_server: SenderWithContext, - full_screen_ws: PositionAndSize, + client_attributes: ClientAttributes, ) -> SessionMetaData { let (to_screen, screen_receiver): ChannelWithContext = mpsc::channel(); let to_screen = SenderWithContext::new(SenderType::Sender(to_screen)); @@ -210,9 +237,9 @@ fn init_session( }; // Don't use default layouts in tests, but do everywhere else - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] let default_layout = Some(PathBuf::from("default")); - #[cfg(test)] + #[cfg(any(feature = "test", test))] let default_layout = None; let layout_path = opts.layout_path; let maybe_layout = opts @@ -255,7 +282,7 @@ fn init_session( let max_panes = opts.max_panes; move || { - screen_thread_main(screen_bus, max_panes, full_screen_ws, config_options); + screen_thread_main(screen_bus, max_panes, client_attributes, config_options); } }) .unwrap(); diff --git a/src/common/os_input_output.rs b/zellij-server/src/os_input_output.rs similarity index 60% rename from src/common/os_input_output.rs rename to zellij-server/src/os_input_output.rs index adde6fdf..1fef826b 100644 --- a/src/common/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -1,9 +1,3 @@ -use crate::common::ipc::{ - ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg, -}; -use crate::errors::ErrorContext; -use crate::panes::PositionAndSize; -use crate::utils::shared::default_palette; use interprocess::local_socket::LocalSocketStream; use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::pty::{forkpty, Winsize}; @@ -11,56 +5,20 @@ use nix::sys::signal::{kill, Signal}; use nix::sys::termios; use nix::sys::wait::waitpid; use nix::unistd::{self, ForkResult, Pid}; -use signal_hook::{consts::signal::*, iterator::Signals}; -use std::io::prelude::*; -use std::os::unix::{fs::PermissionsExt, io::RawFd}; -use std::path::{Path, PathBuf}; +use signal_hook::consts::*; +use std::env; +use std::os::unix::io::RawFd; +use std::path::PathBuf; use std::process::{Child, Command}; use std::sync::{Arc, Mutex}; -use std::{env, fs, io}; use zellij_tile::data::Palette; +use zellij_utils::errors::ErrorContext; +use zellij_utils::ipc::{ + ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg, +}; +use zellij_utils::shared::default_palette; -const UNIX_PERMISSIONS: u32 = 0o700; - -pub fn set_permissions(path: &Path) -> io::Result<()> { - let mut permissions = fs::metadata(path)?.permissions(); - permissions.set_mode(UNIX_PERMISSIONS); - fs::set_permissions(path, permissions) -} - -fn into_raw_mode(pid: RawFd) { - let mut tio = termios::tcgetattr(pid).expect("could not get terminal attribute"); - termios::cfmakeraw(&mut tio); - match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &tio) { - Ok(_) => {} - Err(e) => panic!("error {:?}", e), - }; -} - -fn unset_raw_mode(pid: RawFd, orig_termios: termios::Termios) { - match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &orig_termios) { - Ok(_) => {} - Err(e) => panic!("error {:?}", e), - }; -} - -pub fn get_terminal_size_using_fd(fd: RawFd) -> PositionAndSize { - // TODO: do this with the nix ioctl - use libc::ioctl; - use libc::TIOCGWINSZ; - - let mut winsize = Winsize { - ws_row: 0, - ws_col: 0, - ws_xpixel: 0, - ws_ypixel: 0, - }; - - unsafe { ioctl(fd, TIOCGWINSZ, &mut winsize) }; - PositionAndSize::from(winsize) -} - -pub fn set_terminal_size_using_fd(fd: RawFd, columns: u16, rows: u16) { +pub(crate) fn set_terminal_size_using_fd(fd: RawFd, columns: u16, rows: u16) { // TODO: do this with the nix ioctl use libc::ioctl; use libc::TIOCSWINSZ; @@ -275,140 +233,12 @@ impl Clone for Box { } } -pub fn get_server_os_input() -> ServerOsInputOutput { - let current_termios = termios::tcgetattr(0).unwrap(); +pub fn get_server_os_input() -> Result { + let current_termios = termios::tcgetattr(0)?; let orig_termios = Arc::new(Mutex::new(current_termios)); - ServerOsInputOutput { + Ok(ServerOsInputOutput { orig_termios, receive_instructions_from_client: None, send_instructions_to_client: Arc::new(Mutex::new(None)), - } -} - -#[derive(Clone)] -pub struct ClientOsInputOutput { - orig_termios: Arc>, - send_instructions_to_server: Arc>>>, - receive_instructions_from_server: Arc>>>, -} - -/// The `ClientOsApi` trait represents an abstract interface to the features of an operating system that -/// Zellij client requires. -pub trait ClientOsApi: Send + Sync { - /// Returns the size of the terminal associated to file descriptor `fd`. - fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize; - /// Set the terminal associated to file descriptor `fd` to - /// [raw mode](https://en.wikipedia.org/wiki/Terminal_mode). - fn set_raw_mode(&mut self, fd: RawFd); - /// Set the terminal associated to file descriptor `fd` to - /// [cooked mode](https://en.wikipedia.org/wiki/Terminal_mode). - fn unset_raw_mode(&self, fd: RawFd); - /// Returns the writer that allows writing to standard output. - fn get_stdout_writer(&self) -> Box; - /// Returns the raw contents of standard input. - fn read_from_stdin(&self) -> Vec; - /// Returns a [`Box`] pointer to this [`ClientOsApi`] struct. - fn box_clone(&self) -> Box; - /// Sends a message to the server. - fn send_to_server(&self, msg: ClientToServerMsg); - /// Receives a message on client-side IPC channel - // This should be called from the client-side router thread only. - fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext); - fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box); - /// Establish a connection with the server socket. - fn connect_to_server(&self, path: &Path); -} - -impl ClientOsApi for ClientOsInputOutput { - fn get_terminal_size_using_fd(&self, fd: RawFd) -> PositionAndSize { - get_terminal_size_using_fd(fd) - } - fn set_raw_mode(&mut self, fd: RawFd) { - into_raw_mode(fd); - } - fn unset_raw_mode(&self, fd: RawFd) { - let orig_termios = self.orig_termios.lock().unwrap(); - unset_raw_mode(fd, orig_termios.clone()); - } - fn box_clone(&self) -> Box { - Box::new((*self).clone()) - } - fn read_from_stdin(&self) -> Vec { - let stdin = std::io::stdin(); - let mut stdin = stdin.lock(); - let buffer = stdin.fill_buf().unwrap(); - let length = buffer.len(); - let read_bytes = Vec::from(buffer); - stdin.consume(length); - read_bytes - } - fn get_stdout_writer(&self) -> Box { - let stdout = ::std::io::stdout(); - Box::new(stdout) - } - fn send_to_server(&self, msg: ClientToServerMsg) { - self.send_instructions_to_server - .lock() - .unwrap() - .as_mut() - .unwrap() - .send(msg); - } - fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext) { - self.receive_instructions_from_server - .lock() - .unwrap() - .as_mut() - .unwrap() - .recv() - } - fn handle_signals(&self, sigwinch_cb: Box, quit_cb: Box) { - let mut signals = Signals::new(&[SIGWINCH, SIGTERM, SIGINT, SIGQUIT, SIGHUP]).unwrap(); - for signal in signals.forever() { - match signal { - SIGWINCH => { - sigwinch_cb(); - } - SIGTERM | SIGINT | SIGQUIT | SIGHUP => { - quit_cb(); - break; - } - _ => unreachable!(), - } - } - } - fn connect_to_server(&self, path: &Path) { - let socket; - loop { - match LocalSocketStream::connect(path) { - Ok(sock) => { - socket = sock; - break; - } - Err(_) => { - std::thread::sleep(std::time::Duration::from_millis(50)); - } - } - } - let sender = IpcSenderWithContext::new(socket); - let receiver = sender.get_receiver(); - *self.send_instructions_to_server.lock().unwrap() = Some(sender); - *self.receive_instructions_from_server.lock().unwrap() = Some(receiver); - } -} - -impl Clone for Box { - fn clone(&self) -> Box { - self.box_clone() - } -} - -pub fn get_client_os_input() -> ClientOsInputOutput { - let current_termios = termios::tcgetattr(0).unwrap(); - let orig_termios = Arc::new(Mutex::new(current_termios)); - ClientOsInputOutput { - orig_termios, - send_instructions_to_server: Arc::new(Mutex::new(None)), - receive_instructions_from_server: Arc::new(Mutex::new(None)), - } + }) } diff --git a/src/client/panes/grid.rs b/zellij-server/src/panes/grid.rs similarity index 90% rename from src/client/panes/grid.rs rename to zellij-server/src/panes/grid.rs index e51b1ed5..d9cef5de 100644 --- a/src/client/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -2,6 +2,7 @@ use std::{ cmp::Ordering, collections::{BTreeSet, VecDeque}, fmt::{self, Debug, Formatter}, + str, }; use vte::{Params, Perform}; @@ -9,15 +10,34 @@ use vte::{Params, Perform}; const TABSTOP_WIDTH: usize = 8; // TODO: is this always right? const SCROLL_BACK: usize = 10_000; -use crate::utils::consts::VERSION; -use crate::utils::logging::debug_log_to_file; -use crate::utils::shared::version_number; +use zellij_tile::data::{Palette, PaletteColor}; +use zellij_utils::{consts::VERSION, logging::debug_log_to_file, shared::version_number}; use crate::panes::terminal_character::{ CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, }; +// this was copied verbatim from alacritty +fn parse_number(input: &[u8]) -> Option { + if input.is_empty() { + return None; + } + let mut num: u8 = 0; + for c in input { + let c = *c as char; + if let Some(digit) = c.to_digit(10) { + num = match num.checked_mul(10).and_then(|v| v.checked_add(digit as u8)) { + Some(v) => v, + None => return None, + } + } else { + return None; + } + } + Some(num) +} + fn get_top_non_canonical_rows(rows: &mut Vec) -> Vec { let mut index_of_last_non_canonical_row = None; for (i, row) in rows.iter().enumerate() { @@ -180,6 +200,7 @@ pub struct Grid { scroll_region: Option<(usize, usize)>, active_charset: CharsetIndex, preceding_char: Option, + colors: Palette, pub should_render: bool, pub cursor_key_mode: bool, // DECCKM - when set, cursor keys should send ANSI direction codes (eg. "OD") instead of the arrow keys (eg. "") pub erasure_mode: bool, // ERM @@ -205,7 +226,7 @@ impl Debug for Grid { } impl Grid { - pub fn new(rows: usize, columns: usize) -> Self { + pub fn new(rows: usize, columns: usize, colors: Palette) -> Self { Grid { lines_above: VecDeque::with_capacity(SCROLL_BACK), viewport: vec![Row::new().canonical()], @@ -226,6 +247,7 @@ impl Grid { clear_viewport_before_rendering: false, active_charset: Default::default(), pending_messages_to_pty: vec![], + colors, } } pub fn contains_widechar(&self) -> bool { @@ -1013,8 +1035,139 @@ impl Perform for Grid { // TBD } - fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) { - // TBD + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + let terminator = if bell_terminated { "\x07" } else { "\x1b\\" }; + + if params.is_empty() || params[0].is_empty() { + return; + } + + match params[0] { + // Set window title. + b"0" | b"2" => { + if params.len() >= 2 { + let _title = params[1..] + .iter() + .flat_map(|x| str::from_utf8(x)) + .collect::>() + .join(";") + .trim() + .to_owned(); + // TBD: do something with title? + } + } + + // Set color index. + b"4" => { + // TBD: set color index - currently unsupported + // + // this changes a terminal color index to something else + // meaning anything set to that index will be changed + // during rendering + } + + // Get/set Foreground, Background, Cursor colors. + b"10" | b"11" | b"12" => { + if params.len() >= 2 { + if let Some(mut dynamic_code) = parse_number(params[0]) { + for param in ¶ms[1..] { + // currently only getting the color sequence is supported, + // setting still isn't + if param == b"?" { + let color_response_message = match self.colors.bg { + PaletteColor::Rgb((r, g, b)) => { + format!( + "\u{1b}]{};rgb:{1:02x}{1:02x}/{2:02x}{2:02x}/{3:02x}{3:02x}{4}", + // dynamic_code, color.r, color.g, color.b, terminator + dynamic_code, r, g, b, terminator + ) + } + _ => { + format!( + "\u{1b}]{};rgb:{1:02x}{1:02x}/{2:02x}{2:02x}/{3:02x}{3:02x}{4}", + // dynamic_code, color.r, color.g, color.b, terminator + dynamic_code, 0, 0, 0, terminator + ) + } + }; + self.pending_messages_to_pty + .push(color_response_message.as_bytes().to_vec()); + } + dynamic_code += 1; + } + return; + } + } + } + + // Set cursor style. + b"50" => { + if params.len() >= 2 + && params[1].len() >= 13 + && params[1][0..12] == *b"CursorShape=" + { + let shape = match params[1][12] as char { + '0' => Some(CursorShape::Block), + '1' => Some(CursorShape::Beam), + '2' => Some(CursorShape::Underline), + _ => None, + }; + if let Some(cursor_shape) = shape { + self.cursor.change_shape(cursor_shape); + } + } + } + + // Set clipboard. + b"52" => { + if params.len() < 3 { + return; + } + + let _clipboard = params[1].get(0).unwrap_or(&b'c'); + match params[2] { + b"?" => { + // TBD: paste from own clipboard - currently unsupported + } + _base64 => { + // TBD: copy to own clipboard - currently unsupported + } + } + } + + // Reset color index. + b"104" => { + // Reset all color indexes when no parameters are given. + if params.len() == 1 { + // TBD - reset all color changes - currently unsupported + return; + } + + // Reset color indexes given as parameters. + for param in ¶ms[1..] { + if let Some(_index) = parse_number(param) { + // TBD - reset color index - currently unimplemented + } + } + } + + // Reset foreground color. + b"110" => { + // TBD - reset foreground color - currently unimplemented + } + + // Reset background color. + b"111" => { + // TBD - reset background color - currently unimplemented + } + + // Reset text cursor color. + b"112" => { + // TBD - reset text cursor color - currently unimplemented + } + + _ => {} + } } fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], _ignore: bool, c: char) { @@ -1347,7 +1500,7 @@ impl Perform for Grid { } } else { let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params)); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] result.unwrap(); } } @@ -1436,13 +1589,19 @@ impl Debug for Row { } } -impl Row { - pub fn new() -> Self { +impl Default for Row { + fn default() -> Self { Row { columns: vec![], is_canonical: false, } } +} + +impl Row { + pub fn new() -> Self { + Self::default() + } pub fn from_columns(columns: Vec) -> Self { Row { columns, @@ -1528,6 +1687,9 @@ impl Row { pub fn len(&self) -> usize { self.columns.len() } + pub fn is_empty(&self) -> bool { + self.columns.is_empty() + } pub fn delete_character(&mut self, x: usize) { if x < self.columns.len() { self.columns.remove(x); diff --git a/src/client/panes/mod.rs b/zellij-server/src/panes/mod.rs similarity index 82% rename from src/client/panes/mod.rs rename to zellij-server/src/panes/mod.rs index 4e7d6e80..187b364d 100644 --- a/src/client/panes/mod.rs +++ b/zellij-server/src/panes/mod.rs @@ -4,6 +4,6 @@ mod terminal_character; mod terminal_pane; pub use grid::*; -pub use plugin_pane::*; +pub(crate) use plugin_pane::*; pub use terminal_character::*; pub use terminal_pane::*; diff --git a/src/client/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs similarity index 98% rename from src/client/panes/plugin_pane.rs rename to zellij-server/src/panes/plugin_pane.rs index dde3cd9b..5549a388 100644 --- a/src/client/panes/plugin_pane.rs +++ b/zellij-server/src/panes/plugin_pane.rs @@ -2,13 +2,13 @@ use std::sync::mpsc::channel; use std::time::Instant; use std::unimplemented; -use crate::common::thread_bus::SenderWithContext; -use crate::panes::{PaneId, PositionAndSize}; +use crate::panes::PaneId; use crate::pty::VteBytes; use crate::tab::Pane; use crate::wasm_vm::PluginInstruction; +use zellij_utils::{channels::SenderWithContext, pane_size::PositionAndSize}; -pub struct PluginPane { +pub(crate) struct PluginPane { pub pid: u32, pub should_render: bool, pub selectable: bool, diff --git a/src/client/panes/terminal_character.rs b/zellij-server/src/panes/terminal_character.rs similarity index 99% rename from src/client/panes/terminal_character.rs rename to zellij-server/src/panes/terminal_character.rs index d2340e2e..c55569f0 100644 --- a/src/client/panes/terminal_character.rs +++ b/zellij-server/src/panes/terminal_character.rs @@ -1,10 +1,10 @@ use unicode_width::UnicodeWidthChar; -use crate::utils::logging::debug_log_to_file; use std::convert::TryFrom; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::{Index, IndexMut}; use vte::ParamsIter; +use zellij_utils::logging::debug_log_to_file; pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter { character: ' ', @@ -110,9 +110,9 @@ pub struct CharacterStyles { pub italic: Option, } -impl CharacterStyles { - pub fn new() -> Self { - CharacterStyles { +impl Default for CharacterStyles { + fn default() -> Self { + Self { foreground: None, background: None, strike: None, @@ -126,6 +126,12 @@ impl CharacterStyles { italic: None, } } +} + +impl CharacterStyles { + pub fn new() -> Self { + Self::default() + } pub fn foreground(mut self, foreground_code: Option) -> Self { self.foreground = foreground_code; self diff --git a/src/client/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs similarity index 92% rename from src/client/panes/terminal_pane.rs rename to zellij-server/src/panes/terminal_pane.rs index 5c4f55c8..eaeb0026 100644 --- a/src/client/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -1,45 +1,24 @@ use std::fmt::Debug; use std::os::unix::io::RawFd; use std::time::Instant; +use zellij_tile::data::Palette; +use zellij_utils::pane_size::PositionAndSize; -use nix::pty::Winsize; -use serde::{Deserialize, Serialize}; - -use crate::panes::grid::Grid; -use crate::panes::terminal_character::{ - CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, +use crate::panes::{ + grid::Grid, + terminal_character::{ + CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER, + }, }; use crate::pty::VteBytes; use crate::tab::Pane; -#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Debug)] pub enum PaneId { Terminal(RawFd), Plugin(u32), // FIXME: Drop the trait object, make this a wrapper for the struct? } -/// Contains the position and size of a [`Pane`], or more generally of any terminal, measured -/// in character rows and columns. -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] -pub struct PositionAndSize { - pub x: usize, - pub y: usize, - pub rows: usize, - pub columns: usize, - pub max_rows: Option, - pub max_columns: Option, -} - -impl From for PositionAndSize { - fn from(winsize: Winsize) -> PositionAndSize { - PositionAndSize { - columns: winsize.ws_col as usize, - rows: winsize.ws_row as usize, - ..Default::default() - } - } -} - pub struct TerminalPane { pub grid: Grid, pub pid: RawFd, @@ -49,6 +28,7 @@ pub struct TerminalPane { pub max_height: Option, pub max_width: Option, pub active_at: Instant, + pub colors: Palette, vte_parser: vte::Parser, } @@ -307,8 +287,8 @@ impl Pane for TerminalPane { } impl TerminalPane { - pub fn new(pid: RawFd, position_and_size: PositionAndSize) -> TerminalPane { - let grid = Grid::new(position_and_size.rows, position_and_size.columns); + pub fn new(pid: RawFd, position_and_size: PositionAndSize, palette: Palette) -> TerminalPane { + let grid = Grid::new(position_and_size.rows, position_and_size.columns, palette); TerminalPane { pid, grid, @@ -319,6 +299,7 @@ impl TerminalPane { max_width: None, vte_parser: vte::Parser::new(), active_at: Instant::now(), + colors: palette, } } pub fn get_x(&self) -> usize { @@ -354,7 +335,7 @@ impl TerminalPane { pub fn read_buffer_as_lines(&self) -> Vec> { self.grid.as_character_lines() } - #[cfg(test)] + #[cfg(any(feature = "test", test))] pub fn cursor_coordinates(&self) -> Option<(usize, usize)> { // (x, y) self.grid.cursor_coordinates() diff --git a/src/client/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs similarity index 82% rename from src/client/panes/unit/grid_tests.rs rename to zellij-server/src/panes/unit/grid_tests.rs index 8517a975..7612a05d 100644 --- a/src/client/panes/unit/grid_tests.rs +++ b/zellij-server/src/panes/unit/grid_tests.rs @@ -1,9 +1,10 @@ use super::super::Grid; use ::insta::assert_snapshot; +use zellij_tile::data::Palette; fn read_fixture(fixture_name: &str) -> Vec { let mut path_to_file = std::path::PathBuf::new(); - path_to_file.push("src"); + path_to_file.push("../src"); path_to_file.push("tests"); path_to_file.push("fixtures"); path_to_file.push(fixture_name); @@ -15,7 +16,7 @@ fn read_fixture(fixture_name: &str) -> Vec { #[test] fn vttest1_0() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest1-0"; let content = read_fixture(fixture_name); for byte in content { @@ -27,7 +28,7 @@ fn vttest1_0() { #[test] fn vttest1_1() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest1-1"; let content = read_fixture(fixture_name); for byte in content { @@ -39,7 +40,7 @@ fn vttest1_1() { #[test] fn vttest1_2() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest1-2"; let content = read_fixture(fixture_name); for byte in content { @@ -51,7 +52,7 @@ fn vttest1_2() { #[test] fn vttest1_3() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest1-3"; let content = read_fixture(fixture_name); for byte in content { @@ -63,7 +64,7 @@ fn vttest1_3() { #[test] fn vttest1_4() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest1-4"; let content = read_fixture(fixture_name); for byte in content { @@ -75,7 +76,7 @@ fn vttest1_4() { #[test] fn vttest1_5() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest1-5"; let content = read_fixture(fixture_name); for byte in content { @@ -87,7 +88,7 @@ fn vttest1_5() { #[test] fn vttest2_0() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-0"; let content = read_fixture(fixture_name); for byte in content { @@ -99,7 +100,7 @@ fn vttest2_0() { #[test] fn vttest2_1() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-1"; let content = read_fixture(fixture_name); for byte in content { @@ -111,7 +112,7 @@ fn vttest2_1() { #[test] fn vttest2_2() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-2"; let content = read_fixture(fixture_name); for byte in content { @@ -123,7 +124,7 @@ fn vttest2_2() { #[test] fn vttest2_3() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-3"; let content = read_fixture(fixture_name); for byte in content { @@ -135,7 +136,7 @@ fn vttest2_3() { #[test] fn vttest2_4() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-4"; let content = read_fixture(fixture_name); for byte in content { @@ -147,7 +148,7 @@ fn vttest2_4() { #[test] fn vttest2_5() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-5"; let content = read_fixture(fixture_name); for byte in content { @@ -159,7 +160,7 @@ fn vttest2_5() { #[test] fn vttest2_6() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-6"; let content = read_fixture(fixture_name); for byte in content { @@ -171,7 +172,7 @@ fn vttest2_6() { #[test] fn vttest2_7() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-7"; let content = read_fixture(fixture_name); for byte in content { @@ -183,7 +184,7 @@ fn vttest2_7() { #[test] fn vttest2_8() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-8"; let content = read_fixture(fixture_name); for byte in content { @@ -195,7 +196,7 @@ fn vttest2_8() { #[test] fn vttest2_9() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-9"; let content = read_fixture(fixture_name); for byte in content { @@ -207,7 +208,7 @@ fn vttest2_9() { #[test] fn vttest2_10() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-10"; let content = read_fixture(fixture_name); for byte in content { @@ -219,7 +220,7 @@ fn vttest2_10() { #[test] fn vttest2_11() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-11"; let content = read_fixture(fixture_name); for byte in content { @@ -231,7 +232,7 @@ fn vttest2_11() { #[test] fn vttest2_12() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-12"; let content = read_fixture(fixture_name); for byte in content { @@ -243,7 +244,7 @@ fn vttest2_12() { #[test] fn vttest2_13() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-13"; let content = read_fixture(fixture_name); for byte in content { @@ -255,7 +256,7 @@ fn vttest2_13() { #[test] fn vttest2_14() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest2-14"; let content = read_fixture(fixture_name); for byte in content { @@ -267,7 +268,7 @@ fn vttest2_14() { #[test] fn vttest3_0() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(41, 110); + let mut grid = Grid::new(41, 110, Palette::default()); let fixture_name = "vttest3-0"; let content = read_fixture(fixture_name); for byte in content { @@ -279,7 +280,7 @@ fn vttest3_0() { #[test] fn vttest8_0() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "vttest8-0"; let content = read_fixture(fixture_name); for byte in content { @@ -291,7 +292,7 @@ fn vttest8_0() { #[test] fn vttest8_1() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "vttest8-1"; let content = read_fixture(fixture_name); for byte in content { @@ -303,7 +304,7 @@ fn vttest8_1() { #[test] fn vttest8_2() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "vttest8-2"; let content = read_fixture(fixture_name); for byte in content { @@ -315,7 +316,7 @@ fn vttest8_2() { #[test] fn vttest8_3() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "vttest8-3"; let content = read_fixture(fixture_name); for byte in content { @@ -327,7 +328,7 @@ fn vttest8_3() { #[test] fn vttest8_4() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "vttest8-4"; let content = read_fixture(fixture_name); for byte in content { @@ -339,7 +340,7 @@ fn vttest8_4() { #[test] fn vttest8_5() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "vttest8-5"; let content = read_fixture(fixture_name); for byte in content { @@ -351,7 +352,7 @@ fn vttest8_5() { #[test] fn csi_b() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "csi-b"; let content = read_fixture(fixture_name); for byte in content { @@ -363,7 +364,7 @@ fn csi_b() { #[test] fn csi_capital_i() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "csi-capital-i"; let content = read_fixture(fixture_name); for byte in content { @@ -375,7 +376,7 @@ fn csi_capital_i() { #[test] fn csi_capital_z() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "csi-capital-z"; let content = read_fixture(fixture_name); for byte in content { @@ -387,7 +388,7 @@ fn csi_capital_z() { #[test] fn terminal_reports() { let mut vte_parser = vte::Parser::new(); - let mut grid = Grid::new(51, 97); + let mut grid = Grid::new(51, 97, Palette::default()); let fixture_name = "terminal_reports"; let content = read_fixture(fixture_name); for byte in content { diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_b.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap similarity index 57% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_b.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap index 1d0c34e5..2be051c5 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_b.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_i.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap similarity index 67% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_i.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap index 11f7b8f8..44026d04 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_i.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_z.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap similarity index 61% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_z.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap index 04f492b8..2411b25f 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__csi_capital_z.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__terminal_reports.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap similarity index 79% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__terminal_reports.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap index b2dca273..d289d93f 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__terminal_reports.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid . pending_messages_to_pty)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_0.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_0.snap index 8641098c..f469f2ef 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_1.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_1.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_1.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_1.snap index 09663484..6a43da94 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_1.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_1.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_2.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_2.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_2.snap index 05d80b1d..5250338a 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_2.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_2.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_3.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_3.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_3.snap index 64c3e7b9..f33ce414 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_3.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_3.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_4.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_4.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_4.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_4.snap index dcb417ae..411bcec5 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_4.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_4.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_5.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_5.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_5.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_5.snap index d044691c..5d16f7d6 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest1_5.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest1_5.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/grid.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_0.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_0.snap index f5bd11a5..a8250e29 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_1.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_1.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_1.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_1.snap index 148b8732..8dbcd8fe 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_1.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_1.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_10.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_10.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_10.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_10.snap index 7cbb8545..8fddefa0 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_10.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_10.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_11.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_11.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_11.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_11.snap index 1201290b..df92663d 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_11.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_11.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_12.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_12.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_12.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_12.snap index fc15da63..6373f0d5 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_12.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_12.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_13.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_13.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_13.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_13.snap index ee8e30fb..d250858f 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_13.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_13.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_14.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_14.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_14.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_14.snap index 2bdf1956..7d86b997 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_14.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_14.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_2.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_2.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_2.snap index 91a9a2e6..d751b7b5 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_2.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_2.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_3.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_3.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_3.snap index c3881efb..0ee924ac 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_3.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_3.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_4.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_4.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_4.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_4.snap index 089f3d7d..7c819279 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_4.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_4.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_5.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_5.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_5.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_5.snap index 6cf729c1..3d14e042 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_5.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_5.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_6.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_6.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_6.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_6.snap index 3c6a1c77..20a8aecd 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_6.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_6.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_7.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_7.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_7.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_7.snap index 0c4c5cac..4a980ffc 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_7.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_7.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_8.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_8.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_8.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_8.snap index 9e9ac891..413f7c8e 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_8.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_8.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_9.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_9.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_9.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_9.snap index 852203c8..6759d124 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest2_9.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest2_9.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest3_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap similarity index 98% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest3_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap index 6902cf25..0f9c5ce6 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest3_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_0.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_0.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_0.snap index 18cdd01b..86e447a9 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_0.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_1.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_1.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_1.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_1.snap index 7618e82b..4381306b 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_1.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_1.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_2.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_2.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_2.snap index 0873ec23..b65ed724 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_2.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_2.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_3.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_3.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_3.snap index 049f5083..d18554a8 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_3.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_3.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_4.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_4.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_4.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_4.snap index e7eb978f..c45da961 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_4.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_4.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_5.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_5.snap similarity index 99% rename from src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_5.snap rename to zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_5.snap index 9b54cbc8..00b8b310 100644 --- a/src/client/panes/unit/snapshots/zellij__client__panes__grid__grid_tests__vttest8_5.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest8_5.snap @@ -1,5 +1,5 @@ --- -source: src/client/panes/./unit/grid_tests.rs +source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" --- diff --git a/src/common/pty.rs b/zellij-server/src/pty.rs similarity index 89% rename from src/common/pty.rs rename to zellij-server/src/pty.rs index 5f5442b5..373b5f0b 100644 --- a/src/common/pty.rs +++ b/zellij-server/src/pty.rs @@ -7,15 +7,19 @@ use std::path::PathBuf; use std::pin::*; use std::time::{Duration, Instant}; -use crate::client::panes::PaneId; -use crate::common::errors::{get_current_ctx, ContextType}; -use crate::common::screen::ScreenInstruction; -use crate::common::thread_bus::{Bus, ThreadSenders}; -use crate::layout::Layout; -use crate::os_input_output::ServerOsApi; -use crate::server::ServerInstruction; -use crate::utils::logging::debug_to_file; -use crate::wasm_vm::PluginInstruction; +use crate::{ + os_input_output::ServerOsApi, + panes::PaneId, + screen::ScreenInstruction, + thread_bus::{Bus, ThreadSenders}, + ui::layout::Layout, + wasm_vm::PluginInstruction, + ServerInstruction, +}; +use zellij_utils::{ + errors::{get_current_ctx, ContextType, PtyContext}, + logging::debug_to_file, +}; pub struct ReadFromPid { pid: RawFd, @@ -67,7 +71,7 @@ pub type VteBytes = Vec; /// Instructions related to PTYs (pseudoterminals). #[derive(Clone, Debug)] -pub enum PtyInstruction { +pub(crate) enum PtyInstruction { SpawnTerminal(Option), SpawnTerminalVertically(Option), SpawnTerminalHorizontally(Option), @@ -77,14 +81,28 @@ pub enum PtyInstruction { Exit, } -pub struct Pty { +impl From<&PtyInstruction> for PtyContext { + fn from(pty_instruction: &PtyInstruction) -> Self { + match *pty_instruction { + PtyInstruction::SpawnTerminal(_) => PtyContext::SpawnTerminal, + PtyInstruction::SpawnTerminalVertically(_) => PtyContext::SpawnTerminalVertically, + PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally, + PtyInstruction::ClosePane(_) => PtyContext::ClosePane, + PtyInstruction::CloseTab(_) => PtyContext::CloseTab, + PtyInstruction::NewTab => PtyContext::NewTab, + PtyInstruction::Exit => PtyContext::Exit, + } + } +} + +pub(crate) struct Pty { pub bus: Bus, pub id_to_child_pid: HashMap, debug_to_file: bool, task_handles: HashMap>, } -pub fn pty_thread_main(mut pty: Pty, maybe_layout: Option) { +pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option) { loop { let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Pty((&event).into())); @@ -196,7 +214,7 @@ fn stream_terminal_bytes( } } senders.send_to_screen(ScreenInstruction::Render).unwrap(); - #[cfg(not(test))] + #[cfg(not(any(feature = "test", test)))] // this is a little hacky, and is because the tests end the file as soon as // we read everything, rather than hanging until there is new data // a better solution would be to fix the test fakes, but this will do for now diff --git a/src/server/route.rs b/zellij-server/src/route.rs similarity index 90% rename from src/server/route.rs rename to zellij-server/src/route.rs index c435a0e6..e8ff3376 100644 --- a/src/server/route.rs +++ b/zellij-server/src/route.rs @@ -2,15 +2,18 @@ use std::sync::{Arc, RwLock}; use zellij_tile::data::Event; -use crate::common::input::actions::{Action, Direction}; -use crate::common::input::handler::get_mode_info; -use crate::common::ipc::ClientToServerMsg; -use crate::common::os_input_output::ServerOsApi; -use crate::common::pty::PtyInstruction; -use crate::common::screen::ScreenInstruction; -use crate::common::thread_bus::SenderWithContext; -use crate::common::wasm_vm::PluginInstruction; -use crate::server::{ServerInstruction, SessionMetaData}; +use crate::{ + os_input_output::ServerOsApi, pty::PtyInstruction, screen::ScreenInstruction, + wasm_vm::PluginInstruction, ServerInstruction, SessionMetaData, +}; +use zellij_utils::{ + channels::SenderWithContext, + input::{ + actions::{Action, Direction}, + get_mode_info, + }, + ipc::ClientToServerMsg, +}; fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn ServerOsApi) { match action { @@ -26,6 +29,9 @@ fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn Server } Action::SwitchToMode(mode) => { let palette = os_input.load_palette(); + // TODO: use the palette from the client and remove it from the server os api + // this is left here as a stop gap measure until we shift some code around + // to allow for this session .senders .send_to_plugin(PluginInstruction::Update( @@ -181,7 +187,7 @@ fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn Server } } -pub fn route_thread_main( +pub(crate) fn route_thread_main( sessions: Arc>>, mut os_input: Box, to_server: SenderWithContext, @@ -196,7 +202,9 @@ pub fn route_thread_main( break; } ClientToServerMsg::Action(action) => { - route_action(action, rlocked_sessions.as_ref().unwrap(), &*os_input); + if let Some(rlocked_sessions) = rlocked_sessions.as_ref() { + route_action(action, rlocked_sessions, &*os_input); + } } ClientToServerMsg::TerminalResize(new_size) => { rlocked_sessions diff --git a/src/common/screen.rs b/zellij-server/src/screen.rs similarity index 82% rename from src/common/screen.rs rename to zellij-server/src/screen.rs index d2030243..0500d296 100644 --- a/src/common/screen.rs +++ b/zellij-server/src/screen.rs @@ -4,22 +4,26 @@ use std::collections::BTreeMap; use std::os::unix::io::RawFd; use std::str; -use crate::common::input::options::Options; -use crate::common::pty::{PtyInstruction, VteBytes}; -use crate::common::thread_bus::Bus; -use crate::errors::ContextType; -use crate::layout::Layout; -use crate::panes::PaneId; -use crate::panes::PositionAndSize; -use crate::server::ServerInstruction; -use crate::tab::Tab; -use crate::wasm_vm::PluginInstruction; - +use crate::{ + panes::PaneId, + pty::{PtyInstruction, VteBytes}, + tab::Tab, + thread_bus::Bus, + ui::layout::Layout, + wasm_vm::PluginInstruction, + ServerInstruction, +}; use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PluginCapabilities, TabInfo}; +use zellij_utils::{ + errors::{ContextType, ScreenContext}, + input::options::Options, + ipc::ClientAttributes, + pane_size::PositionAndSize, +}; /// Instructions that can be sent to the [`Screen`]. #[derive(Debug, Clone)] -pub enum ScreenInstruction { +pub(crate) enum ScreenInstruction { PtyBytes(RawFd, VteBytes), Render, NewPane(PaneId), @@ -63,9 +67,61 @@ pub enum ScreenInstruction { ChangeMode(ModeInfo), } +impl From<&ScreenInstruction> for ScreenContext { + fn from(screen_instruction: &ScreenInstruction) -> Self { + match *screen_instruction { + ScreenInstruction::PtyBytes(..) => ScreenContext::HandlePtyBytes, + ScreenInstruction::Render => ScreenContext::Render, + ScreenInstruction::NewPane(_) => ScreenContext::NewPane, + ScreenInstruction::HorizontalSplit(_) => ScreenContext::HorizontalSplit, + ScreenInstruction::VerticalSplit(_) => ScreenContext::VerticalSplit, + ScreenInstruction::WriteCharacter(_) => ScreenContext::WriteCharacter, + ScreenInstruction::ResizeLeft => ScreenContext::ResizeLeft, + ScreenInstruction::ResizeRight => ScreenContext::ResizeRight, + ScreenInstruction::ResizeDown => ScreenContext::ResizeDown, + ScreenInstruction::ResizeUp => ScreenContext::ResizeUp, + ScreenInstruction::SwitchFocus => ScreenContext::SwitchFocus, + ScreenInstruction::FocusNextPane => ScreenContext::FocusNextPane, + ScreenInstruction::FocusPreviousPane => ScreenContext::FocusPreviousPane, + ScreenInstruction::MoveFocusLeft => ScreenContext::MoveFocusLeft, + ScreenInstruction::MoveFocusLeftOrPreviousTab => { + ScreenContext::MoveFocusLeftOrPreviousTab + } + ScreenInstruction::MoveFocusDown => ScreenContext::MoveFocusDown, + ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp, + ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight, + ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab, + ScreenInstruction::Exit => ScreenContext::Exit, + ScreenInstruction::ScrollUp => ScreenContext::ScrollUp, + ScreenInstruction::ScrollDown => ScreenContext::ScrollDown, + ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp, + ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown, + ScreenInstruction::ClearScroll => ScreenContext::ClearScroll, + ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane, + ScreenInstruction::ToggleActiveTerminalFullscreen => { + ScreenContext::ToggleActiveTerminalFullscreen + } + ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable, + ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders, + ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight, + ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane, + ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout, + ScreenInstruction::NewTab(_) => ScreenContext::NewTab, + ScreenInstruction::SwitchTabNext => ScreenContext::SwitchTabNext, + ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev, + ScreenInstruction::CloseTab => ScreenContext::CloseTab, + ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab, + ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName, + ScreenInstruction::TerminalResize(_) => ScreenContext::TerminalResize, + ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode, + ScreenInstruction::ToggleActiveSyncTab => ScreenContext::ToggleActiveSyncTab, + } + } +} + /// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes). /// It only directly controls which tab is active, delegating the rest to the individual `Tab`. -pub struct Screen { +pub(crate) struct Screen { /// A Bus for sending and receiving messages with the other threads. pub bus: Bus, /// An optional maximal amount of panes allowed per [`Tab`] in this [`Screen`] instance. @@ -73,7 +129,7 @@ pub struct Screen { /// A map between this [`Screen`]'s tabs and their ID/key. tabs: BTreeMap, /// The full size of this [`Screen`]. - full_screen_ws: PositionAndSize, + position_and_size: PositionAndSize, /// The index of this [`Screen`]'s active [`Tab`]. active_tab_index: Option, mode_info: ModeInfo, @@ -85,21 +141,20 @@ impl Screen { /// Creates and returns a new [`Screen`]. pub fn new( bus: Bus, - full_screen_ws: &PositionAndSize, + client_attributes: &ClientAttributes, max_panes: Option, mode_info: ModeInfo, input_mode: InputMode, - colors: Palette, ) -> Self { Screen { bus, max_panes, - full_screen_ws: *full_screen_ws, + position_and_size: client_attributes.position_and_size, + colors: client_attributes.palette, active_tab_index: None, tabs: BTreeMap::new(), mode_info, input_mode, - colors, } } @@ -112,7 +167,7 @@ impl Screen { tab_index, position, String::new(), - &self.full_screen_ws, + &self.position_and_size, self.bus.os_input.as_ref().unwrap().clone(), self.bus.senders.clone(), self.max_panes, @@ -219,7 +274,7 @@ impl Screen { } pub fn resize_to_screen(&mut self, new_screen_size: PositionAndSize) { - self.full_screen_ws = new_screen_size; + self.position_and_size = new_screen_size; for (_, tab) in self.tabs.iter_mut() { tab.resize_whole_tab(new_screen_size); } @@ -268,7 +323,7 @@ impl Screen { tab_index, position, String::new(), - &self.full_screen_ws, + &self.position_and_size, self.bus.os_input.as_ref().unwrap().clone(), self.bus.senders.clone(), self.max_panes, @@ -328,28 +383,26 @@ impl Screen { // The box is here in order to make the // NewClient enum smaller #[allow(clippy::boxed_local)] -pub fn screen_thread_main( +pub(crate) fn screen_thread_main( bus: Bus, max_panes: Option, - full_screen_ws: PositionAndSize, + client_attributes: ClientAttributes, config_options: Box, ) { - let colors = bus.os_input.as_ref().unwrap().load_palette(); let capabilities = config_options.simplified_ui; let mut screen = Screen::new( bus, - &full_screen_ws, + &client_attributes, max_panes, ModeInfo { - palette: colors, + palette: client_attributes.palette, capabilities: PluginCapabilities { arrow_fonts: capabilities, }, ..ModeInfo::default() }, InputMode::Normal, - colors, ); loop { let (event, mut err_ctx) = screen diff --git a/src/client/tab.rs b/zellij-server/src/tab.rs similarity index 99% rename from src/client/tab.rs rename to zellij-server/src/tab.rs index 29a41530..69de7e86 100644 --- a/src/client/tab.rs +++ b/zellij-server/src/tab.rs @@ -1,17 +1,15 @@ //! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size, //! as well as how they should be resized -use crate::client::pane_resizer::PaneResizer; -use crate::common::input::handler::parse_keys; -use crate::common::thread_bus::ThreadSenders; -use crate::layout::Layout; -use crate::os_input_output::ServerOsApi; -use crate::panes::{PaneId, PositionAndSize, TerminalPane}; -use crate::pty::{PtyInstruction, VteBytes}; -use crate::server::ServerInstruction; -use crate::utils::shared::adjust_to_size; -use crate::wasm_vm::PluginInstruction; -use crate::{boundaries::Boundaries, panes::PluginPane}; +use crate::{ + os_input_output::ServerOsApi, + panes::{PaneId, PluginPane, TerminalPane}, + pty::{PtyInstruction, VteBytes}, + thread_bus::ThreadSenders, + ui::{boundaries::Boundaries, layout::Layout, pane_resizer::PaneResizer}, + wasm_vm::PluginInstruction, + ServerInstruction, +}; use serde::{Deserialize, Serialize}; use std::os::unix::io::RawFd; use std::sync::mpsc::channel; @@ -21,6 +19,7 @@ use std::{ collections::{BTreeMap, HashSet}, }; use zellij_tile::data::{Event, InputMode, ModeInfo, Palette}; +use zellij_utils::{input::parse_keys, pane_size::PositionAndSize, shared::adjust_to_size}; const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this @@ -59,7 +58,7 @@ fn split_horizontally_with_gap(rect: &PositionAndSize) -> (PositionAndSize, Posi (first_rect, second_rect) } -pub struct Tab { +pub(crate) struct Tab { pub index: usize, pub position: usize, pub name: String, @@ -79,7 +78,7 @@ pub struct Tab { } #[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct TabData { +pub(crate) struct TabData { /* subset of fields to publish to plugins */ pub position: usize, pub name: String, @@ -242,7 +241,7 @@ impl Tab { colors: Palette, ) -> Self { let panes = if let Some(PaneId::Terminal(pid)) = pane_id { - let new_terminal = TerminalPane::new(pid, *full_screen_ws); + let new_terminal = TerminalPane::new(pid, *full_screen_ws, colors); os_api.set_terminal_size_using_fd( new_terminal.pid, new_terminal.columns() as u16, @@ -344,7 +343,7 @@ impl Tab { } else { // there are still panes left to fill, use the pids we received in this method let pid = new_pids.next().unwrap(); // if this crashes it means we got less pids than there are panes in this layout - let new_terminal = TerminalPane::new(*pid, *position_and_size); + let new_terminal = TerminalPane::new(*pid, *position_and_size, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, new_terminal.columns() as u16, @@ -372,7 +371,7 @@ impl Tab { } if !self.has_panes() { if let PaneId::Terminal(term_pid) = pid { - let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws); + let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, new_terminal.columns() as u16, @@ -422,7 +421,7 @@ impl Tab { { if let PaneId::Terminal(term_pid) = pid { let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws); - let new_terminal = TerminalPane::new(term_pid, bottom_winsize); + let new_terminal = TerminalPane::new(term_pid, bottom_winsize, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, bottom_winsize.columns as u16, @@ -442,7 +441,7 @@ impl Tab { } else if terminal_to_split.columns() > terminal_to_split.min_width() * 2 { if let PaneId::Terminal(term_pid) = pid { let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws); - let new_terminal = TerminalPane::new(term_pid, right_winsize); + let new_terminal = TerminalPane::new(term_pid, right_winsize, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, right_winsize.columns as u16, @@ -470,7 +469,7 @@ impl Tab { } if !self.has_panes() { if let PaneId::Terminal(term_pid) = pid { - let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws); + let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, new_terminal.columns() as u16, @@ -500,7 +499,7 @@ impl Tab { active_pane.change_pos_and_size(&top_winsize); - let new_terminal = TerminalPane::new(term_pid, bottom_winsize); + let new_terminal = TerminalPane::new(term_pid, bottom_winsize, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, bottom_winsize.columns as u16, @@ -527,7 +526,7 @@ impl Tab { } if !self.has_panes() { if let PaneId::Terminal(term_pid) = pid { - let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws); + let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, new_terminal.columns() as u16, @@ -557,7 +556,7 @@ impl Tab { active_pane.change_pos_and_size(&left_winsize); - let new_terminal = TerminalPane::new(term_pid, right_winsize); + let new_terminal = TerminalPane::new(term_pid, right_winsize, self.colors); self.os_api.set_terminal_size_using_fd( new_terminal.pid, right_winsize.columns as u16, diff --git a/zellij-server/src/thread_bus.rs b/zellij-server/src/thread_bus.rs new file mode 100644 index 00000000..afc1d875 --- /dev/null +++ b/zellij-server/src/thread_bus.rs @@ -0,0 +1,80 @@ +//! Definitions and helpers for sending and receiving messages between threads. + +use crate::{ + os_input_output::ServerOsApi, pty::PtyInstruction, screen::ScreenInstruction, + wasm_vm::PluginInstruction, ServerInstruction, +}; +use std::sync::mpsc; +use zellij_utils::{channels::SenderWithContext, errors::ErrorContext}; + +/// A container for senders to the different threads in zellij on the server side +#[derive(Clone)] +pub(crate) struct ThreadSenders { + pub to_screen: Option>, + pub to_pty: Option>, + pub to_plugin: Option>, + pub to_server: Option>, +} + +impl ThreadSenders { + pub fn send_to_screen( + &self, + instruction: ScreenInstruction, + ) -> Result<(), mpsc::SendError<(ScreenInstruction, ErrorContext)>> { + self.to_screen.as_ref().unwrap().send(instruction) + } + + pub fn send_to_pty( + &self, + instruction: PtyInstruction, + ) -> Result<(), mpsc::SendError<(PtyInstruction, ErrorContext)>> { + self.to_pty.as_ref().unwrap().send(instruction) + } + + pub fn send_to_plugin( + &self, + instruction: PluginInstruction, + ) -> Result<(), mpsc::SendError<(PluginInstruction, ErrorContext)>> { + self.to_plugin.as_ref().unwrap().send(instruction) + } + + pub fn send_to_server( + &self, + instruction: ServerInstruction, + ) -> Result<(), mpsc::SendError<(ServerInstruction, ErrorContext)>> { + self.to_server.as_ref().unwrap().send(instruction) + } +} + +/// A container for a receiver, OS input and the senders to a given thread +pub(crate) struct Bus { + pub receiver: mpsc::Receiver<(T, ErrorContext)>, + pub senders: ThreadSenders, + pub os_input: Option>, +} + +impl Bus { + pub fn new( + receiver: mpsc::Receiver<(T, ErrorContext)>, + to_screen: Option<&SenderWithContext>, + to_pty: Option<&SenderWithContext>, + to_plugin: Option<&SenderWithContext>, + to_server: Option<&SenderWithContext>, + os_input: Option>, + ) -> Self { + Bus { + receiver, + senders: ThreadSenders { + to_screen: to_screen.cloned(), + to_pty: to_pty.cloned(), + to_plugin: to_plugin.cloned(), + to_server: to_server.cloned(), + }, + os_input: os_input.clone(), + } + } + + pub fn recv(&self) -> Result<(T, ErrorContext), mpsc::RecvError> { + self.receiver.recv() + } +} diff --git a/src/client/boundaries.rs b/zellij-server/src/ui/boundaries.rs similarity index 99% rename from src/client/boundaries.rs rename to zellij-server/src/ui/boundaries.rs index 86fb37fc..984b1376 100644 --- a/src/client/boundaries.rs +++ b/zellij-server/src/ui/boundaries.rs @@ -1,8 +1,8 @@ use crate::tab::Pane; -use crate::utils::shared::colors; use ansi_term::Colour::{Fixed, RGB}; use std::collections::HashMap; use zellij_tile::data::{InputMode, Palette, PaletteColor}; +use zellij_utils::shared::colors; use std::fmt::{Display, Error, Formatter}; pub mod boundary_type { @@ -19,10 +19,10 @@ pub mod boundary_type { pub const CROSS: &str = "┼"; } -pub type BoundaryType = &'static str; // easy way to refer to boundary_type above +pub(crate) type BoundaryType = &'static str; // easy way to refer to boundary_type above #[derive(Clone, Copy, Debug)] -pub struct BoundarySymbol { +pub(crate) struct BoundarySymbol { boundary_type: BoundaryType, invisible: bool, color: Option, @@ -392,7 +392,7 @@ fn combine_symbols( } #[derive(PartialEq, Eq, Hash, Debug)] -pub struct Coordinates { +pub(crate) struct Coordinates { x: usize, y: usize, } @@ -403,7 +403,7 @@ impl Coordinates { } } -pub trait Rect { +pub(crate) trait Rect { fn x(&self) -> usize; fn y(&self) -> usize; fn rows(&self) -> usize; diff --git a/src/client/layout.rs b/zellij-server/src/ui/layout.rs similarity index 98% rename from src/client/layout.rs rename to zellij-server/src/ui/layout.rs index 592481dc..3965b478 100644 --- a/src/client/layout.rs +++ b/zellij-server/src/ui/layout.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; use std::{fs::File, io::prelude::*}; -use crate::panes::PositionAndSize; +use zellij_utils::pane_size::PositionAndSize; fn split_space_to_parts_vertically( space_to_split: &PositionAndSize, @@ -167,19 +167,19 @@ fn split_space( } #[derive(Debug, Serialize, Deserialize, Clone)] -pub enum Direction { +pub(crate) enum Direction { Horizontal, Vertical, } #[derive(Debug, Serialize, Deserialize, Clone, Copy)] -pub enum SplitSize { +pub(crate) enum SplitSize { Percent(u8), // 1 to 100 Fixed(u16), // An absolute number of columns or rows } #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Layout { +pub(crate) struct Layout { pub direction: Direction, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub parts: Vec, diff --git a/zellij-server/src/ui/mod.rs b/zellij-server/src/ui/mod.rs new file mode 100644 index 00000000..1e4c85fd --- /dev/null +++ b/zellij-server/src/ui/mod.rs @@ -0,0 +1,3 @@ +pub mod boundaries; +pub mod layout; +pub mod pane_resizer; diff --git a/src/client/pane_resizer.rs b/zellij-server/src/ui/pane_resizer.rs similarity index 99% rename from src/client/pane_resizer.rs rename to zellij-server/src/ui/pane_resizer.rs index 73678499..b2001945 100644 --- a/src/client/pane_resizer.rs +++ b/zellij-server/src/ui/pane_resizer.rs @@ -1,12 +1,11 @@ -use crate::os_input_output::ServerOsApi; -use crate::panes::{PaneId, PositionAndSize}; -use crate::tab::Pane; +use crate::{os_input_output::ServerOsApi, panes::PaneId, tab::Pane}; use std::{ cmp::Ordering, collections::{BTreeMap, HashSet}, }; +use zellij_utils::pane_size::PositionAndSize; -pub struct PaneResizer<'a> { +pub(crate) struct PaneResizer<'a> { panes: &'a mut BTreeMap>, os_api: &'a mut Box, } diff --git a/src/common/wasm_vm.rs b/zellij-server/src/wasm_vm.rs similarity index 91% rename from src/common/wasm_vm.rs rename to zellij-server/src/wasm_vm.rs index 51eb4ed8..65f5358a 100644 --- a/src/common/wasm_vm.rs +++ b/zellij-server/src/wasm_vm.rs @@ -15,14 +15,16 @@ use wasmer::{ use wasmer_wasi::{Pipe, WasiEnv, WasiState}; use zellij_tile::data::{Event, EventType, PluginIds}; -use crate::common::errors::ContextType; -use crate::common::pty::PtyInstruction; -use crate::common::screen::ScreenInstruction; -use crate::common::thread_bus::{Bus, ThreadSenders}; -use crate::common::PaneId; +use crate::{ + panes::PaneId, + pty::PtyInstruction, + screen::ScreenInstruction, + thread_bus::{Bus, ThreadSenders}, +}; +use zellij_utils::errors::{ContextType, PluginContext}; #[derive(Clone, Debug)] -pub enum PluginInstruction { +pub(crate) enum PluginInstruction { Load(Sender, PathBuf), Update(Option, Event), // Focused plugin / broadcast, event data Render(Sender, u32, usize, usize), // String buffer, plugin id, rows, cols @@ -30,8 +32,20 @@ pub enum PluginInstruction { Exit, } +impl From<&PluginInstruction> for PluginContext { + fn from(plugin_instruction: &PluginInstruction) -> Self { + match *plugin_instruction { + PluginInstruction::Load(..) => PluginContext::Load, + PluginInstruction::Update(..) => PluginContext::Update, + PluginInstruction::Render(..) => PluginContext::Render, + PluginInstruction::Unload(_) => PluginContext::Unload, + PluginInstruction::Exit => PluginContext::Exit, + } + } +} + #[derive(WasmerEnv, Clone)] -pub struct PluginEnv { +pub(crate) struct PluginEnv { pub plugin_id: u32, pub senders: ThreadSenders, pub wasi_env: WasiEnv, @@ -39,7 +53,7 @@ pub struct PluginEnv { } // Thread main -------------------------------------------------------------------------------------------------------- -pub fn wasm_thread_main(bus: Bus, store: Store, data_dir: PathBuf) { +pub(crate) fn wasm_thread_main(bus: Bus, store: Store, data_dir: PathBuf) { let mut plugin_id = 0; let mut plugin_map = HashMap::new(); loop { @@ -126,7 +140,7 @@ pub fn wasm_thread_main(bus: Bus, store: Store, data_dir: Pat // Plugin API --------------------------------------------------------------------------------------------------------- -pub fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObject { +pub(crate) fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObject { macro_rules! zellij_export { ($($host_function:ident),+ $(,)?) => { imports! { diff --git a/zellij-utils/Cargo.toml b/zellij-utils/Cargo.toml new file mode 100644 index 00000000..d33ac659 --- /dev/null +++ b/zellij-utils/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "zellij-utils" +version = "0.12.0" +authors = ["Kunal Mohan "] +edition = "2018" +description = "A utility library for Zellij client and server" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +backtrace = "0.3.55" +bincode = "1.3.1" +interprocess = "1.1.1" +structopt = "0.3" +serde = { version = "1.0", features = ["derive"] } +zellij-tile = { path = "../zellij-tile/", version = "0.12.0" } +names = "0.11.0" +colors-transform = "0.2.5" +strip-ansi-escapes = "0.1.0" +strum = "0.20.0" +serde_yaml = "0.8" +nix = "0.19.1" +lazy_static = "1.4.0" +directories-next = "2.0" +termion = "1.5.0" + +[dependencies.async-std] +version = "1.3.0" +features = ["unstable"] + +[dev-dependencies] +tempfile = "3.2.0" + +[features] +test = [] diff --git a/zellij-utils/src/channels.rs b/zellij-utils/src/channels.rs new file mode 100644 index 00000000..8a97fa7d --- /dev/null +++ b/zellij-utils/src/channels.rs @@ -0,0 +1,65 @@ +//! Definitions and helpers for sending and receiving messages between threads. + +use async_std::task_local; +use std::cell::RefCell; +use std::sync::mpsc; + +use crate::errors::{get_current_ctx, ErrorContext}; + +/// An [MPSC](mpsc) asynchronous channel with added error context. +pub type ChannelWithContext = ( + mpsc::Sender<(T, ErrorContext)>, + mpsc::Receiver<(T, ErrorContext)>, +); +/// An [MPSC](mpsc) synchronous channel with added error context. +pub type SyncChannelWithContext = ( + mpsc::SyncSender<(T, ErrorContext)>, + mpsc::Receiver<(T, ErrorContext)>, +); + +/// Wrappers around the two standard [MPSC](mpsc) sender types, [`mpsc::Sender`] and [`mpsc::SyncSender`], with an additional [`ErrorContext`]. +#[derive(Clone)] +pub enum SenderType { + /// A wrapper around an [`mpsc::Sender`], adding an [`ErrorContext`]. + Sender(mpsc::Sender<(T, ErrorContext)>), + /// A wrapper around an [`mpsc::SyncSender`], adding an [`ErrorContext`]. + SyncSender(mpsc::SyncSender<(T, ErrorContext)>), +} + +/// Sends messages on an [MPSC](std::sync::mpsc) channel, along with an [`ErrorContext`], +/// synchronously or asynchronously depending on the underlying [`SenderType`]. +#[derive(Clone)] +pub struct SenderWithContext { + sender: SenderType, +} + +impl SenderWithContext { + pub fn new(sender: SenderType) -> Self { + Self { sender } + } + + /// Sends an event, along with the current [`ErrorContext`], on this + /// [`SenderWithContext`]'s channel. + pub fn send(&self, event: T) -> Result<(), mpsc::SendError<(T, ErrorContext)>> { + let err_ctx = get_current_ctx(); + match self.sender { + SenderType::Sender(ref s) => s.send((event, err_ctx)), + SenderType::SyncSender(ref s) => s.send((event, err_ctx)), + } + } +} + +unsafe impl Send for SenderWithContext {} +unsafe impl Sync for SenderWithContext {} + +thread_local!( + /// A key to some thread local storage (TLS) that holds a representation of the thread's call + /// stack in the form of an [`ErrorContext`]. + pub static OPENCALLS: RefCell = RefCell::default() +); + +task_local! { + /// A key to some task local storage that holds a representation of the task's call + /// stack in the form of an [`ErrorContext`]. + pub static ASYNCOPENCALLS: RefCell = RefCell::default() +} diff --git a/src/cli.rs b/zellij-utils/src/cli.rs similarity index 90% rename from src/cli.rs rename to zellij-utils/src/cli.rs index b8a61344..56e93edb 100644 --- a/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -1,6 +1,6 @@ -use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; -use crate::common::input::options::Options; -use crate::common::setup::Setup; +use crate::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; +use crate::input::options::Options; +use crate::setup::Setup; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use structopt::StructOpt; diff --git a/src/common/utils/consts.rs b/zellij-utils/src/consts.rs similarity index 97% rename from src/common/utils/consts.rs rename to zellij-utils/src/consts.rs index 42843eb8..799e2913 100644 --- a/src/common/utils/consts.rs +++ b/zellij-utils/src/consts.rs @@ -1,6 +1,6 @@ //! Zellij program-wide constants. -use crate::os_input_output::set_permissions; +use crate::shared::set_permissions; use directories_next::ProjectDirs; use lazy_static::lazy_static; use nix::unistd::Uid; diff --git a/src/common/errors.rs b/zellij-utils/src/errors.rs similarity index 55% rename from src/common/errors.rs rename to zellij-utils/src/errors.rs index 262dfd6b..94a894c4 100644 --- a/src/common/errors.rs +++ b/zellij-utils/src/errors.rs @@ -1,43 +1,20 @@ //! Error context system based on a thread-local representation of the call stack, itself based on //! the instructions that are sent between threads. +use crate::channels::{SenderWithContext, ASYNCOPENCALLS, OPENCALLS}; use serde::{Deserialize, Serialize}; - use std::fmt::{Display, Error, Formatter}; - -use crate::client::ClientInstruction; -use crate::common::thread_bus::{ASYNCOPENCALLS, OPENCALLS}; -use crate::pty::PtyInstruction; -use crate::screen::ScreenInstruction; -use crate::server::ServerInstruction; +use std::panic::PanicInfo; /// The maximum amount of calls an [`ErrorContext`] will keep track /// of in its stack representation. This is a per-thread maximum. const MAX_THREAD_CALL_STACK: usize = 6; -#[cfg(not(test))] -use super::thread_bus::SenderWithContext; -#[cfg(not(test))] -use std::panic::PanicInfo; - pub trait ErrorInstruction { fn error(err: String) -> Self; } -impl ErrorInstruction for ClientInstruction { - fn error(err: String) -> Self { - ClientInstruction::Error(err) - } -} - -impl ErrorInstruction for ServerInstruction { - fn error(err: String) -> Self { - ServerInstruction::Error(err) - } -} - /// Custom panic handler/hook. Prints the [`ErrorContext`]. -#[cfg(not(test))] pub fn handle_panic(info: &PanicInfo<'_>, sender: &SenderWithContext) where T: ErrorInstruction + Clone, @@ -243,59 +220,6 @@ pub enum ScreenContext { ChangeMode, } -// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!! -impl From<&ScreenInstruction> for ScreenContext { - fn from(screen_instruction: &ScreenInstruction) -> Self { - match *screen_instruction { - ScreenInstruction::PtyBytes(..) => ScreenContext::HandlePtyBytes, - ScreenInstruction::Render => ScreenContext::Render, - ScreenInstruction::NewPane(_) => ScreenContext::NewPane, - ScreenInstruction::HorizontalSplit(_) => ScreenContext::HorizontalSplit, - ScreenInstruction::VerticalSplit(_) => ScreenContext::VerticalSplit, - ScreenInstruction::WriteCharacter(_) => ScreenContext::WriteCharacter, - ScreenInstruction::ResizeLeft => ScreenContext::ResizeLeft, - ScreenInstruction::ResizeRight => ScreenContext::ResizeRight, - ScreenInstruction::ResizeDown => ScreenContext::ResizeDown, - ScreenInstruction::ResizeUp => ScreenContext::ResizeUp, - ScreenInstruction::SwitchFocus => ScreenContext::SwitchFocus, - ScreenInstruction::FocusNextPane => ScreenContext::FocusNextPane, - ScreenInstruction::FocusPreviousPane => ScreenContext::FocusPreviousPane, - ScreenInstruction::MoveFocusLeft => ScreenContext::MoveFocusLeft, - ScreenInstruction::MoveFocusLeftOrPreviousTab => { - ScreenContext::MoveFocusLeftOrPreviousTab - } - ScreenInstruction::MoveFocusDown => ScreenContext::MoveFocusDown, - ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp, - ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight, - ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab, - ScreenInstruction::Exit => ScreenContext::Exit, - ScreenInstruction::ScrollUp => ScreenContext::ScrollUp, - ScreenInstruction::ScrollDown => ScreenContext::ScrollDown, - ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp, - ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown, - ScreenInstruction::ClearScroll => ScreenContext::ClearScroll, - ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane, - ScreenInstruction::ToggleActiveTerminalFullscreen => { - ScreenContext::ToggleActiveTerminalFullscreen - } - ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable, - ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders, - ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight, - ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane, - ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout, - ScreenInstruction::NewTab(_) => ScreenContext::NewTab, - ScreenInstruction::SwitchTabNext => ScreenContext::SwitchTabNext, - ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev, - ScreenInstruction::CloseTab => ScreenContext::CloseTab, - ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab, - ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName, - ScreenInstruction::TerminalResize(_) => ScreenContext::TerminalResize, - ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode, - ScreenInstruction::ToggleActiveSyncTab => ScreenContext::ToggleActiveSyncTab, - } - } -} - /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum PtyContext { @@ -308,24 +232,6 @@ pub enum PtyContext { Exit, } -impl From<&PtyInstruction> for PtyContext { - fn from(pty_instruction: &PtyInstruction) -> Self { - match *pty_instruction { - PtyInstruction::SpawnTerminal(_) => PtyContext::SpawnTerminal, - PtyInstruction::SpawnTerminalVertically(_) => PtyContext::SpawnTerminalVertically, - PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally, - PtyInstruction::ClosePane(_) => PtyContext::ClosePane, - PtyInstruction::CloseTab(_) => PtyContext::CloseTab, - PtyInstruction::NewTab => PtyContext::NewTab, - PtyInstruction::Exit => PtyContext::Exit, - } - } -} - -// FIXME: This whole pattern *needs* a macro eventually, it's soul-crushing to write - -use crate::wasm_vm::PluginInstruction; - /// Stack call representations corresponding to the different types of [`PluginInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum PluginContext { @@ -336,18 +242,6 @@ pub enum PluginContext { Exit, } -impl From<&PluginInstruction> for PluginContext { - fn from(plugin_instruction: &PluginInstruction) -> Self { - match *plugin_instruction { - PluginInstruction::Load(..) => PluginContext::Load, - PluginInstruction::Update(..) => PluginContext::Update, - PluginInstruction::Render(..) => PluginContext::Render, - PluginInstruction::Unload(_) => PluginContext::Unload, - PluginInstruction::Exit => PluginContext::Exit, - } - } -} - /// Stack call representations corresponding to the different types of [`ClientInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum ClientContext { @@ -358,18 +252,6 @@ pub enum ClientContext { ServerError, } -impl From<&ClientInstruction> for ClientContext { - fn from(client_instruction: &ClientInstruction) -> Self { - match *client_instruction { - ClientInstruction::Exit => ClientContext::Exit, - ClientInstruction::Error(_) => ClientContext::Error, - ClientInstruction::ServerError(_) => ClientContext::ServerError, - ClientInstruction::Render(_) => ClientContext::Render, - ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread, - } - } -} - /// Stack call representations corresponding to the different types of [`ServerInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum ServerContext { @@ -379,15 +261,3 @@ pub enum ServerContext { ClientExit, Error, } - -impl From<&ServerInstruction> for ServerContext { - fn from(server_instruction: &ServerInstruction) -> Self { - match *server_instruction { - ServerInstruction::NewClient(..) => ServerContext::NewClient, - ServerInstruction::Render(_) => ServerContext::Render, - ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread, - ServerInstruction::ClientExit => ServerContext::ClientExit, - ServerInstruction::Error(_) => ServerContext::Error, - } - } -} diff --git a/src/common/input/actions.rs b/zellij-utils/src/input/actions.rs similarity index 100% rename from src/common/input/actions.rs rename to zellij-utils/src/input/actions.rs diff --git a/src/common/input/config.rs b/zellij-utils/src/input/config.rs similarity index 98% rename from src/common/input/config.rs rename to zellij-utils/src/input/config.rs index 3dffe71c..a0341689 100644 --- a/src/common/input/config.rs +++ b/zellij-utils/src/input/config.rs @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf}; use super::keybinds::{Keybinds, KeybindsFromYaml}; use super::options::Options; use crate::cli::{CliArgs, ConfigCli}; -use crate::common::setup; +use crate::setup; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; @@ -177,7 +177,7 @@ mod config_test { #[test] fn try_from_cli_args_with_option_clean() { - use crate::common::setup::Setup; + use crate::setup::Setup; let mut opts = CliArgs::default(); opts.option = Some(ConfigCli::Setup(Setup { clean: true, diff --git a/src/common/input/keybinds.rs b/zellij-utils/src/input/keybinds.rs similarity index 100% rename from src/common/input/keybinds.rs rename to zellij-utils/src/input/keybinds.rs diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs new file mode 100644 index 00000000..2747205b --- /dev/null +++ b/zellij-utils/src/input/mod.rs @@ -0,0 +1,87 @@ +//! The way terminal input is handled. + +pub mod actions; +pub mod config; +pub mod keybinds; +pub mod options; + +use termion::input::TermRead; +use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities}; + +/// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds +/// (as pairs of [`String`]s). +// TODO this should probably be automatically generated in some way +pub fn get_mode_info( + mode: InputMode, + palette: Palette, + capabilities: PluginCapabilities, +) -> ModeInfo { + let mut keybinds: Vec<(String, String)> = vec![]; + match mode { + InputMode::Normal | InputMode::Locked => {} + InputMode::Resize => { + keybinds.push(("←↓↑→".to_string(), "Resize".to_string())); + } + InputMode::Pane => { + keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); + keybinds.push(("p".to_string(), "Next".to_string())); + keybinds.push(("n".to_string(), "New".to_string())); + keybinds.push(("d".to_string(), "Down split".to_string())); + keybinds.push(("r".to_string(), "Right split".to_string())); + keybinds.push(("x".to_string(), "Close".to_string())); + keybinds.push(("f".to_string(), "Fullscreen".to_string())); + } + InputMode::Tab => { + keybinds.push(("←↓↑→".to_string(), "Move focus".to_string())); + keybinds.push(("n".to_string(), "New".to_string())); + keybinds.push(("x".to_string(), "Close".to_string())); + keybinds.push(("r".to_string(), "Rename".to_string())); + keybinds.push(("s".to_string(), "Sync".to_string())); + } + InputMode::Scroll => { + keybinds.push(("↓↑".to_string(), "Scroll".to_string())); + keybinds.push(("PgUp/PgDn".to_string(), "Scroll Page".to_string())); + } + InputMode::RenameTab => { + keybinds.push(("Enter".to_string(), "when done".to_string())); + } + } + ModeInfo { + mode, + keybinds, + palette, + capabilities, + } +} + +pub fn parse_keys(input_bytes: &[u8]) -> Vec { + input_bytes.keys().flatten().map(cast_termion_key).collect() +} + +// FIXME: This is an absolutely cursed function that should be destroyed as soon +// as an alternative that doesn't touch zellij-tile can be developed... +pub fn cast_termion_key(event: termion::event::Key) -> Key { + match event { + termion::event::Key::Backspace => Key::Backspace, + termion::event::Key::Left => Key::Left, + termion::event::Key::Right => Key::Right, + termion::event::Key::Up => Key::Up, + termion::event::Key::Down => Key::Down, + termion::event::Key::Home => Key::Home, + termion::event::Key::End => Key::End, + termion::event::Key::PageUp => Key::PageUp, + termion::event::Key::PageDown => Key::PageDown, + termion::event::Key::BackTab => Key::BackTab, + termion::event::Key::Delete => Key::Delete, + termion::event::Key::Insert => Key::Insert, + termion::event::Key::F(n) => Key::F(n), + termion::event::Key::Char(c) => Key::Char(c), + termion::event::Key::Alt(c) => Key::Alt(c), + termion::event::Key::Ctrl(c) => Key::Ctrl(c), + termion::event::Key::Null => Key::Null, + termion::event::Key::Esc => Key::Esc, + _ => { + unimplemented!("Encountered an unknown key!") + } + } +} diff --git a/src/common/input/options.rs b/zellij-utils/src/input/options.rs similarity index 100% rename from src/common/input/options.rs rename to zellij-utils/src/input/options.rs diff --git a/src/common/input/unit/keybinds_test.rs b/zellij-utils/src/input/unit/keybinds_test.rs similarity index 100% rename from src/common/input/unit/keybinds_test.rs rename to zellij-utils/src/input/unit/keybinds_test.rs diff --git a/src/common/ipc.rs b/zellij-utils/src/ipc.rs similarity index 92% rename from src/common/ipc.rs rename to zellij-utils/src/ipc.rs index af6dd859..725bf16b 100644 --- a/src/common/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -1,11 +1,11 @@ //! IPC stuff for starting to split things into a client and server model. use crate::cli::CliArgs; -use crate::common::{ +use crate::pane_size::PositionAndSize; +use crate::{ errors::{get_current_ctx, ErrorContext}, input::{actions::Action, options::Options}, }; -use crate::panes::PositionAndSize; use interprocess::local_socket::LocalSocketStream; use nix::unistd::dup; use serde::{Deserialize, Serialize}; @@ -13,6 +13,8 @@ use std::io::{self, Write}; use std::marker::PhantomData; use std::os::unix::io::{AsRawFd, FromRawFd}; +use zellij_tile::data::Palette; + type SessionId = u64; #[derive(PartialEq, Eq, Serialize, Deserialize, Hash)] @@ -32,7 +34,14 @@ pub enum ClientType { Writer, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ClientAttributes { + pub position_and_size: PositionAndSize, + pub palette: Palette, +} + // Types of messages sent from the client to the server +#[allow(clippy::large_enum_variant)] #[derive(Serialize, Deserialize, Debug, Clone)] pub enum ClientToServerMsg { /*// List which sessions are available @@ -47,7 +56,7 @@ pub enum ClientToServerMsg { DisconnectFromSession,*/ ClientExit, TerminalResize(PositionAndSize), - NewClient(PositionAndSize, Box, Box), + NewClient(ClientAttributes, Box, Box), Action(Action), } diff --git a/zellij-utils/src/lib.rs b/zellij-utils/src/lib.rs new file mode 100644 index 00000000..35f27244 --- /dev/null +++ b/zellij-utils/src/lib.rs @@ -0,0 +1,10 @@ +pub mod channels; +pub mod cli; +pub mod consts; +pub mod errors; +pub mod input; +pub mod ipc; +pub mod logging; +pub mod pane_size; +pub mod setup; +pub mod shared; diff --git a/src/common/utils/logging.rs b/zellij-utils/src/logging.rs similarity index 94% rename from src/common/utils/logging.rs rename to zellij-utils/src/logging.rs index 0dd382d6..d2c57612 100644 --- a/src/common/utils/logging.rs +++ b/zellij-utils/src/logging.rs @@ -7,8 +7,8 @@ use std::{ path::{Path, PathBuf}, }; -use crate::os_input_output::set_permissions; -use crate::utils::consts::{ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE}; +use crate::consts::{ZELLIJ_TMP_LOG_DIR, ZELLIJ_TMP_LOG_FILE}; +use crate::shared::set_permissions; pub fn atomic_create_file(file_name: &Path) -> io::Result<()> { let _ = fs::OpenOptions::new() diff --git a/zellij-utils/src/pane_size.rs b/zellij-utils/src/pane_size.rs new file mode 100644 index 00000000..2744c43f --- /dev/null +++ b/zellij-utils/src/pane_size.rs @@ -0,0 +1,24 @@ +use nix::pty::Winsize; +use serde::{Deserialize, Serialize}; + +/// Contains the position and size of a [`Pane`], or more generally of any terminal, measured +/// in character rows and columns. +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] +pub struct PositionAndSize { + pub x: usize, + pub y: usize, + pub rows: usize, + pub columns: usize, + pub max_rows: Option, + pub max_columns: Option, +} + +impl From for PositionAndSize { + fn from(winsize: Winsize) -> PositionAndSize { + PositionAndSize { + columns: winsize.ws_col as usize, + rows: winsize.ws_row as usize, + ..Default::default() + } + } +} diff --git a/src/common/setup.rs b/zellij-utils/src/setup.rs similarity index 93% rename from src/common/setup.rs rename to zellij-utils/src/setup.rs index 2e076776..ef51b2e5 100644 --- a/src/common/setup.rs +++ b/zellij-utils/src/setup.rs @@ -1,8 +1,8 @@ use crate::cli::CliArgs; -use crate::common::utils::consts::{ +use crate::consts::{ FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, ZELLIJ_PROJ_DIR, }; -use crate::os_input_output::set_permissions; +use crate::shared::set_permissions; use directories_next::BaseDirs; use serde::{Deserialize, Serialize}; use std::io::Write; @@ -32,13 +32,13 @@ pub mod install { pub fn populate_data_dir(data_dir: &Path) { // First run installation of default plugins & layouts let mut assets = asset_map! { - "assets/layouts/default.yaml" => "layouts/default.yaml", - "assets/layouts/strider.yaml" => "layouts/strider.yaml", + "../assets/layouts/default.yaml" => "layouts/default.yaml", + "../assets/layouts/strider.yaml" => "layouts/strider.yaml", }; assets.extend(asset_map! { - "assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm", - "assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm", - "assets/plugins/strider.wasm" => "plugins/strider.wasm", + "../assets/plugins/status-bar.wasm" => "plugins/status-bar.wasm", + "../assets/plugins/tab-bar.wasm" => "plugins/tab-bar.wasm", + "../assets/plugins/strider.wasm" => "plugins/strider.wasm", }); assets.insert("VERSION", VERSION.as_bytes().to_vec()); @@ -57,7 +57,7 @@ pub mod install { } } -#[cfg(not(test))] +#[cfg(not(any(feature = "test", test)))] /// Goes through a predefined list and checks for an already /// existing config directory, returns the first match pub fn find_default_config_dir() -> Option { @@ -68,7 +68,7 @@ pub fn find_default_config_dir() -> Option { .flatten() } -#[cfg(test)] +#[cfg(any(feature = "test", test))] pub fn find_default_config_dir() -> Option { None } @@ -119,7 +119,7 @@ pub fn dump_asset(asset: &[u8]) -> std::io::Result<()> { pub const DEFAULT_CONFIG: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/", - "assets/config/default.yaml" + "../assets/config/default.yaml" )); pub fn dump_default_config() -> std::io::Result<()> { @@ -192,7 +192,7 @@ impl Setup { } } if let Some(config_file) = config_file { - use crate::common::input::config::Config; + use crate::input::config::Config; message.push_str(&format!("[CONFIG FILE]: {:?}\n", config_file)); match Config::new(&config_file) { Ok(_) => message.push_str(&"[CONFIG FILE]: Well defined.\n"), diff --git a/src/common/utils/shared.rs b/zellij-utils/src/shared.rs similarity index 91% rename from src/common/utils/shared.rs rename to zellij-utils/src/shared.rs index 26a2f90a..bc8b6771 100644 --- a/src/common/utils/shared.rs +++ b/zellij-utils/src/shared.rs @@ -5,8 +5,19 @@ use std::{iter, str::from_utf8}; use strip_ansi_escapes::strip; use colors_transform::{Color, Rgb}; +use std::os::unix::fs::PermissionsExt; +use std::path::Path; +use std::{fs, io}; use zellij_tile::data::{Palette, PaletteColor, PaletteSource, Theme}; +const UNIX_PERMISSIONS: u32 = 0o700; + +pub fn set_permissions(path: &Path) -> io::Result<()> { + let mut permissions = fs::metadata(path)?.permissions(); + permissions.set_mode(UNIX_PERMISSIONS); + fs::set_permissions(path, permissions) +} + fn ansi_len(s: &str) -> usize { from_utf8(&strip(s.as_bytes()).unwrap()) .unwrap()