Merge branch 'main' of https://github.com/zellij-org/zellij into config-file
This commit is contained in:
commit
84488a35aa
41 changed files with 799 additions and 861 deletions
122
Cargo.lock
generated
122
Cargo.lock
generated
|
|
@ -11,9 +11,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bedc89c5c7b5550ffb9372eb5c5ffc7f9f705cc3f4a128bd4669b9745f555093"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
|
|
@ -223,9 +223,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
|||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "0.19.4"
|
||||
version = "0.19.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81"
|
||||
checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium",
|
||||
|
|
@ -536,9 +536,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
|||
|
||||
[[package]]
|
||||
name = "enumset"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c70e3089d60da62772627697a83dd166615072eebe1a52ac05f16bdbd0165dc3"
|
||||
checksum = "fbd795df6708a599abf1ee10eacc72efd052b7a5f70fdf0715e4d5151a6db9c3"
|
||||
dependencies = [
|
||||
"enumset_derive",
|
||||
]
|
||||
|
|
@ -807,9 +807,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.1"
|
||||
version = "1.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
|
||||
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
|
@ -818,9 +818,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.6.3"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd354a2c8c8083d58414597a4ecada1984f9b82ea7e87eeabddc869eaf120992"
|
||||
checksum = "e1b6cf41e31a7e7b78055b548826da45c7dc74e6a13a3fa6b897a17a01322f26"
|
||||
dependencies = [
|
||||
"console",
|
||||
"lazy_static",
|
||||
|
|
@ -842,16 +842,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "interprocess"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98969eda6bf33b8532e8a7b8f157afc43556188741fa0df8c92b8780f8654e52"
|
||||
checksum = "1c58ec7fbda1df9a93f587b780659db3c99f61f4be27f9c82c9b37684ffd0366"
|
||||
dependencies = [
|
||||
"blocking",
|
||||
"cfg-if 1.0.0",
|
||||
"futures",
|
||||
"intmap",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spinning",
|
||||
"thiserror",
|
||||
"winapi",
|
||||
|
|
@ -893,9 +893,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.47"
|
||||
version = "0.3.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
|
||||
checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
|
@ -936,9 +936,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.86"
|
||||
version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
|
||||
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
|
@ -1093,9 +1093,9 @@ checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.7.0"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10acf907b94fc1b1a152d08ef97e7759650268cf986bf127f387e602b02c7e5a"
|
||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
|
|
@ -1105,9 +1105,9 @@ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
|||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.4"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827"
|
||||
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
|
@ -1269,12 +1269,6 @@ dependencies = [
|
|||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.5"
|
||||
|
|
@ -1290,7 +1284,7 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
|
||||
dependencies = [
|
||||
"redox_syscall 0.2.5",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1300,7 +1294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall 0.2.5",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1370,9 +1364,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.123"
|
||||
version = "1.0.124"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
|
||||
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
|
@ -1388,9 +1382,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.123"
|
||||
version = "1.0.124"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
|
||||
checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1399,9 +1393,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.63"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43535db9747a4ba938c0ce0a98cc631a46ebf943c9e1d604e091df6007620bf6"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
|
@ -1582,9 +1576,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.60"
|
||||
version = "1.0.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
||||
checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1621,7 +1615,7 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall 0.2.5",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
|
@ -1637,16 +1631,15 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion_temporary_zellij_fork"
|
||||
version = "1.6.0"
|
||||
name = "termion"
|
||||
version = "1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65175afb01727f72d690bc8b2a2ac411c0243ec43988b7bd96d428301197bed0"
|
||||
checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"numtoa",
|
||||
"redox_syscall 0.1.57",
|
||||
"redox_syscall",
|
||||
"redox_termios",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1890,9 +1883,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.70"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
|
||||
checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
|
|
@ -1900,9 +1893,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.70"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
|
||||
checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
|
|
@ -1915,9 +1908,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.20"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94"
|
||||
checksum = "8e67a5806118af01f0d9045915676b22aaebecf4178ae7021bc171dab0b897ab"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
|
|
@ -1927,9 +1920,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.70"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
|
||||
checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -1937,9 +1930,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.70"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
|
||||
checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1950,9 +1943,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.70"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
|
||||
checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1"
|
||||
|
||||
[[package]]
|
||||
name = "wasmer"
|
||||
|
|
@ -2156,27 +2149,27 @@ checksum = "87cc2fe6350834b4e528ba0901e7aa405d78b89dc1fa3145359eb4de0e323fcf"
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "34.0.0"
|
||||
version = "35.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3de71ea922e46a60d0bde4b27ebf24ab7c4991006fd5de23ce9c58e129b3ab3c"
|
||||
checksum = "db5ae96da18bb5926341516fd409b5a8ce4e4714da7f0a1063d3b20ac9f9a1e1"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.0.35"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "474403335b9a90b21120ab8131dd888f0a8d041c2d365ab960feddfe5a73c4b6"
|
||||
checksum = "0b0fa059022c5dabe129f02b429d67086400deb8277f89c975555dacc1dadbcc"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.47"
|
||||
version = "0.3.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
|
||||
checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -2251,6 +2244,7 @@ dependencies = [
|
|||
name = "zellij"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"async-std",
|
||||
"backtrace",
|
||||
"bincode",
|
||||
|
|
@ -2269,8 +2263,7 @@ dependencies = [
|
|||
"strip-ansi-escapes",
|
||||
"structopt",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"termion_temporary_zellij_fork",
|
||||
"termion",
|
||||
"termios",
|
||||
"toml",
|
||||
"unicode-truncate",
|
||||
|
|
@ -2279,6 +2272,7 @@ dependencies = [
|
|||
"walkdir",
|
||||
"wasmer",
|
||||
"wasmer-wasi",
|
||||
"zellij-tile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2287,4 +2281,6 @@ version = "0.5.0"
|
|||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ publish = []
|
|||
# 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"
|
||||
directories-next = "2.0"
|
||||
|
|
@ -26,18 +27,17 @@ serde_yaml = "0.8"
|
|||
signal-hook = "0.1.10"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
structopt = "0.3"
|
||||
# termion = { git = "https://gitlab.com/TheLostLambda/termion.git", version = "1.6.0", features = ["serde"] }
|
||||
termion = { package = "termion_temporary_zellij_fork" , version = "1.6.0", features = ["serde"]}
|
||||
termion = "1.5.0"
|
||||
termios = "0.3"
|
||||
unicode-truncate = "0.2.0"
|
||||
unicode-width = "0.1.8"
|
||||
vte = "0.8.0"
|
||||
strum = "0.20.0"
|
||||
strum_macros = "0.20.0"
|
||||
lazy_static = "1.4.0"
|
||||
wasmer = "1.0.0"
|
||||
wasmer-wasi = "1.0.0"
|
||||
interprocess = "1.0.1"
|
||||
zellij-tile = { path = "zellij-tile/", version = "0.5.0" }
|
||||
|
||||
[dependencies.async-std]
|
||||
version = "1.3.0"
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ parts:
|
|||
split_size:
|
||||
Fixed: 1
|
||||
plugin: tab-bar
|
||||
events:
|
||||
- Tab
|
||||
- direction: Vertical
|
||||
expansion_boundary: true
|
||||
- direction: Vertical
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
---
|
||||
direction: Horizontal
|
||||
parts:
|
||||
- direction: Vertical
|
||||
split_size:
|
||||
Fixed: 1
|
||||
plugin: tab-bar
|
||||
- direction: Vertical
|
||||
parts:
|
||||
- direction: Horizontal
|
||||
|
|
@ -11,5 +15,5 @@ parts:
|
|||
expansion_boundary: true
|
||||
- direction: Vertical
|
||||
split_size:
|
||||
Fixed: 1
|
||||
Fixed: 2
|
||||
plugin: status-bar
|
||||
|
|
|
|||
18
build-all.sh
18
build-all.sh
|
|
@ -1,29 +1,25 @@
|
|||
#!/bin/sh
|
||||
|
||||
total=6
|
||||
total=5
|
||||
|
||||
# This is temporary while https://github.com/rust-lang/cargo/issues/7004 is open
|
||||
|
||||
echo "Building zellij-tile (1/$total)..."
|
||||
cd zellij-tile
|
||||
echo "Building status-bar (1/$total)..."
|
||||
cd default-tiles/status-bar
|
||||
cargo build --release --target-dir ../../target
|
||||
|
||||
echo "Building status-bar (2/$total)..."
|
||||
cd ../default-tiles/status-bar
|
||||
cargo build --release --target-dir ../../target
|
||||
|
||||
echo "Building strider (3/$total)..."
|
||||
echo "Building strider (2/$total)..."
|
||||
cd ../strider
|
||||
cargo build --release --target-dir ../../target
|
||||
|
||||
echo "Building tab-bar (4/$total)..."
|
||||
echo "Building tab-bar (3/$total)..."
|
||||
cd ../tab-bar
|
||||
cargo build --release --target-dir ../../target
|
||||
|
||||
echo "Optimising WASM executables (5/$total)..."
|
||||
echo "Optimising WASM executables (4/$total)..."
|
||||
cd ../..
|
||||
wasm-opt -O target/wasm32-wasi/release/status-bar.wasm -o target/status-bar.wasm || cp target/wasm32-wasi/release/status-bar.wasm target/status-bar.wasm
|
||||
wasm-opt -O target/wasm32-wasi/release/strider.wasm -o target/strider.wasm || cp target/wasm32-wasi/release/strider.wasm target/strider.wasm
|
||||
wasm-opt -O target/wasm32-wasi/release/tab-bar.wasm -o target/tab-bar.wasm || cp target/wasm32-wasi/release/tab-bar.wasm target/tab-bar.wasm
|
||||
echo "Building zellij (6/$total)..."
|
||||
echo "Building zellij (5/$total)..."
|
||||
cargo build --target-dir target $@
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use ansi_term::{ANSIStrings, Style};
|
||||
use zellij_tile::*;
|
||||
use zellij_tile::prelude::*;
|
||||
|
||||
use crate::colors::{BLACK, BRIGHT_GRAY, GRAY, GREEN, RED, WHITE};
|
||||
use crate::{LinePart, ARROW_SEPARATOR};
|
||||
|
|
@ -70,19 +70,19 @@ fn unselected_mode_shortcut(letter: char, text: &str) -> LinePart {
|
|||
.fg(BLACK)
|
||||
.on(BRIGHT_GRAY)
|
||||
.bold()
|
||||
.paint(format!(" <"));
|
||||
.paint(" <");
|
||||
let char_shortcut = Style::new()
|
||||
.bold()
|
||||
.fg(RED)
|
||||
.on(BRIGHT_GRAY)
|
||||
.bold()
|
||||
.paint(format!("{}", letter));
|
||||
.paint(letter.to_string());
|
||||
let char_right_separator = Style::new()
|
||||
.bold()
|
||||
.fg(BLACK)
|
||||
.on(BRIGHT_GRAY)
|
||||
.bold()
|
||||
.paint(format!(">"));
|
||||
.paint(">");
|
||||
let styled_text = Style::new()
|
||||
.fg(BLACK)
|
||||
.on(BRIGHT_GRAY)
|
||||
|
|
@ -90,41 +90,29 @@ fn unselected_mode_shortcut(letter: char, text: &str) -> LinePart {
|
|||
.paint(format!("{} ", text));
|
||||
let suffix_separator = Style::new().fg(BRIGHT_GRAY).on(GRAY).paint(ARROW_SEPARATOR);
|
||||
LinePart {
|
||||
part: format!(
|
||||
"{}",
|
||||
ANSIStrings(&[
|
||||
prefix_separator,
|
||||
char_left_separator,
|
||||
char_shortcut,
|
||||
char_right_separator,
|
||||
styled_text,
|
||||
suffix_separator
|
||||
])
|
||||
),
|
||||
part: ANSIStrings(&[
|
||||
prefix_separator,
|
||||
char_left_separator,
|
||||
char_shortcut,
|
||||
char_right_separator,
|
||||
styled_text,
|
||||
suffix_separator,
|
||||
])
|
||||
.to_string(),
|
||||
len: text.chars().count() + 6, // 2 for the arrows, 3 for the char separators, 1 for the character
|
||||
}
|
||||
}
|
||||
|
||||
fn selected_mode_shortcut(letter: char, text: &str) -> LinePart {
|
||||
let prefix_separator = Style::new().fg(GRAY).on(GREEN).paint(ARROW_SEPARATOR);
|
||||
let char_left_separator = Style::new()
|
||||
.bold()
|
||||
.fg(BLACK)
|
||||
.on(GREEN)
|
||||
.bold()
|
||||
.paint(format!(" <"));
|
||||
let char_left_separator = Style::new().bold().fg(BLACK).on(GREEN).bold().paint(" <");
|
||||
let char_shortcut = Style::new()
|
||||
.bold()
|
||||
.fg(RED)
|
||||
.on(GREEN)
|
||||
.bold()
|
||||
.paint(format!("{}", letter));
|
||||
let char_right_separator = Style::new()
|
||||
.bold()
|
||||
.fg(BLACK)
|
||||
.on(GREEN)
|
||||
.bold()
|
||||
.paint(format!(">"));
|
||||
.paint(letter.to_string());
|
||||
let char_right_separator = Style::new().bold().fg(BLACK).on(GREEN).bold().paint(">");
|
||||
let styled_text = Style::new()
|
||||
.fg(BLACK)
|
||||
.on(GREEN)
|
||||
|
|
@ -132,17 +120,15 @@ fn selected_mode_shortcut(letter: char, text: &str) -> LinePart {
|
|||
.paint(format!("{} ", text));
|
||||
let suffix_separator = Style::new().fg(GREEN).on(GRAY).paint(ARROW_SEPARATOR);
|
||||
LinePart {
|
||||
part: format!(
|
||||
"{}",
|
||||
ANSIStrings(&[
|
||||
prefix_separator,
|
||||
char_left_separator,
|
||||
char_shortcut,
|
||||
char_right_separator,
|
||||
styled_text,
|
||||
suffix_separator
|
||||
])
|
||||
),
|
||||
part: ANSIStrings(&[
|
||||
prefix_separator,
|
||||
char_left_separator,
|
||||
char_shortcut,
|
||||
char_right_separator,
|
||||
styled_text,
|
||||
suffix_separator,
|
||||
])
|
||||
.to_string(),
|
||||
len: text.chars().count() + 6, // 2 for the arrows, 3 for the char separators, 1 for the character
|
||||
}
|
||||
}
|
||||
|
|
@ -173,10 +159,7 @@ fn selected_mode_shortcut_single_letter(letter: char) -> LinePart {
|
|||
.paint(char_shortcut_text);
|
||||
let suffix_separator = Style::new().fg(GREEN).on(GRAY).paint(ARROW_SEPARATOR);
|
||||
LinePart {
|
||||
part: format!(
|
||||
"{}",
|
||||
ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator])
|
||||
),
|
||||
part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(),
|
||||
len,
|
||||
}
|
||||
}
|
||||
|
|
@ -193,10 +176,7 @@ fn unselected_mode_shortcut_single_letter(letter: char) -> LinePart {
|
|||
.paint(char_shortcut_text);
|
||||
let suffix_separator = Style::new().fg(BRIGHT_GRAY).on(GRAY).paint(ARROW_SEPARATOR);
|
||||
LinePart {
|
||||
part: format!(
|
||||
"{}",
|
||||
ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator])
|
||||
),
|
||||
part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(),
|
||||
len,
|
||||
}
|
||||
}
|
||||
|
|
@ -225,12 +205,8 @@ fn shortened_ctrl_key(key: &CtrlKeyShortcut) -> LinePart {
|
|||
_ => shortened_text,
|
||||
};
|
||||
match key.mode {
|
||||
CtrlKeyMode::Unselected => {
|
||||
unselected_mode_shortcut(letter_shortcut, &format!("{}", shortened_text))
|
||||
}
|
||||
CtrlKeyMode::Selected => {
|
||||
selected_mode_shortcut(letter_shortcut, &format!("{}", shortened_text))
|
||||
}
|
||||
CtrlKeyMode::Unselected => unselected_mode_shortcut(letter_shortcut, &shortened_text),
|
||||
CtrlKeyMode::Selected => selected_mode_shortcut(letter_shortcut, &shortened_text),
|
||||
CtrlKeyMode::Disabled => {
|
||||
disabled_mode_shortcut(&format!(" <{}>{}", letter_shortcut, shortened_text))
|
||||
}
|
||||
|
|
@ -282,16 +258,16 @@ pub fn superkey() -> LinePart {
|
|||
let prefix_text = " Ctrl + ";
|
||||
let prefix = Style::new().fg(WHITE).on(GRAY).bold().paint(prefix_text);
|
||||
LinePart {
|
||||
part: format!("{}", prefix),
|
||||
part: prefix.to_string(),
|
||||
len: prefix_text.chars().count(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ctrl_keys(help: &Help, max_len: usize) -> LinePart {
|
||||
pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
|
||||
match &help.mode {
|
||||
InputMode::Locked => key_indicators(
|
||||
max_len,
|
||||
&vec![
|
||||
&[
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Lock),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Pane),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Tab),
|
||||
|
|
@ -302,7 +278,7 @@ pub fn ctrl_keys(help: &Help, max_len: usize) -> LinePart {
|
|||
),
|
||||
InputMode::Resize => key_indicators(
|
||||
max_len,
|
||||
&vec![
|
||||
&[
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
|
|
@ -313,7 +289,7 @@ pub fn ctrl_keys(help: &Help, max_len: usize) -> LinePart {
|
|||
),
|
||||
InputMode::Pane => key_indicators(
|
||||
max_len,
|
||||
&vec![
|
||||
&[
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Pane),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
|
|
@ -324,7 +300,7 @@ pub fn ctrl_keys(help: &Help, max_len: usize) -> LinePart {
|
|||
),
|
||||
InputMode::Tab | InputMode::RenameTab => key_indicators(
|
||||
max_len,
|
||||
&vec![
|
||||
&[
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Tab),
|
||||
|
|
@ -335,7 +311,7 @@ pub fn ctrl_keys(help: &Help, max_len: usize) -> LinePart {
|
|||
),
|
||||
InputMode::Scroll => key_indicators(
|
||||
max_len,
|
||||
&vec![
|
||||
&[
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
|
|
@ -344,9 +320,9 @@ pub fn ctrl_keys(help: &Help, max_len: usize) -> LinePart {
|
|||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||
],
|
||||
),
|
||||
InputMode::Normal | _ => key_indicators(
|
||||
InputMode::Normal => key_indicators(
|
||||
max_len,
|
||||
&vec![
|
||||
&[
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ mod first_line;
|
|||
mod second_line;
|
||||
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
use zellij_tile::*;
|
||||
use zellij_tile::prelude::*;
|
||||
|
||||
use first_line::{ctrl_keys, superkey};
|
||||
use second_line::keybinds;
|
||||
|
|
@ -23,7 +23,9 @@ static ARROW_SEPARATOR: &str = "";
|
|||
static MORE_MSG: &str = " ... ";
|
||||
|
||||
#[derive(Default)]
|
||||
struct State {}
|
||||
struct State {
|
||||
mode_info: ModeInfo,
|
||||
}
|
||||
|
||||
register_tile!(State);
|
||||
|
||||
|
|
@ -40,19 +42,25 @@ impl Display for LinePart {
|
|||
}
|
||||
|
||||
impl ZellijTile for State {
|
||||
fn init(&mut self) {
|
||||
fn load(&mut self) {
|
||||
set_selectable(false);
|
||||
set_invisible_borders(true);
|
||||
set_max_height(2);
|
||||
subscribe(&[EventType::ModeUpdate]);
|
||||
}
|
||||
|
||||
fn draw(&mut self, _rows: usize, cols: usize) {
|
||||
let help = get_help();
|
||||
fn update(&mut self, event: Event) {
|
||||
if let Event::ModeUpdate(mode_info) = event {
|
||||
self.mode_info = mode_info;
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, _rows: usize, cols: usize) {
|
||||
let superkey = superkey();
|
||||
let ctrl_keys = ctrl_keys(&help, cols - superkey.len);
|
||||
let ctrl_keys = ctrl_keys(&self.mode_info, cols - superkey.len);
|
||||
|
||||
let first_line = format!("{}{}", superkey, ctrl_keys);
|
||||
let second_line = keybinds(&help, cols);
|
||||
let second_line = keybinds(&self.mode_info, cols);
|
||||
|
||||
// [48;5;238m is gray background, [0K is so that it fills the rest of the line
|
||||
// [48;5;16m is black background, [0K is so that it fills the rest of the line
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// use colored::*;
|
||||
use ansi_term::{ANSIStrings, Style};
|
||||
use zellij_tile::*;
|
||||
use zellij_tile::prelude::*;
|
||||
|
||||
use crate::colors::{BLACK, GREEN, ORANGE, WHITE};
|
||||
use crate::{LinePart, MORE_MSG};
|
||||
|
|
@ -97,7 +97,7 @@ fn select_pane_shortcut(is_first_shortcut: bool) -> LinePart {
|
|||
}
|
||||
}
|
||||
|
||||
fn full_shortcut_list(help: &Help) -> LinePart {
|
||||
fn full_shortcut_list(help: &ModeInfo) -> LinePart {
|
||||
match help.mode {
|
||||
InputMode::Normal => LinePart::default(),
|
||||
InputMode::Locked => locked_interface_indication(),
|
||||
|
|
@ -108,7 +108,7 @@ fn full_shortcut_list(help: &Help) -> LinePart {
|
|||
line_part.len += shortcut.len;
|
||||
line_part.part = format!("{}{}", line_part.part, shortcut,);
|
||||
}
|
||||
let select_pane_shortcut = select_pane_shortcut(help.keybinds.len() == 0);
|
||||
let select_pane_shortcut = select_pane_shortcut(help.keybinds.is_empty());
|
||||
line_part.len += select_pane_shortcut.len;
|
||||
line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,);
|
||||
line_part
|
||||
|
|
@ -116,7 +116,7 @@ fn full_shortcut_list(help: &Help) -> LinePart {
|
|||
}
|
||||
}
|
||||
|
||||
fn shortened_shortcut_list(help: &Help) -> LinePart {
|
||||
fn shortened_shortcut_list(help: &ModeInfo) -> LinePart {
|
||||
match help.mode {
|
||||
InputMode::Normal => LinePart::default(),
|
||||
InputMode::Locked => locked_interface_indication(),
|
||||
|
|
@ -127,7 +127,7 @@ fn shortened_shortcut_list(help: &Help) -> LinePart {
|
|||
line_part.len += shortcut.len;
|
||||
line_part.part = format!("{}{}", line_part.part, shortcut,);
|
||||
}
|
||||
let select_pane_shortcut = select_pane_shortcut(help.keybinds.len() == 0);
|
||||
let select_pane_shortcut = select_pane_shortcut(help.keybinds.is_empty());
|
||||
line_part.len += select_pane_shortcut.len;
|
||||
line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,);
|
||||
line_part
|
||||
|
|
@ -135,7 +135,7 @@ fn shortened_shortcut_list(help: &Help) -> LinePart {
|
|||
}
|
||||
}
|
||||
|
||||
fn best_effort_shortcut_list(help: &Help, max_len: usize) -> LinePart {
|
||||
fn best_effort_shortcut_list(help: &ModeInfo, max_len: usize) -> LinePart {
|
||||
match help.mode {
|
||||
InputMode::Normal => LinePart::default(),
|
||||
InputMode::Locked => {
|
||||
|
|
@ -159,7 +159,7 @@ fn best_effort_shortcut_list(help: &Help, max_len: usize) -> LinePart {
|
|||
line_part.len += shortcut.len;
|
||||
line_part.part = format!("{}{}", line_part.part, shortcut,);
|
||||
}
|
||||
let select_pane_shortcut = select_pane_shortcut(help.keybinds.len() == 0);
|
||||
let select_pane_shortcut = select_pane_shortcut(help.keybinds.is_empty());
|
||||
if line_part.len + select_pane_shortcut.len <= max_len {
|
||||
line_part.len += select_pane_shortcut.len;
|
||||
line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,);
|
||||
|
|
@ -169,7 +169,7 @@ fn best_effort_shortcut_list(help: &Help, max_len: usize) -> LinePart {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn keybinds(help: &Help, max_width: usize) -> LinePart {
|
||||
pub fn keybinds(help: &ModeInfo, max_width: usize) -> LinePart {
|
||||
let full_shortcut_list = full_shortcut_list(help);
|
||||
if full_shortcut_list.len <= max_width {
|
||||
return full_shortcut_list;
|
||||
|
|
@ -178,5 +178,5 @@ pub fn keybinds(help: &Help, max_width: usize) -> LinePart {
|
|||
if shortened_shortcut_list.len <= max_width {
|
||||
return shortened_shortcut_list;
|
||||
}
|
||||
return best_effort_shortcut_list(help, max_width);
|
||||
best_effort_shortcut_list(help, max_width)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,51 @@ mod state;
|
|||
use colored::*;
|
||||
use state::{FsEntry, State};
|
||||
use std::{cmp::min, fs::read_dir};
|
||||
use zellij_tile::*;
|
||||
use zellij_tile::prelude::*;
|
||||
|
||||
register_tile!(State);
|
||||
|
||||
impl ZellijTile for State {
|
||||
fn init(&mut self) {
|
||||
fn load(&mut self) {
|
||||
refresh_directory(self);
|
||||
subscribe(&[EventType::KeyPress]);
|
||||
}
|
||||
|
||||
fn draw(&mut self, rows: usize, cols: usize) {
|
||||
fn update(&mut self, event: Event) {
|
||||
if let Event::KeyPress(key) = event {
|
||||
match key {
|
||||
Key::Up | Key::Char('k') => {
|
||||
*self.selected_mut() = self.selected().saturating_sub(1);
|
||||
}
|
||||
Key::Down | Key::Char('j') => {
|
||||
let next = self.selected().saturating_add(1);
|
||||
*self.selected_mut() = min(self.files.len() - 1, next);
|
||||
}
|
||||
Key::Right | Key::Char('\n') | Key::Char('l') => {
|
||||
match self.files[self.selected()].clone() {
|
||||
FsEntry::Dir(p, _) => {
|
||||
self.path = p;
|
||||
refresh_directory(self);
|
||||
}
|
||||
FsEntry::File(p, _) => open_file(&p),
|
||||
}
|
||||
}
|
||||
Key::Left | Key::Char('h') => {
|
||||
self.path.pop();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
Key::Char('.') => {
|
||||
self.toggle_hidden_files();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, rows: usize, cols: usize) {
|
||||
for i in 0..rows {
|
||||
if self.selected() < self.scroll() {
|
||||
*self.scroll_mut() = self.selected();
|
||||
|
|
@ -38,38 +73,6 @@ impl ZellijTile for State {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_key(&mut self, key: Key) {
|
||||
match key {
|
||||
Key::Up | Key::Char('k') => {
|
||||
*self.selected_mut() = self.selected().saturating_sub(1);
|
||||
}
|
||||
Key::Down | Key::Char('j') => {
|
||||
let next = self.selected().saturating_add(1);
|
||||
*self.selected_mut() = min(self.files.len() - 1, next);
|
||||
}
|
||||
Key::Right | Key::Char('\n') | Key::Char('l') => {
|
||||
match self.files[self.selected()].clone() {
|
||||
FsEntry::Dir(p, _) => {
|
||||
self.path = p;
|
||||
refresh_directory(self);
|
||||
}
|
||||
FsEntry::File(p, _) => open_file(&p),
|
||||
}
|
||||
}
|
||||
Key::Left | Key::Char('h') => {
|
||||
self.path.pop();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
Key::Char('.') => {
|
||||
self.toggle_hidden_files();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_directory(state: &mut State) {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,6 @@ impl FsEntry {
|
|||
}
|
||||
|
||||
pub fn is_hidden_file(&self) -> bool {
|
||||
self.name().chars().nth(0).unwrap() == '.'.into()
|
||||
self.name().starts_with('.')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fn left_more_message(tab_count_to_the_left: usize) -> LinePart {
|
|||
let more_text = if tab_count_to_the_left < 10000 {
|
||||
format!(" ← +{} ", tab_count_to_the_left)
|
||||
} else {
|
||||
format!(" ← +many ")
|
||||
" ← +many ".to_string()
|
||||
};
|
||||
// 238
|
||||
let more_text_len = more_text.chars().count() + 2; // 2 for the arrows
|
||||
|
|
@ -84,7 +84,7 @@ fn right_more_message(tab_count_to_the_right: usize) -> LinePart {
|
|||
let more_text = if tab_count_to_the_right < 10000 {
|
||||
format!(" +{} → ", tab_count_to_the_right)
|
||||
} else {
|
||||
format!(" +many → ")
|
||||
" +many → ".to_string()
|
||||
};
|
||||
let more_text_len = more_text.chars().count() + 1; // 2 for the arrow
|
||||
let left_separator = Style::new().fg(GRAY).on(ORANGE).paint(ARROW_SEPARATOR);
|
||||
|
|
@ -130,7 +130,7 @@ fn add_next_tabs_msg(
|
|||
}
|
||||
|
||||
fn tab_line_prefix() -> LinePart {
|
||||
let prefix_text = format!(" Zellij ");
|
||||
let prefix_text = " Zellij ".to_string();
|
||||
let prefix_text_len = prefix_text.chars().count();
|
||||
let prefix_styled_text = Style::new().fg(WHITE).on(GRAY).bold().paint(prefix_text);
|
||||
LinePart {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
mod line;
|
||||
mod tab;
|
||||
|
||||
use zellij_tile::*;
|
||||
use zellij_tile::prelude::*;
|
||||
|
||||
use crate::line::tab_line;
|
||||
use crate::tab::tab_style;
|
||||
|
|
@ -12,25 +12,10 @@ pub struct LinePart {
|
|||
len: usize,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum BarMode {
|
||||
Normal,
|
||||
Rename,
|
||||
}
|
||||
|
||||
impl Default for BarMode {
|
||||
fn default() -> Self {
|
||||
BarMode::Normal
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct State {
|
||||
active_tab_index: usize,
|
||||
num_tabs: usize,
|
||||
tabs: Vec<TabData>,
|
||||
mode: BarMode,
|
||||
new_name: String,
|
||||
tabs: Vec<TabInfo>,
|
||||
mode: InputMode,
|
||||
}
|
||||
|
||||
static ARROW_SEPARATOR: &str = "";
|
||||
|
|
@ -49,17 +34,22 @@ pub mod colors {
|
|||
register_tile!(State);
|
||||
|
||||
impl ZellijTile for State {
|
||||
fn init(&mut self) {
|
||||
fn load(&mut self) {
|
||||
set_selectable(false);
|
||||
set_invisible_borders(true);
|
||||
set_max_height(1);
|
||||
self.active_tab_index = 0;
|
||||
self.num_tabs = 0;
|
||||
self.mode = BarMode::Normal;
|
||||
self.new_name = String::new();
|
||||
subscribe(&[EventType::TabUpdate, EventType::ModeUpdate]);
|
||||
}
|
||||
|
||||
fn draw(&mut self, _rows: usize, cols: usize) {
|
||||
fn update(&mut self, event: Event) {
|
||||
match event {
|
||||
Event::ModeUpdate(mode_info) => self.mode = mode_info.mode,
|
||||
Event::TabUpdate(tabs) => self.tabs = tabs,
|
||||
_ => unimplemented!(), // FIXME: This should be unreachable, but this could be cleaner
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, _rows: usize, cols: usize) {
|
||||
if self.tabs.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -67,11 +57,9 @@ impl ZellijTile for State {
|
|||
let mut active_tab_index = 0;
|
||||
for t in self.tabs.iter_mut() {
|
||||
let mut tabname = t.name.clone();
|
||||
if t.active && self.mode == BarMode::Rename {
|
||||
if self.new_name.is_empty() {
|
||||
if t.active && self.mode == InputMode::RenameTab {
|
||||
if tabname.is_empty() {
|
||||
tabname = String::from("Enter name...");
|
||||
} else {
|
||||
tabname = self.new_name.clone();
|
||||
}
|
||||
active_tab_index = t.position;
|
||||
} else if t.active {
|
||||
|
|
@ -87,20 +75,4 @@ impl ZellijTile for State {
|
|||
}
|
||||
println!("{}\u{1b}[48;5;238m\u{1b}[0K", s);
|
||||
}
|
||||
|
||||
fn update_tabs(&mut self) {
|
||||
self.tabs = get_tabs();
|
||||
}
|
||||
|
||||
fn handle_tab_rename_keypress(&mut self, key: Key) {
|
||||
self.mode = BarMode::Rename;
|
||||
match key {
|
||||
Key::Char('\n') | Key::Esc => {
|
||||
self.mode = BarMode::Normal;
|
||||
self.new_name.clear();
|
||||
}
|
||||
Key::Char(c) => self.new_name = format!("{}{}", self.new_name, c),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use crate::tab::Pane;
|
||||
use ansi_term::Colour;
|
||||
use std::collections::HashMap;
|
||||
use zellij_tile::data::InputMode;
|
||||
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
|
||||
|
|
@ -17,12 +19,20 @@ pub mod boundary_type {
|
|||
pub const CROSS: &str = "┼";
|
||||
}
|
||||
|
||||
pub mod colors {
|
||||
use ansi_term::Colour::{self, Fixed};
|
||||
pub const WHITE: Colour = Fixed(255);
|
||||
pub const GREEN: Colour = Fixed(154);
|
||||
pub const GRAY: Colour = Fixed(238);
|
||||
}
|
||||
|
||||
pub type BoundaryType = &'static str; // easy way to refer to boundary_type above
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BoundarySymbol {
|
||||
boundary_type: BoundaryType,
|
||||
invisible: bool,
|
||||
color: Option<Colour>,
|
||||
}
|
||||
|
||||
impl BoundarySymbol {
|
||||
|
|
@ -30,20 +40,27 @@ impl BoundarySymbol {
|
|||
BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible: false,
|
||||
color: Some(colors::GRAY),
|
||||
}
|
||||
}
|
||||
pub fn invisible(mut self) -> Self {
|
||||
self.invisible = true;
|
||||
self
|
||||
}
|
||||
pub fn color(&mut self, color: Option<Colour>) -> Self {
|
||||
self.color = color;
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BoundarySymbol {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
if self.invisible {
|
||||
write!(f, " ")
|
||||
} else {
|
||||
write!(f, "{}", self.boundary_type)
|
||||
match self.invisible {
|
||||
true => write!(f, " "),
|
||||
false => match self.color {
|
||||
Some(color) => write!(f, "{}", color.paint(self.boundary_type)),
|
||||
None => write!(f, "{}", self.boundary_type),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +70,10 @@ fn combine_symbols(
|
|||
next_symbol: BoundarySymbol,
|
||||
) -> Option<BoundarySymbol> {
|
||||
let invisible = current_symbol.invisible || next_symbol.invisible;
|
||||
let color = match (current_symbol.color.is_some(), next_symbol.color.is_some()) {
|
||||
(true, _) => current_symbol.color,
|
||||
_ => next_symbol.color,
|
||||
};
|
||||
let current_symbol = current_symbol.boundary_type;
|
||||
let next_symbol = next_symbol.boundary_type;
|
||||
match (current_symbol, next_symbol) {
|
||||
|
|
@ -62,6 +83,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::VERTICAL) => {
|
||||
|
|
@ -70,6 +92,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::HORIZONTAL) => {
|
||||
|
|
@ -78,6 +101,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::TOP_LEFT) => {
|
||||
|
|
@ -86,6 +110,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::BOTTOM_RIGHT) => {
|
||||
|
|
@ -94,6 +119,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::BOTTOM_LEFT) => {
|
||||
|
|
@ -102,6 +128,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::VERTICAL_LEFT) => {
|
||||
|
|
@ -110,6 +137,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -118,6 +146,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -126,6 +155,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -134,6 +164,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_RIGHT, boundary_type::CROSS) => {
|
||||
|
|
@ -142,6 +173,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::HORIZONTAL) => {
|
||||
|
|
@ -150,6 +182,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::VERTICAL) => {
|
||||
|
|
@ -158,6 +191,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::TOP_LEFT) => {
|
||||
|
|
@ -166,6 +200,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::BOTTOM_RIGHT) => {
|
||||
|
|
@ -174,6 +209,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::BOTTOM_LEFT) => {
|
||||
|
|
@ -182,6 +218,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::VERTICAL_LEFT) => {
|
||||
|
|
@ -190,6 +227,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -198,6 +236,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -206,6 +245,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -214,6 +254,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL, boundary_type::CROSS) => {
|
||||
|
|
@ -222,6 +263,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::VERTICAL) => {
|
||||
|
|
@ -230,6 +272,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::TOP_LEFT) => {
|
||||
|
|
@ -238,6 +281,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::BOTTOM_RIGHT) => {
|
||||
|
|
@ -246,6 +290,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::BOTTOM_LEFT) => {
|
||||
|
|
@ -254,6 +299,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::VERTICAL_LEFT) => {
|
||||
|
|
@ -262,6 +308,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -270,6 +317,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -278,6 +326,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -286,6 +335,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL, boundary_type::CROSS) => {
|
||||
|
|
@ -294,6 +344,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::TOP_LEFT) => {
|
||||
|
|
@ -302,6 +353,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::BOTTOM_RIGHT) => {
|
||||
|
|
@ -310,6 +362,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::BOTTOM_LEFT) => {
|
||||
|
|
@ -318,6 +371,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::VERTICAL_LEFT) => {
|
||||
|
|
@ -326,6 +380,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -334,6 +389,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -342,6 +398,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -350,6 +407,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::TOP_LEFT, boundary_type::CROSS) => {
|
||||
|
|
@ -358,6 +416,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_RIGHT, boundary_type::BOTTOM_RIGHT) => {
|
||||
|
|
@ -366,6 +425,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_RIGHT, boundary_type::BOTTOM_LEFT) => {
|
||||
|
|
@ -374,6 +434,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_RIGHT, boundary_type::VERTICAL_LEFT) => {
|
||||
|
|
@ -382,6 +443,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_RIGHT, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -390,6 +452,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_RIGHT, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -398,6 +461,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_RIGHT, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -406,6 +470,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_RIGHT, boundary_type::CROSS) => {
|
||||
|
|
@ -414,6 +479,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_LEFT, boundary_type::BOTTOM_LEFT) => {
|
||||
|
|
@ -422,6 +488,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_LEFT, boundary_type::VERTICAL_LEFT) => {
|
||||
|
|
@ -430,6 +497,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_LEFT, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -438,6 +506,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_LEFT, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -446,6 +515,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_LEFT, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -454,6 +524,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::BOTTOM_LEFT, boundary_type::CROSS) => {
|
||||
|
|
@ -462,6 +533,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_LEFT, boundary_type::VERTICAL_LEFT) => {
|
||||
|
|
@ -470,6 +542,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_LEFT, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -478,6 +551,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_LEFT, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -486,6 +560,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_LEFT, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -494,6 +569,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_LEFT, boundary_type::CROSS) => {
|
||||
|
|
@ -502,6 +578,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_RIGHT, boundary_type::VERTICAL_RIGHT) => {
|
||||
|
|
@ -510,6 +587,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_RIGHT, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -518,6 +596,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_RIGHT, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -526,6 +605,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::VERTICAL_RIGHT, boundary_type::CROSS) => {
|
||||
|
|
@ -534,6 +614,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL_DOWN, boundary_type::HORIZONTAL_DOWN) => {
|
||||
|
|
@ -542,6 +623,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL_DOWN, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -550,6 +632,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL_DOWN, boundary_type::CROSS) => {
|
||||
|
|
@ -558,6 +641,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL_UP, boundary_type::HORIZONTAL_UP) => {
|
||||
|
|
@ -566,6 +650,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::HORIZONTAL_UP, boundary_type::CROSS) => {
|
||||
|
|
@ -574,6 +659,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(boundary_type::CROSS, boundary_type::CROSS) => {
|
||||
|
|
@ -582,6 +668,7 @@ fn combine_symbols(
|
|||
Some(BoundarySymbol {
|
||||
boundary_type,
|
||||
invisible,
|
||||
color,
|
||||
})
|
||||
}
|
||||
(_, _) => None,
|
||||
|
|
@ -677,7 +764,14 @@ impl Boundaries {
|
|||
boundary_characters: HashMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn add_rect(&mut self, rect: &dyn Pane) {
|
||||
pub fn add_rect(&mut self, rect: &dyn Pane, input_mode: InputMode, color: Option<Colour>) {
|
||||
let color = match color.is_some() {
|
||||
true => match input_mode {
|
||||
InputMode::Normal | InputMode::Locked => Some(colors::GREEN),
|
||||
_ => Some(colors::WHITE),
|
||||
},
|
||||
false => None,
|
||||
};
|
||||
if rect.x() > 0 {
|
||||
let boundary_x_coords = rect.x() - 1;
|
||||
let first_row_coordinates = self.rect_right_boundary_row_start(rect);
|
||||
|
|
@ -685,11 +779,11 @@ impl Boundaries {
|
|||
for row in first_row_coordinates..last_row_coordinates {
|
||||
let coordinates = Coordinates::new(boundary_x_coords, row);
|
||||
let mut symbol_to_add = if row == first_row_coordinates && row != 0 {
|
||||
BoundarySymbol::new(boundary_type::TOP_LEFT)
|
||||
BoundarySymbol::new(boundary_type::TOP_LEFT).color(color)
|
||||
} else if row == last_row_coordinates - 1 && row != self.rows - 1 {
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_LEFT)
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color)
|
||||
} else {
|
||||
BoundarySymbol::new(boundary_type::VERTICAL)
|
||||
BoundarySymbol::new(boundary_type::VERTICAL).color(color)
|
||||
};
|
||||
if rect.invisible_borders() {
|
||||
symbol_to_add = symbol_to_add.invisible();
|
||||
|
|
@ -709,11 +803,11 @@ impl Boundaries {
|
|||
for col in first_col_coordinates..last_col_coordinates {
|
||||
let coordinates = Coordinates::new(col, boundary_y_coords);
|
||||
let mut symbol_to_add = if col == first_col_coordinates && col != 0 {
|
||||
BoundarySymbol::new(boundary_type::TOP_LEFT)
|
||||
BoundarySymbol::new(boundary_type::TOP_LEFT).color(color)
|
||||
} else if col == last_col_coordinates - 1 && col != self.columns - 1 {
|
||||
BoundarySymbol::new(boundary_type::TOP_RIGHT)
|
||||
BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color)
|
||||
} else {
|
||||
BoundarySymbol::new(boundary_type::HORIZONTAL)
|
||||
BoundarySymbol::new(boundary_type::HORIZONTAL).color(color)
|
||||
};
|
||||
if rect.invisible_borders() {
|
||||
symbol_to_add = symbol_to_add.invisible();
|
||||
|
|
@ -734,11 +828,11 @@ impl Boundaries {
|
|||
for row in first_row_coordinates..last_row_coordinates {
|
||||
let coordinates = Coordinates::new(boundary_x_coords, row);
|
||||
let mut symbol_to_add = if row == first_row_coordinates && row != 0 {
|
||||
BoundarySymbol::new(boundary_type::TOP_RIGHT)
|
||||
BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color)
|
||||
} else if row == last_row_coordinates - 1 && row != self.rows - 1 {
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_RIGHT)
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color)
|
||||
} else {
|
||||
BoundarySymbol::new(boundary_type::VERTICAL)
|
||||
BoundarySymbol::new(boundary_type::VERTICAL).color(color)
|
||||
};
|
||||
if rect.invisible_borders() {
|
||||
symbol_to_add = symbol_to_add.invisible();
|
||||
|
|
@ -758,11 +852,11 @@ impl Boundaries {
|
|||
for col in first_col_coordinates..last_col_coordinates {
|
||||
let coordinates = Coordinates::new(col, boundary_y_coords);
|
||||
let mut symbol_to_add = if col == first_col_coordinates && col != 0 {
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_LEFT)
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color)
|
||||
} else if col == last_col_coordinates - 1 && col != self.columns - 1 {
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_RIGHT)
|
||||
BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color)
|
||||
} else {
|
||||
BoundarySymbol::new(boundary_type::HORIZONTAL)
|
||||
BoundarySymbol::new(boundary_type::HORIZONTAL).color(color)
|
||||
};
|
||||
if rect.invisible_borders() {
|
||||
symbol_to_add = symbol_to_add.invisible();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use crate::utils::consts::ZELLIJ_ROOT_LAYOUT_DIR;
|
||||
use directories_next::ProjectDirs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::{fs::File, io::prelude::*};
|
||||
|
||||
use crate::common::wasm_vm::EventType;
|
||||
use crate::panes::PositionAndSize;
|
||||
|
||||
fn split_space_to_parts_vertically(
|
||||
|
|
@ -181,19 +179,15 @@ pub struct Layout {
|
|||
pub plugin: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub expansion_boundary: bool,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub events: Vec<EventType>,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn new(layout_path: PathBuf) -> Self {
|
||||
let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap();
|
||||
let layout_dir = project_dirs.data_dir().join("layouts/");
|
||||
let root_layout_dir = Path::new(ZELLIJ_ROOT_LAYOUT_DIR);
|
||||
let mut layout_file = File::open(&layout_path)
|
||||
.or_else(|_| File::open(&layout_path.with_extension("yaml")))
|
||||
.or_else(|_| File::open(&layout_dir.join(&layout_path).with_extension("yaml")))
|
||||
.or_else(|_| File::open(root_layout_dir.join(&layout_path).with_extension("yaml")))
|
||||
.unwrap_or_else(|_| panic!("cannot find layout {}", &layout_path.display()));
|
||||
|
||||
let mut layout = String::new();
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl Pane for PluginPane {
|
|||
let (buf_tx, buf_rx) = channel();
|
||||
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Draw(
|
||||
.send(PluginInstruction::Render(
|
||||
buf_tx,
|
||||
self.pid,
|
||||
self.rows(),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ pub enum AnsiCode {
|
|||
On,
|
||||
Reset,
|
||||
NamedColor(NamedColor),
|
||||
RGBCode((u8, u8, u8)),
|
||||
RgbCode((u8, u8, u8)),
|
||||
ColorIndex(u8),
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ impl CharacterStyles {
|
|||
[36, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
|
||||
[37, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))),
|
||||
[38, 2, ..] => {
|
||||
let ansi_code = AnsiCode::RGBCode((
|
||||
let ansi_code = AnsiCode::RgbCode((
|
||||
*ansi_params.get(2).unwrap() as u8,
|
||||
*ansi_params.get(3).unwrap() as u8,
|
||||
*ansi_params.get(4).unwrap() as u8,
|
||||
|
|
@ -364,7 +364,7 @@ impl CharacterStyles {
|
|||
[46, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))),
|
||||
[47, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))),
|
||||
[48, 2, ..] => {
|
||||
let ansi_code = AnsiCode::RGBCode((
|
||||
let ansi_code = AnsiCode::RgbCode((
|
||||
*ansi_params.get(2).unwrap() as u8,
|
||||
*ansi_params.get(3).unwrap() as u8,
|
||||
*ansi_params.get(4).unwrap() as u8,
|
||||
|
|
@ -416,7 +416,7 @@ impl Display for CharacterStyles {
|
|||
}
|
||||
if let Some(ansi_code) = self.foreground {
|
||||
match ansi_code {
|
||||
AnsiCode::RGBCode((r, g, b)) => {
|
||||
AnsiCode::RgbCode((r, g, b)) => {
|
||||
write!(f, "\u{1b}[38;2;{};{};{}m", r, g, b)?;
|
||||
}
|
||||
AnsiCode::ColorIndex(color_index) => {
|
||||
|
|
@ -433,7 +433,7 @@ impl Display for CharacterStyles {
|
|||
};
|
||||
if let Some(ansi_code) = self.background {
|
||||
match ansi_code {
|
||||
AnsiCode::RGBCode((r, g, b)) => {
|
||||
AnsiCode::RgbCode((r, g, b)) => {
|
||||
write!(f, "\u{1b}[48;2;{};{};{}m", r, g, b)?;
|
||||
}
|
||||
AnsiCode::ColorIndex(color_index) => {
|
||||
|
|
|
|||
|
|
@ -70,13 +70,11 @@ impl Pane for TerminalPane {
|
|||
fn reset_size_and_position_override(&mut self) {
|
||||
self.position_and_size_override = None;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn change_pos_and_size(&mut self, position_and_size: &PositionAndSize) {
|
||||
self.position_and_size.columns = position_and_size.columns;
|
||||
self.position_and_size.rows = position_and_size.rows;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) {
|
||||
let position_and_size_override = PositionAndSize {
|
||||
|
|
@ -87,7 +85,6 @@ impl Pane for TerminalPane {
|
|||
};
|
||||
self.position_and_size_override = Some(position_and_size_override);
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn handle_event(&mut self, event: VteEvent) {
|
||||
match event {
|
||||
|
|
@ -191,12 +188,14 @@ impl Pane for TerminalPane {
|
|||
self.max_height
|
||||
}
|
||||
fn render(&mut self) -> Option<String> {
|
||||
// if self.should_render {
|
||||
// FIXME:
|
||||
// the below conditional is commented out because it causes several bugs:
|
||||
// 1. When panes are resized or tabs are switched the previous contents of the screen stick
|
||||
// around
|
||||
// 2. When there are wide characters in a pane, since we don't yet handle them properly,
|
||||
// the spill over to the pane to the right
|
||||
// if self.should_render || cfg!(test) {
|
||||
if true {
|
||||
// while checking should_render rather than rendering each pane every time
|
||||
// is more performant, it causes some problems when the pane to the left should be
|
||||
// rendered and has wide characters (eg. Chinese characters or emoji)
|
||||
// as a (hopefully) temporary hack, we render all panes until we find a better solution
|
||||
let mut vte_output = String::new();
|
||||
let buffer_lines = &self.read_buffer_as_lines();
|
||||
let display_cols = self.get_columns();
|
||||
|
|
@ -205,12 +204,11 @@ impl Pane for TerminalPane {
|
|||
for line_index in 0..self.grid.height {
|
||||
let x = self.get_x();
|
||||
let y = self.get_y();
|
||||
vte_output = format!(
|
||||
"{}\u{1b}[{};{}H\u{1b}[m",
|
||||
vte_output,
|
||||
vte_output.push_str(&format!(
|
||||
"\u{1b}[{};{}H\u{1b}[m",
|
||||
y + line_index + 1,
|
||||
x + 1
|
||||
); // goto row/col and reset styles
|
||||
)); // goto row/col and reset styles
|
||||
for _col_index in 0..self.grid.width {
|
||||
vte_output.push(EMPTY_TERMINAL_CHARACTER.character);
|
||||
}
|
||||
|
|
@ -220,7 +218,7 @@ impl Pane for TerminalPane {
|
|||
for (row, line) in buffer_lines.iter().enumerate() {
|
||||
let x = self.get_x();
|
||||
let y = self.get_y();
|
||||
vte_output = format!("{}\u{1b}[{};{}H\u{1b}[m", vte_output, y + row + 1, x + 1); // goto row/col and reset styles
|
||||
vte_output.push_str(&format!("\u{1b}[{};{}H\u{1b}[m", y + row + 1, x + 1)); // goto row/col and reset styles
|
||||
for (col, t_character) in line.iter().enumerate() {
|
||||
if col < display_cols {
|
||||
// in some cases (eg. while resizing) some characters will spill over
|
||||
|
|
@ -232,14 +230,14 @@ impl Pane for TerminalPane {
|
|||
// the terminal keeps the previous styles as long as we're in the same
|
||||
// line, so we only want to update the new styles here (this also
|
||||
// includes resetting previous styles as needed)
|
||||
vte_output = format!("{}{}", vte_output, new_styles);
|
||||
vte_output.push_str(&new_styles.to_string());
|
||||
}
|
||||
vte_output.push(t_character.character);
|
||||
}
|
||||
}
|
||||
character_styles.clear();
|
||||
}
|
||||
self.mark_for_rerender();
|
||||
self.should_render = false;
|
||||
Some(vte_output)
|
||||
} else {
|
||||
None
|
||||
|
|
@ -252,45 +250,37 @@ impl Pane for TerminalPane {
|
|||
self.position_and_size.y += count;
|
||||
self.position_and_size.rows -= count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn increase_height_down(&mut self, count: usize) {
|
||||
self.position_and_size.rows += count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn increase_height_up(&mut self, count: usize) {
|
||||
self.position_and_size.y -= count;
|
||||
self.position_and_size.rows += count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn reduce_height_up(&mut self, count: usize) {
|
||||
self.position_and_size.rows -= count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn reduce_width_right(&mut self, count: usize) {
|
||||
self.position_and_size.x += count;
|
||||
self.position_and_size.columns -= count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn reduce_width_left(&mut self, count: usize) {
|
||||
self.position_and_size.columns -= count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn increase_width_left(&mut self, count: usize) {
|
||||
self.position_and_size.x -= count;
|
||||
self.position_and_size.columns += count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn increase_width_right(&mut self, count: usize) {
|
||||
self.position_and_size.columns += count;
|
||||
self.reflow_lines();
|
||||
self.mark_for_rerender();
|
||||
}
|
||||
fn scroll_up(&mut self, count: usize) {
|
||||
self.grid.move_viewport_up(count);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
//! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size,
|
||||
//! as well as how they should be resized
|
||||
|
||||
use crate::common::{AppInstruction, SenderWithContext};
|
||||
use crate::boundaries::colors;
|
||||
use crate::common::{input::handler::parse_keys, AppInstruction, SenderWithContext};
|
||||
use crate::layout::Layout;
|
||||
use crate::panes::{PaneId, PositionAndSize, TerminalPane};
|
||||
use crate::pty_bus::{PtyInstruction, VteEvent};
|
||||
use crate::wasm_vm::{PluginInputType, PluginInstruction};
|
||||
use crate::wasm_vm::PluginInstruction;
|
||||
use crate::{boundaries::Boundaries, panes::PluginPane};
|
||||
use crate::{os_input_output::OsApi, utils::shared::pad_to_size};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
collections::{BTreeMap, HashSet},
|
||||
};
|
||||
use std::{io::Write, sync::mpsc::channel};
|
||||
use zellij_tile::data::{Event, InputMode};
|
||||
|
||||
const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this
|
||||
const MIN_TERMINAL_HEIGHT: usize = 2;
|
||||
|
|
@ -65,14 +66,7 @@ pub struct Tab {
|
|||
pub send_plugin_instructions: SenderWithContext<PluginInstruction>,
|
||||
pub send_app_instructions: SenderWithContext<AppInstruction>,
|
||||
expansion_boundary: Option<PositionAndSize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct TabData {
|
||||
/* subset of fields to publish to plugins */
|
||||
pub position: usize,
|
||||
pub name: String,
|
||||
pub active: bool,
|
||||
pub input_mode: InputMode,
|
||||
}
|
||||
|
||||
// FIXME: Use a struct that has a pane_type enum, to reduce all of the duplication
|
||||
|
|
@ -189,6 +183,7 @@ impl Tab {
|
|||
send_app_instructions: SenderWithContext<AppInstruction>,
|
||||
max_panes: Option<usize>,
|
||||
pane_id: Option<PaneId>,
|
||||
input_mode: InputMode,
|
||||
) -> Self {
|
||||
let panes = if let Some(PaneId::Terminal(pid)) = pane_id {
|
||||
let new_terminal = TerminalPane::new(pid, *full_screen_ws);
|
||||
|
|
@ -218,6 +213,7 @@ impl Tab {
|
|||
send_pty_instructions,
|
||||
send_plugin_instructions,
|
||||
expansion_boundary: None,
|
||||
input_mode,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,11 +258,7 @@ impl Tab {
|
|||
if let Some(plugin) = &layout.plugin {
|
||||
let (pid_tx, pid_rx) = channel();
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Load(
|
||||
pid_tx,
|
||||
plugin.clone(),
|
||||
layout.events.clone(),
|
||||
))
|
||||
.send(PluginInstruction::Load(pid_tx, plugin.clone()))
|
||||
.unwrap();
|
||||
let pid = pid_rx.recv().unwrap();
|
||||
let new_plugin = PluginPane::new(
|
||||
|
|
@ -305,7 +297,6 @@ impl Tab {
|
|||
self.toggle_active_pane_fullscreen();
|
||||
}
|
||||
if !self.has_panes() {
|
||||
// FIXME: This could use a second look
|
||||
if let PaneId::Terminal(term_pid) = pid {
|
||||
let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
|
|
@ -356,7 +347,6 @@ impl Tab {
|
|||
if terminal_to_split.rows() * CURSOR_HEIGHT_WIDTH_RATIO > terminal_to_split.columns()
|
||||
&& terminal_to_split.rows() > terminal_to_split.min_height() * 2
|
||||
{
|
||||
// FIXME: This could use a second look
|
||||
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);
|
||||
|
|
@ -377,7 +367,6 @@ impl Tab {
|
|||
self.active_terminal = Some(pid);
|
||||
}
|
||||
} else if terminal_to_split.columns() > terminal_to_split.min_width() * 2 {
|
||||
// FIXME: This could use a second look
|
||||
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);
|
||||
|
|
@ -407,7 +396,6 @@ impl Tab {
|
|||
self.toggle_active_pane_fullscreen();
|
||||
}
|
||||
if !self.has_panes() {
|
||||
// FIXME: This could use a second look
|
||||
if let PaneId::Terminal(term_pid) = pid {
|
||||
let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
|
|
@ -418,47 +406,44 @@ impl Tab {
|
|||
self.panes.insert(pid, Box::new(new_terminal));
|
||||
self.active_terminal = Some(pid);
|
||||
}
|
||||
} else {
|
||||
// FIXME: This could use a second look
|
||||
if let PaneId::Terminal(term_pid) = pid {
|
||||
// TODO: check minimum size of active terminal
|
||||
let active_pane_id = &self.get_active_pane_id().unwrap();
|
||||
let active_pane = self.panes.get_mut(active_pane_id).unwrap();
|
||||
if active_pane.rows() < MIN_TERMINAL_HEIGHT * 2 + 1 {
|
||||
self.send_pty_instructions
|
||||
.send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
let terminal_ws = PositionAndSize {
|
||||
x: active_pane.x(),
|
||||
y: active_pane.y(),
|
||||
rows: active_pane.rows(),
|
||||
columns: active_pane.columns(),
|
||||
};
|
||||
let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws);
|
||||
|
||||
active_pane.change_pos_and_size(&top_winsize);
|
||||
|
||||
let new_terminal = TerminalPane::new(term_pid, bottom_winsize);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
new_terminal.pid,
|
||||
bottom_winsize.columns as u16,
|
||||
bottom_winsize.rows as u16,
|
||||
);
|
||||
self.panes.insert(pid, Box::new(new_terminal));
|
||||
|
||||
if let PaneId::Terminal(active_terminal_pid) = active_pane_id {
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
*active_terminal_pid,
|
||||
top_winsize.columns as u16,
|
||||
top_winsize.rows as u16,
|
||||
);
|
||||
}
|
||||
|
||||
self.active_terminal = Some(pid);
|
||||
self.render();
|
||||
} else if let PaneId::Terminal(term_pid) = pid {
|
||||
// TODO: check minimum size of active terminal
|
||||
let active_pane_id = &self.get_active_pane_id().unwrap();
|
||||
let active_pane = self.panes.get_mut(active_pane_id).unwrap();
|
||||
if active_pane.rows() < MIN_TERMINAL_HEIGHT * 2 + 1 {
|
||||
self.send_pty_instructions
|
||||
.send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
let terminal_ws = PositionAndSize {
|
||||
x: active_pane.x(),
|
||||
y: active_pane.y(),
|
||||
rows: active_pane.rows(),
|
||||
columns: active_pane.columns(),
|
||||
};
|
||||
let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws);
|
||||
|
||||
active_pane.change_pos_and_size(&top_winsize);
|
||||
|
||||
let new_terminal = TerminalPane::new(term_pid, bottom_winsize);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
new_terminal.pid,
|
||||
bottom_winsize.columns as u16,
|
||||
bottom_winsize.rows as u16,
|
||||
);
|
||||
self.panes.insert(pid, Box::new(new_terminal));
|
||||
|
||||
if let PaneId::Terminal(active_terminal_pid) = active_pane_id {
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
*active_terminal_pid,
|
||||
top_winsize.columns as u16,
|
||||
top_winsize.rows as u16,
|
||||
);
|
||||
}
|
||||
|
||||
self.active_terminal = Some(pid);
|
||||
self.render();
|
||||
}
|
||||
}
|
||||
pub fn vertical_split(&mut self, pid: PaneId) {
|
||||
|
|
@ -467,7 +452,6 @@ impl Tab {
|
|||
self.toggle_active_pane_fullscreen();
|
||||
}
|
||||
if !self.has_panes() {
|
||||
// FIXME: This could use a second look
|
||||
if let PaneId::Terminal(term_pid) = pid {
|
||||
let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
|
|
@ -478,47 +462,44 @@ impl Tab {
|
|||
self.panes.insert(pid, Box::new(new_terminal));
|
||||
self.active_terminal = Some(pid);
|
||||
}
|
||||
} else {
|
||||
// FIXME: This could use a second look
|
||||
if let PaneId::Terminal(term_pid) = pid {
|
||||
// TODO: check minimum size of active terminal
|
||||
let active_pane_id = &self.get_active_pane_id().unwrap();
|
||||
let active_pane = self.panes.get_mut(active_pane_id).unwrap();
|
||||
if active_pane.columns() < MIN_TERMINAL_WIDTH * 2 + 1 {
|
||||
self.send_pty_instructions
|
||||
.send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
let terminal_ws = PositionAndSize {
|
||||
x: active_pane.x(),
|
||||
y: active_pane.y(),
|
||||
rows: active_pane.rows(),
|
||||
columns: active_pane.columns(),
|
||||
};
|
||||
let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws);
|
||||
|
||||
active_pane.change_pos_and_size(&left_winsize);
|
||||
|
||||
let new_terminal = TerminalPane::new(term_pid, right_winsize);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
new_terminal.pid,
|
||||
right_winsize.columns as u16,
|
||||
right_winsize.rows as u16,
|
||||
);
|
||||
self.panes.insert(pid, Box::new(new_terminal));
|
||||
|
||||
if let PaneId::Terminal(active_terminal_pid) = active_pane_id {
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
*active_terminal_pid,
|
||||
left_winsize.columns as u16,
|
||||
left_winsize.rows as u16,
|
||||
);
|
||||
}
|
||||
|
||||
self.active_terminal = Some(pid);
|
||||
self.render();
|
||||
} else if let PaneId::Terminal(term_pid) = pid {
|
||||
// TODO: check minimum size of active terminal
|
||||
let active_pane_id = &self.get_active_pane_id().unwrap();
|
||||
let active_pane = self.panes.get_mut(active_pane_id).unwrap();
|
||||
if active_pane.columns() < MIN_TERMINAL_WIDTH * 2 + 1 {
|
||||
self.send_pty_instructions
|
||||
.send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
let terminal_ws = PositionAndSize {
|
||||
x: active_pane.x(),
|
||||
y: active_pane.y(),
|
||||
rows: active_pane.rows(),
|
||||
columns: active_pane.columns(),
|
||||
};
|
||||
let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws);
|
||||
|
||||
active_pane.change_pos_and_size(&left_winsize);
|
||||
|
||||
let new_terminal = TerminalPane::new(term_pid, right_winsize);
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
new_terminal.pid,
|
||||
right_winsize.columns as u16,
|
||||
right_winsize.rows as u16,
|
||||
);
|
||||
self.panes.insert(pid, Box::new(new_terminal));
|
||||
|
||||
if let PaneId::Terminal(active_terminal_pid) = active_pane_id {
|
||||
self.os_api.set_terminal_size_using_fd(
|
||||
*active_terminal_pid,
|
||||
left_winsize.columns as u16,
|
||||
left_winsize.rows as u16,
|
||||
);
|
||||
}
|
||||
|
||||
self.active_terminal = Some(pid);
|
||||
self.render();
|
||||
}
|
||||
}
|
||||
pub fn get_active_pane(&self) -> Option<&dyn Pane> {
|
||||
|
|
@ -562,12 +543,11 @@ impl Tab {
|
|||
.expect("failed to drain terminal");
|
||||
}
|
||||
Some(PaneId::Plugin(pid)) => {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Input(
|
||||
PluginInputType::Normal(pid),
|
||||
input_bytes,
|
||||
))
|
||||
.unwrap();
|
||||
for key in parse_keys(&input_bytes) {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Update(Some(pid), Event::KeyPress(key)))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -645,7 +625,12 @@ impl Tab {
|
|||
.expect("cannot write to stdout");
|
||||
for (kind, terminal) in self.panes.iter_mut() {
|
||||
if !self.panes_to_hide.contains(&terminal.pid()) {
|
||||
boundaries.add_rect(terminal.as_ref());
|
||||
match self.active_terminal.unwrap() == terminal.pid() {
|
||||
true => {
|
||||
boundaries.add_rect(terminal.as_ref(), self.input_mode, Some(colors::GREEN))
|
||||
}
|
||||
false => boundaries.add_rect(terminal.as_ref(), self.input_mode, None),
|
||||
}
|
||||
if let Some(vte_output) = terminal.render() {
|
||||
let vte_output = if let PaneId::Terminal(_) = kind {
|
||||
vte_output
|
||||
|
|
@ -1679,8 +1664,8 @@ impl Tab {
|
|||
} else if self.can_reduce_pane_and_surroundings_right(&active_pane_id, count) {
|
||||
self.reduce_pane_and_surroundings_right(&active_pane_id, count);
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
pub fn resize_left(&mut self) {
|
||||
// TODO: find out by how much we actually reduced and only reduce by that much
|
||||
|
|
@ -1691,8 +1676,8 @@ impl Tab {
|
|||
} else if self.can_reduce_pane_and_surroundings_left(&active_pane_id, count) {
|
||||
self.reduce_pane_and_surroundings_left(&active_pane_id, count);
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
pub fn resize_down(&mut self) {
|
||||
// TODO: find out by how much we actually reduced and only reduce by that much
|
||||
|
|
@ -1703,8 +1688,8 @@ impl Tab {
|
|||
} else if self.can_reduce_pane_and_surroundings_down(&active_pane_id, count) {
|
||||
self.reduce_pane_and_surroundings_down(&active_pane_id, count);
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
pub fn resize_up(&mut self) {
|
||||
// TODO: find out by how much we actually reduced and only reduce by that much
|
||||
|
|
@ -1715,8 +1700,8 @@ impl Tab {
|
|||
} else if self.can_reduce_pane_and_surroundings_up(&active_pane_id, count) {
|
||||
self.reduce_pane_and_surroundings_up(&active_pane_id, count);
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
self.render();
|
||||
}
|
||||
pub fn move_focus(&mut self) {
|
||||
if !self.has_selectable_panes() {
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ pub enum ContextType {
|
|||
Plugin(PluginContext),
|
||||
/// An app-related call.
|
||||
App(AppContext),
|
||||
IPCServer,
|
||||
IpcServer,
|
||||
StdinHandler,
|
||||
AsyncTask,
|
||||
/// An empty, placeholder call. This should be thought of as representing no call at all.
|
||||
|
|
@ -152,7 +152,7 @@ impl Display for ContextType {
|
|||
|
||||
ContextType::Plugin(c) => write!(f, "{}plugin_thread: {}{:?}", purple, green, c),
|
||||
ContextType::App(c) => write!(f, "{}main_thread: {}{:?}", purple, green, c),
|
||||
ContextType::IPCServer => write!(f, "{}ipc_server: {}AcceptInput", purple, green),
|
||||
ContextType::IpcServer => write!(f, "{}ipc_server: {}AcceptInput", purple, green),
|
||||
ContextType::StdinHandler => {
|
||||
write!(f, "{}stdin_handler_thread: {}AcceptInput", purple, green)
|
||||
}
|
||||
|
|
@ -164,6 +164,7 @@ impl Display for ContextType {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!!
|
||||
/// Stack call representations corresponding to the different types of [`ScreenInstruction`]s.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ScreenContext {
|
||||
|
|
@ -199,8 +200,10 @@ pub enum ScreenContext {
|
|||
CloseTab,
|
||||
GoToTab,
|
||||
UpdateTabName,
|
||||
ChangeInputMode,
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
|
@ -238,6 +241,7 @@ impl From<&ScreenInstruction> for ScreenContext {
|
|||
ScreenInstruction::CloseTab => ScreenContext::CloseTab,
|
||||
ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab,
|
||||
ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName,
|
||||
ScreenInstruction::ChangeInputMode(_) => ScreenContext::ChangeInputMode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,24 +280,20 @@ use crate::wasm_vm::PluginInstruction;
|
|||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum PluginContext {
|
||||
Load,
|
||||
Draw,
|
||||
Input,
|
||||
GlobalInput,
|
||||
Update,
|
||||
Render,
|
||||
Unload,
|
||||
Quit,
|
||||
Tabs,
|
||||
}
|
||||
|
||||
impl From<&PluginInstruction> for PluginContext {
|
||||
fn from(plugin_instruction: &PluginInstruction) -> Self {
|
||||
match *plugin_instruction {
|
||||
PluginInstruction::Load(..) => PluginContext::Load,
|
||||
PluginInstruction::Draw(..) => PluginContext::Draw,
|
||||
PluginInstruction::Input(..) => PluginContext::Input,
|
||||
PluginInstruction::GlobalInput(_) => PluginContext::GlobalInput,
|
||||
PluginInstruction::Update(..) => PluginContext::Update,
|
||||
PluginInstruction::Render(..) => PluginContext::Render,
|
||||
PluginInstruction::Unload(_) => PluginContext::Unload,
|
||||
PluginInstruction::Quit => PluginContext::Quit,
|
||||
PluginInstruction::UpdateTabs(..) => PluginContext::Tabs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -301,8 +301,6 @@ impl From<&PluginInstruction> for PluginContext {
|
|||
/// Stack call representations corresponding to the different types of [`AppInstruction`]s.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum AppContext {
|
||||
GetState,
|
||||
SetState,
|
||||
Exit,
|
||||
Error,
|
||||
}
|
||||
|
|
@ -310,8 +308,6 @@ pub enum AppContext {
|
|||
impl From<&AppInstruction> for AppContext {
|
||||
fn from(app_instruction: &AppInstruction) -> Self {
|
||||
match *app_instruction {
|
||||
AppInstruction::GetState(_) => AppContext::GetState,
|
||||
AppInstruction::SetState(_) => AppContext::SetState,
|
||||
AppInstruction::Exit => AppContext::Exit,
|
||||
AppInstruction::Error(_) => AppContext::Error,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
//! Definition of the actions that can be bound to keys.
|
||||
|
||||
use super::handler;
|
||||
//use super::macros;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zellij_tile::data::InputMode;
|
||||
|
||||
/// The four directions (left, right, up, down).
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
|
|
@ -21,7 +20,7 @@ pub enum Action {
|
|||
/// Write to the terminal.
|
||||
Write(Vec<u8>),
|
||||
/// Switch to the specified input mode.
|
||||
SwitchToMode(handler::InputMode),
|
||||
SwitchToMode(InputMode),
|
||||
/// Resize focus pane in specified direction.
|
||||
Resize(Direction),
|
||||
/// Switch focus to next pane in specified direction.
|
||||
|
|
@ -51,5 +50,4 @@ pub enum Action {
|
|||
CloseTab,
|
||||
GoToTab(u32),
|
||||
TabNameInput(Vec<u8>),
|
||||
SaveTabName,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,17 +3,16 @@
|
|||
use super::actions::Action;
|
||||
use super::keybinds::Keybinds;
|
||||
use crate::common::input::config::Config;
|
||||
use crate::common::{update_state, AppInstruction, AppState, SenderWithContext, OPENCALLS};
|
||||
use crate::common::{AppInstruction, SenderWithContext, OPENCALLS};
|
||||
use crate::errors::ContextType;
|
||||
use crate::os_input_output::OsApi;
|
||||
use crate::pty_bus::PtyInstruction;
|
||||
use crate::screen::ScreenInstruction;
|
||||
use crate::wasm_vm::{EventType, PluginInputType, PluginInstruction};
|
||||
use crate::wasm_vm::PluginInstruction;
|
||||
use crate::CommandIsExecuting;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumIter;
|
||||
use termion::input::TermReadEventsAndRaw;
|
||||
use termion::input::{TermRead, TermReadEventsAndRaw};
|
||||
use zellij_tile::data::{Event, InputMode, Key, ModeInfo};
|
||||
|
||||
/// Handles the dispatching of [`Action`]s according to the current
|
||||
/// [`InputMode`], and keep tracks of the current [`InputMode`].
|
||||
|
|
@ -64,27 +63,22 @@ impl InputHandler {
|
|||
'input_loop: loop {
|
||||
//@@@ I think this should actually just iterate over stdin directly
|
||||
let stdin_buffer = self.os_input.read_from_stdin();
|
||||
drop(
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
|
||||
);
|
||||
for key_result in stdin_buffer.events_and_raw() {
|
||||
match key_result {
|
||||
Ok((event, raw_bytes)) => match event {
|
||||
termion::event::Event::Key(key) => {
|
||||
let key = cast_termion_key(key);
|
||||
// FIXME this explicit break is needed because the current test
|
||||
// framework relies on it to not create dead threads that loop
|
||||
// and eat up CPUs. Do not remove until the test framework has
|
||||
// been revised. Sorry about this (@categorille)
|
||||
if {
|
||||
let mut should_break = false;
|
||||
for action in
|
||||
Keybinds::key_to_actions(&key, raw_bytes, &self.mode, &keybinds)
|
||||
{
|
||||
should_break |= self.dispatch_action(action);
|
||||
}
|
||||
should_break
|
||||
} {
|
||||
let mut should_break = false;
|
||||
for action in
|
||||
Keybinds::key_to_actions(&key, raw_bytes, &self.mode, &keybinds)
|
||||
{
|
||||
should_break |= self.dispatch_action(action);
|
||||
}
|
||||
if should_break {
|
||||
break 'input_loop;
|
||||
}
|
||||
}
|
||||
|
|
@ -127,9 +121,15 @@ impl InputHandler {
|
|||
}
|
||||
Action::SwitchToMode(mode) => {
|
||||
self.mode = mode;
|
||||
update_state(&self.send_app_instructions, |_| AppState {
|
||||
input_mode: self.mode,
|
||||
});
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Update(
|
||||
None,
|
||||
Event::ModeUpdate(get_mode_info(mode)),
|
||||
))
|
||||
.unwrap();
|
||||
self.send_screen_instructions
|
||||
.send(ScreenInstruction::ChangeInputMode(mode))
|
||||
.unwrap();
|
||||
self.send_screen_instructions
|
||||
.send(ScreenInstruction::Render)
|
||||
.unwrap();
|
||||
|
|
@ -230,27 +230,10 @@ impl InputHandler {
|
|||
.unwrap();
|
||||
}
|
||||
Action::TabNameInput(c) => {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Input(
|
||||
PluginInputType::Event(EventType::Tab),
|
||||
c.clone(),
|
||||
))
|
||||
.unwrap();
|
||||
self.send_screen_instructions
|
||||
.send(ScreenInstruction::UpdateTabName(c))
|
||||
.unwrap();
|
||||
}
|
||||
Action::SaveTabName => {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Input(
|
||||
PluginInputType::Event(EventType::Tab),
|
||||
vec![b'\n'],
|
||||
))
|
||||
.unwrap();
|
||||
self.send_screen_instructions
|
||||
.send(ScreenInstruction::UpdateTabName(vec![b'\n']))
|
||||
.unwrap();
|
||||
}
|
||||
Action::NoOp => {}
|
||||
}
|
||||
|
||||
|
|
@ -266,52 +249,10 @@ impl InputHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/// Describes the different input modes, which change the way that keystrokes will be interpreted.
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, EnumIter, Serialize, Deserialize)]
|
||||
pub enum InputMode {
|
||||
/// In `Normal` mode, input is always written to the terminal, except for the shortcuts leading
|
||||
/// to other modes
|
||||
#[serde(alias = "normal")]
|
||||
Normal,
|
||||
/// In `Locked` mode, input is always written to the terminal and all shortcuts are disabled
|
||||
/// except the one leading back to normal mode
|
||||
#[serde(alias = "locked")]
|
||||
Locked,
|
||||
/// `Resize` mode allows resizing the different existing panes.
|
||||
#[serde(alias = "resize")]
|
||||
Resize,
|
||||
/// `Pane` mode allows creating and closing panes, as well as moving between them.
|
||||
#[serde(alias = "pane")]
|
||||
Pane,
|
||||
/// `Tab` mode allows creating and closing tabs, as well as moving between them.
|
||||
#[serde(alias = "tab")]
|
||||
Tab,
|
||||
/// `Scroll` mode allows scrolling up and down within a pane.
|
||||
#[serde(alias = "scroll")]
|
||||
Scroll,
|
||||
#[serde(alias = "renametab")]
|
||||
RenameTab,
|
||||
}
|
||||
|
||||
/// Represents the contents of the help message that is printed in the status bar,
|
||||
/// which indicates the current [`InputMode`] and what the keybinds for that mode
|
||||
/// are. Related to the default `status-bar` plugin.
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Help {
|
||||
pub mode: InputMode,
|
||||
pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description>
|
||||
}
|
||||
|
||||
impl Default for InputMode {
|
||||
fn default() -> InputMode {
|
||||
InputMode::Normal
|
||||
}
|
||||
}
|
||||
|
||||
/// 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_help(mode: InputMode) -> Help {
|
||||
pub fn get_mode_info(mode: InputMode) -> ModeInfo {
|
||||
let mut keybinds: Vec<(String, String)> = vec![];
|
||||
match mode {
|
||||
InputMode::Normal | InputMode::Locked => {}
|
||||
|
|
@ -340,7 +281,7 @@ pub fn get_help(mode: InputMode) -> Help {
|
|||
keybinds.push(("Enter".to_string(), "when done".to_string()));
|
||||
}
|
||||
}
|
||||
Help { mode, keybinds }
|
||||
ModeInfo { mode, keybinds }
|
||||
}
|
||||
|
||||
/// Entry point to the module. Instantiates an [`InputHandler`] and starts
|
||||
|
|
@ -365,3 +306,35 @@ pub fn input_loop(
|
|||
)
|
||||
.handle_input();
|
||||
}
|
||||
|
||||
pub fn parse_keys(input_bytes: &[u8]) -> Vec<Key> {
|
||||
input_bytes.keys().flatten().map(cast_termion_key).collect()
|
||||
}
|
||||
|
||||
// FIXME: This is an absolutely cursed function that should be destroyed as soon
|
||||
// as an alternative that doesn't touch zellij-tile can be developed...
|
||||
fn cast_termion_key(event: termion::event::Key) -> Key {
|
||||
match event {
|
||||
termion::event::Key::Backspace => Key::Backspace,
|
||||
termion::event::Key::Left => Key::Left,
|
||||
termion::event::Key::Right => Key::Right,
|
||||
termion::event::Key::Up => Key::Up,
|
||||
termion::event::Key::Down => Key::Down,
|
||||
termion::event::Key::Home => Key::Home,
|
||||
termion::event::Key::End => Key::End,
|
||||
termion::event::Key::PageUp => Key::PageUp,
|
||||
termion::event::Key::PageDown => Key::PageDown,
|
||||
termion::event::Key::BackTab => Key::BackTab,
|
||||
termion::event::Key::Delete => Key::Delete,
|
||||
termion::event::Key::Insert => Key::Insert,
|
||||
termion::event::Key::F(n) => Key::F(n),
|
||||
termion::event::Key::Char(c) => Key::Char(c),
|
||||
termion::event::Key::Alt(c) => Key::Alt(c),
|
||||
termion::event::Key::Ctrl(c) => Key::Ctrl(c),
|
||||
termion::event::Key::Null => Key::Null,
|
||||
termion::event::Key::Esc => Key::Esc,
|
||||
_ => {
|
||||
unimplemented!("Encountered an unknown key!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::actions::{Action, Direction};
|
||||
use super::handler::InputMode;
|
||||
|
||||
use serde::Deserialize;
|
||||
use strum::IntoEnumIterator;
|
||||
use termion::event::Key;
|
||||
use zellij_tile::data::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Keybinds(HashMap<InputMode, ModeKeybinds>);
|
||||
|
|
@ -275,10 +274,7 @@ impl Keybinds {
|
|||
defaults.insert(Key::Up, vec![Action::ScrollUp]);
|
||||
}
|
||||
InputMode::RenameTab => {
|
||||
defaults.insert(
|
||||
Key::Char('\n'),
|
||||
vec![Action::SaveTabName, Action::SwitchToMode(InputMode::Tab)],
|
||||
);
|
||||
defaults.insert(Key::Char('\n'), vec![Action::SwitchToMode(InputMode::Tab)]);
|
||||
defaults.insert(
|
||||
Key::Ctrl('g'),
|
||||
vec![Action::SwitchToMode(InputMode::Normal)],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use super::super::actions::*;
|
||||
use super::super::keybinds::*;
|
||||
use termion::event::Key;
|
||||
use zellij_tile::data::Key;
|
||||
|
||||
#[test]
|
||||
fn merge_keybinds_merges_different_keys() {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
|
||||
type SessionID = u64;
|
||||
type SessionId = u64;
|
||||
|
||||
#[derive(PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||
pub struct Session {
|
||||
// Unique ID for this session
|
||||
id: SessionID,
|
||||
id: SessionId,
|
||||
// Identifier for the underlying IPC primitive (socket, pipe)
|
||||
conn_name: String,
|
||||
// User configured alias for the session
|
||||
|
|
@ -30,9 +30,9 @@ pub enum ClientToServerMsg {
|
|||
// Create a new session
|
||||
CreateSession,
|
||||
// Attach to a running session
|
||||
AttachToSession(SessionID, ClientType),
|
||||
AttachToSession(SessionId, ClientType),
|
||||
// Force detach
|
||||
DetachSession(SessionID),
|
||||
DetachSession(SessionId),
|
||||
// Disconnect from the session we're connected to
|
||||
DisconnectFromSession,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,35 +9,36 @@ pub mod screen;
|
|||
pub mod utils;
|
||||
pub mod wasm_vm;
|
||||
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::cell::RefCell;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::{cell::RefCell, sync::mpsc::TrySendError};
|
||||
use std::{collections::HashMap, fs};
|
||||
|
||||
use crate::panes::PaneId;
|
||||
use directories_next::ProjectDirs;
|
||||
use input::handler::InputMode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use termion::input::TermRead;
|
||||
use wasm_vm::PluginEnv;
|
||||
use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value};
|
||||
use wasmer_wasi::{Pipe, WasiState};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
io::Write,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use crate::cli::CliArgs;
|
||||
use crate::common::input::config::Config;
|
||||
use crate::layout::Layout;
|
||||
use crate::panes::PaneId;
|
||||
use command_is_executing::CommandIsExecuting;
|
||||
use directories_next::ProjectDirs;
|
||||
use errors::{AppContext, ContextType, ErrorContext, PluginContext, PtyContext, ScreenContext};
|
||||
use input::handler::input_loop;
|
||||
use os_input_output::OsApi;
|
||||
use pty_bus::{PtyBus, PtyInstruction};
|
||||
use screen::{Screen, ScreenInstruction};
|
||||
use utils::consts::{ZELLIJ_IPC_PIPE, ZELLIJ_ROOT_PLUGIN_DIR};
|
||||
use wasm_vm::{
|
||||
wasi_stdout, wasi_write_string, zellij_imports, EventType, PluginInputType, PluginInstruction,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utils::consts::ZELLIJ_IPC_PIPE;
|
||||
use wasm_vm::PluginEnv;
|
||||
use wasm_vm::{wasi_stdout, wasi_write_string, zellij_imports, PluginInstruction};
|
||||
use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value};
|
||||
use wasmer_wasi::{Pipe, WasiState};
|
||||
use zellij_tile::data::{EventType, InputMode};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum ApiCommand {
|
||||
|
|
@ -46,33 +47,6 @@ pub enum ApiCommand {
|
|||
SplitVertically,
|
||||
MoveFocus,
|
||||
}
|
||||
// FIXME: It would be good to add some more things to this over time
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AppState {
|
||||
pub input_mode: InputMode,
|
||||
}
|
||||
|
||||
impl Default for AppState {
|
||||
fn default() -> Self {
|
||||
AppState {
|
||||
input_mode: InputMode::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Make this a method on the big `Communication` struct, so that app_tx can be extracted
|
||||
// from self instead of being explicitly passed here
|
||||
pub fn update_state(
|
||||
app_tx: &SenderWithContext<AppInstruction>,
|
||||
update_fn: impl FnOnce(AppState) -> AppState,
|
||||
) {
|
||||
let (state_tx, state_rx) = mpsc::channel();
|
||||
|
||||
drop(app_tx.send(AppInstruction::GetState(state_tx)));
|
||||
let state = state_rx.recv().unwrap();
|
||||
|
||||
drop(app_tx.send(AppInstruction::SetState(update_fn(state))))
|
||||
}
|
||||
|
||||
/// An [MPSC](mpsc) asynchronous channel with added error context.
|
||||
pub type ChannelWithContext<T> = (
|
||||
|
|
@ -116,19 +90,6 @@ impl<T: Clone> SenderWithContext<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Attempts to send an event on this sender's channel, terminating instead of blocking
|
||||
/// if the event could not be sent (buffer full or connection closed).
|
||||
///
|
||||
/// This can only be called on [`SyncSender`](SenderType::SyncSender)s, and will
|
||||
/// panic if called on an asynchronous [`Sender`](SenderType::Sender).
|
||||
pub fn try_send(&self, event: T) -> Result<(), TrySendError<(T, ErrorContext)>> {
|
||||
if let SenderType::SyncSender(ref s) = self.sender {
|
||||
s.try_send((event, self.err_ctx))
|
||||
} else {
|
||||
panic!("try_send can only be called on SyncSenders!")
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates this [`SenderWithContext`]'s [`ErrorContext`]. This is the way one adds
|
||||
/// a call to the error context.
|
||||
///
|
||||
|
|
@ -151,8 +112,6 @@ thread_local!(
|
|||
/// Instructions related to the entire application.
|
||||
#[derive(Clone)]
|
||||
pub enum AppInstruction {
|
||||
GetState(mpsc::Sender<AppState>),
|
||||
SetState(AppState),
|
||||
Exit,
|
||||
Error(String),
|
||||
}
|
||||
|
|
@ -167,8 +126,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
.write(take_snapshot.as_bytes())
|
||||
.unwrap();
|
||||
|
||||
let mut app_state = AppState::default();
|
||||
|
||||
let config = Config::from_cli_config(opts.config)
|
||||
.map_err(|e| {
|
||||
eprintln!("There was an error in the config file:\n{}", e);
|
||||
|
|
@ -307,6 +264,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
&full_screen_ws,
|
||||
os_input,
|
||||
max_panes,
|
||||
InputMode::Normal,
|
||||
);
|
||||
loop {
|
||||
let (event, mut err_ctx) = screen
|
||||
|
|
@ -398,8 +356,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
.get_active_tab_mut()
|
||||
.unwrap()
|
||||
.set_pane_selectable(id, selectable);
|
||||
// FIXME: Is this needed?
|
||||
screen.render();
|
||||
}
|
||||
ScreenInstruction::SetMaxHeight(id, max_height) => {
|
||||
screen
|
||||
|
|
@ -441,6 +397,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
ScreenInstruction::UpdateTabName(c) => {
|
||||
screen.update_active_tab_name(c);
|
||||
}
|
||||
ScreenInstruction::ChangeInputMode(input_mode) => {
|
||||
screen.change_input_mode(input_mode);
|
||||
}
|
||||
ScreenInstruction::Quit => {
|
||||
break;
|
||||
}
|
||||
|
|
@ -460,12 +419,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
let store = Store::default();
|
||||
let mut plugin_id = 0;
|
||||
let mut plugin_map = HashMap::new();
|
||||
let handler_map: HashMap<EventType, String> =
|
||||
[(EventType::Tab, "handle_tab_rename_keypress".to_string())]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
move || loop {
|
||||
let (event, mut err_ctx) = receive_plugin_instructions
|
||||
.recv()
|
||||
|
|
@ -475,18 +428,13 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
send_pty_instructions.update(err_ctx);
|
||||
send_app_instructions.update(err_ctx);
|
||||
match event {
|
||||
PluginInstruction::Load(pid_tx, path, events) => {
|
||||
PluginInstruction::Load(pid_tx, path) => {
|
||||
let project_dirs =
|
||||
ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap();
|
||||
let plugin_dir = project_dirs.data_dir().join("plugins/");
|
||||
// FIXME: This really shouldn't need to exist anymore, let's get rid of it!
|
||||
let root_plugin_dir = Path::new(ZELLIJ_ROOT_PLUGIN_DIR);
|
||||
let wasm_bytes = fs::read(&path)
|
||||
.or_else(|_| fs::read(&path.with_extension("wasm")))
|
||||
.or_else(|_| fs::read(&plugin_dir.join(&path).with_extension("wasm")))
|
||||
.or_else(|_| {
|
||||
fs::read(&root_plugin_dir.join(&path).with_extension("wasm"))
|
||||
})
|
||||
.unwrap_or_else(|_| panic!("cannot find plugin {}", &path.display()));
|
||||
|
||||
// FIXME: Cache this compiled module on disk. I could use `(de)serialize_to_file()` for that
|
||||
|
|
@ -517,7 +465,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
send_screen_instructions: send_screen_instructions.clone(),
|
||||
send_app_instructions: send_app_instructions.clone(),
|
||||
wasi_env,
|
||||
events,
|
||||
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
||||
};
|
||||
|
||||
let zellij = zellij_imports(&store, &plugin_env);
|
||||
|
|
@ -532,88 +480,33 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
pid_tx.send(plugin_id).unwrap();
|
||||
plugin_id += 1;
|
||||
}
|
||||
PluginInstruction::Draw(buf_tx, pid, rows, cols) => {
|
||||
PluginInstruction::Update(pid, event) => {
|
||||
for (&i, (instance, plugin_env)) in &plugin_map {
|
||||
let subs = plugin_env.subscriptions.lock().unwrap();
|
||||
// FIXME: This is very janky... Maybe I should write my own macro for Event -> EventType?
|
||||
let event_type = EventType::from_str(&event.to_string()).unwrap();
|
||||
if (pid.is_none() || pid == Some(i)) && subs.contains(&event_type) {
|
||||
let update = instance.exports.get_function("update").unwrap();
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&event).unwrap(),
|
||||
);
|
||||
update.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::Render(buf_tx, pid, rows, cols) => {
|
||||
let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
|
||||
|
||||
let draw = instance.exports.get_function("draw").unwrap();
|
||||
let render = instance.exports.get_function("render").unwrap();
|
||||
|
||||
draw.call(&[Value::I32(rows as i32), Value::I32(cols as i32)])
|
||||
render
|
||||
.call(&[Value::I32(rows as i32), Value::I32(cols as i32)])
|
||||
.unwrap();
|
||||
|
||||
buf_tx.send(wasi_stdout(&plugin_env.wasi_env)).unwrap();
|
||||
}
|
||||
PluginInstruction::UpdateTabs(mut tabs) => {
|
||||
for (instance, plugin_env) in plugin_map.values() {
|
||||
if !plugin_env.events.contains(&EventType::Tab) {
|
||||
continue;
|
||||
}
|
||||
let handler = instance.exports.get_function("update_tabs").unwrap();
|
||||
tabs.sort_by(|a, b| a.position.cmp(&b.position));
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&tabs).unwrap(),
|
||||
);
|
||||
handler.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
// FIXME: Deduplicate this with the callback below!
|
||||
PluginInstruction::Input(input_type, input_bytes) => {
|
||||
match input_type {
|
||||
PluginInputType::Normal(pid) => {
|
||||
let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
|
||||
let handle_key =
|
||||
instance.exports.get_function("handle_key").unwrap();
|
||||
for key in input_bytes.keys() {
|
||||
if let Ok(key) = key {
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&key).unwrap(),
|
||||
);
|
||||
handle_key.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
PluginInputType::Event(event) => {
|
||||
for (instance, plugin_env) in plugin_map.values() {
|
||||
if !plugin_env.events.contains(&event) {
|
||||
continue;
|
||||
}
|
||||
let handle_key = instance
|
||||
.exports
|
||||
.get_function(handler_map.get(&event).unwrap())
|
||||
.unwrap();
|
||||
for key in input_bytes.keys() {
|
||||
if let Ok(key) = key {
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&key).unwrap(),
|
||||
);
|
||||
handle_key.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::GlobalInput(input_bytes) => {
|
||||
// FIXME: Set up an event subscription system, and timed callbacks
|
||||
for (instance, plugin_env) in plugin_map.values() {
|
||||
let handler =
|
||||
instance.exports.get_function("handle_global_key").unwrap();
|
||||
for key in input_bytes.keys() {
|
||||
if let Ok(key) = key {
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&key).unwrap(),
|
||||
);
|
||||
handler.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::Unload(pid) => drop(plugin_map.remove(&pid)),
|
||||
PluginInstruction::Quit => break,
|
||||
}
|
||||
|
|
@ -636,7 +529,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
let listener = std::os::unix::net::UnixListener::bind(ZELLIJ_IPC_PIPE)
|
||||
.expect("could not listen on ipc socket");
|
||||
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
|
||||
err_ctx.add_call(ContextType::IPCServer);
|
||||
err_ctx.add_call(ContextType::IpcServer);
|
||||
send_pty_instructions.update(err_ctx);
|
||||
send_screen_instructions.update(err_ctx);
|
||||
|
||||
|
|
@ -713,8 +606,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
|||
send_screen_instructions.update(err_ctx);
|
||||
send_pty_instructions.update(err_ctx);
|
||||
match app_instruction {
|
||||
AppInstruction::GetState(state_tx) => drop(state_tx.send(app_state.clone())),
|
||||
AppInstruction::SetState(state) => app_state = state,
|
||||
AppInstruction::Exit => {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,15 +82,10 @@ fn handle_command_exit(mut child: Child) {
|
|||
}
|
||||
|
||||
for signal in signals.pending() {
|
||||
// FIXME: We need to handle more signals here!
|
||||
#[allow(clippy::single_match)]
|
||||
match signal {
|
||||
signal_hook::SIGINT => {
|
||||
child.kill().unwrap();
|
||||
child.wait().unwrap();
|
||||
break 'handle_exit;
|
||||
}
|
||||
_ => {}
|
||||
if signal == signal_hook::SIGINT {
|
||||
child.kill().unwrap();
|
||||
child.wait().unwrap();
|
||||
break 'handle_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,12 @@ use super::{AppInstruction, SenderWithContext};
|
|||
use crate::os_input_output::OsApi;
|
||||
use crate::panes::PositionAndSize;
|
||||
use crate::pty_bus::{PtyInstruction, VteEvent};
|
||||
use crate::tab::{Tab, TabData};
|
||||
use crate::tab::Tab;
|
||||
use crate::{errors::ErrorContext, wasm_vm::PluginInstruction};
|
||||
use crate::{layout::Layout, panes::PaneId};
|
||||
|
||||
use zellij_tile::data::{Event, InputMode, TabInfo};
|
||||
|
||||
/// Instructions that can be sent to the [`Screen`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ScreenInstruction {
|
||||
|
|
@ -48,6 +50,7 @@ pub enum ScreenInstruction {
|
|||
CloseTab,
|
||||
GoToTab(u32),
|
||||
UpdateTabName(Vec<u8>),
|
||||
ChangeInputMode(InputMode),
|
||||
}
|
||||
|
||||
/// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes).
|
||||
|
|
@ -71,7 +74,7 @@ pub struct Screen {
|
|||
active_tab_index: Option<usize>,
|
||||
/// The [`OsApi`] this [`Screen`] uses.
|
||||
os_api: Box<dyn OsApi>,
|
||||
tabname_buf: String,
|
||||
input_mode: InputMode,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
|
|
@ -84,6 +87,7 @@ impl Screen {
|
|||
full_screen_ws: &PositionAndSize,
|
||||
os_api: Box<dyn OsApi>,
|
||||
max_panes: Option<usize>,
|
||||
input_mode: InputMode,
|
||||
) -> Self {
|
||||
Screen {
|
||||
receiver: receive_screen_instructions,
|
||||
|
|
@ -95,7 +99,7 @@ impl Screen {
|
|||
active_tab_index: None,
|
||||
tabs: BTreeMap::new(),
|
||||
os_api,
|
||||
tabname_buf: String::new(),
|
||||
input_mode,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +119,7 @@ impl Screen {
|
|||
self.send_app_instructions.clone(),
|
||||
self.max_panes,
|
||||
Some(PaneId::Terminal(pane_id)),
|
||||
self.input_mode,
|
||||
);
|
||||
self.active_tab_index = Some(tab_index);
|
||||
self.tabs.insert(tab_index, tab);
|
||||
|
|
@ -169,15 +174,12 @@ impl Screen {
|
|||
pub fn go_to_tab(&mut self, mut tab_index: usize) {
|
||||
tab_index -= 1;
|
||||
let active_tab = self.get_active_tab().unwrap();
|
||||
match self.tabs.values().find(|t| t.position == tab_index) {
|
||||
Some(t) => {
|
||||
if t.index != active_tab.index {
|
||||
self.active_tab_index = Some(t.index);
|
||||
self.update_tabs();
|
||||
self.render();
|
||||
}
|
||||
if let Some(t) = self.tabs.values().find(|t| t.position == tab_index) {
|
||||
if t.index != active_tab.index {
|
||||
self.active_tab_index = Some(t.index);
|
||||
self.update_tabs();
|
||||
self.render();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -259,6 +261,7 @@ impl Screen {
|
|||
self.send_app_instructions.clone(),
|
||||
self.max_panes,
|
||||
None,
|
||||
self.input_mode,
|
||||
);
|
||||
tab.apply_layout(layout, new_pids);
|
||||
self.active_tab_index = Some(tab_index);
|
||||
|
|
@ -270,33 +273,38 @@ impl Screen {
|
|||
let mut tab_data = vec![];
|
||||
let active_tab_index = self.active_tab_index.unwrap();
|
||||
for tab in self.tabs.values() {
|
||||
tab_data.push(TabData {
|
||||
tab_data.push(TabInfo {
|
||||
position: tab.position,
|
||||
name: tab.name.clone(),
|
||||
active: active_tab_index == tab.index,
|
||||
});
|
||||
}
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::UpdateTabs(tab_data))
|
||||
.send(PluginInstruction::Update(None, Event::TabUpdate(tab_data)))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn update_active_tab_name(&mut self, buf: Vec<u8>) {
|
||||
let s = str::from_utf8(&buf).unwrap();
|
||||
let active_tab = self.get_active_tab_mut().unwrap();
|
||||
match s {
|
||||
"\0" => {
|
||||
self.tabname_buf = String::new();
|
||||
active_tab.name = String::new();
|
||||
}
|
||||
"\n" => {
|
||||
let new_name = self.tabname_buf.clone();
|
||||
let active_tab = self.get_active_tab_mut().unwrap();
|
||||
active_tab.name = new_name;
|
||||
self.update_tabs();
|
||||
self.render();
|
||||
"\u{007F}" | "\u{0008}" => {
|
||||
//delete and backspace keys
|
||||
active_tab.name.pop();
|
||||
}
|
||||
c => {
|
||||
self.tabname_buf.push_str(c);
|
||||
active_tab.name.push_str(c);
|
||||
}
|
||||
}
|
||||
self.update_tabs();
|
||||
}
|
||||
pub fn change_input_mode(&mut self, input_mode: InputMode) {
|
||||
self.input_mode = input_mode;
|
||||
for tab in self.tabs.values_mut() {
|
||||
tab.input_mode = self.input_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,3 @@ pub const ZELLIJ_TMP_DIR: &str = "/tmp/zellij";
|
|||
pub const ZELLIJ_TMP_LOG_DIR: &str = "/tmp/zellij/zellij-log";
|
||||
pub const ZELLIJ_TMP_LOG_FILE: &str = "/tmp/zellij/zellij-log/log.txt";
|
||||
pub const ZELLIJ_IPC_PIPE: &str = "/tmp/zellij/ipc";
|
||||
pub const ZELLIJ_ROOT_PLUGIN_DIR: &str = "/usr/share/zellij/plugins";
|
||||
pub const ZELLIJ_ROOT_LAYOUT_DIR: &str = "/usr/share/zellij/layouts";
|
||||
|
|
|
|||
|
|
@ -1,36 +1,22 @@
|
|||
use crate::tab::TabData;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::PathBuf,
|
||||
sync::mpsc::{channel, Sender},
|
||||
sync::{mpsc::Sender, Arc, Mutex},
|
||||
};
|
||||
use wasmer::{imports, Function, ImportObject, Store, WasmerEnv};
|
||||
use wasmer_wasi::WasiEnv;
|
||||
use zellij_tile::data::{Event, EventType};
|
||||
|
||||
use super::{
|
||||
input::handler::get_help, pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction,
|
||||
PaneId, SenderWithContext,
|
||||
pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction, PaneId, SenderWithContext,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Hash, Eq, Serialize, Deserialize)]
|
||||
pub enum EventType {
|
||||
Tab,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PluginInputType {
|
||||
Normal(u32),
|
||||
Event(EventType),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PluginInstruction {
|
||||
Load(Sender<u32>, PathBuf, Vec<EventType>),
|
||||
Draw(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
||||
Input(PluginInputType, Vec<u8>), // plugin id, input bytes
|
||||
GlobalInput(Vec<u8>), // input bytes
|
||||
Load(Sender<u32>, PathBuf),
|
||||
Update(Option<u32>, Event), // Focused plugin / broadcast, event data
|
||||
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
||||
Unload(u32),
|
||||
UpdateTabs(Vec<TabData>), // num tabs, active tab
|
||||
Quit,
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +27,7 @@ pub struct PluginEnv {
|
|||
pub send_app_instructions: SenderWithContext<AppInstruction>,
|
||||
pub send_pty_instructions: SenderWithContext<PtyInstruction>, // FIXME: This should be a big bundle of all of the channels
|
||||
pub wasi_env: WasiEnv,
|
||||
pub events: Vec<EventType>,
|
||||
pub subscriptions: Arc<Mutex<HashSet<EventType>>>,
|
||||
}
|
||||
|
||||
// Plugin API ---------------------------------------------------------------------------------------------------------
|
||||
|
|
@ -49,16 +35,28 @@ pub struct PluginEnv {
|
|||
pub fn zellij_imports(store: &Store, plugin_env: &PluginEnv) -> ImportObject {
|
||||
imports! {
|
||||
"zellij" => {
|
||||
"host_subscribe" => Function::new_native_with_env(store, plugin_env.clone(), host_subscribe),
|
||||
"host_unsubscribe" => Function::new_native_with_env(store, plugin_env.clone(), host_unsubscribe),
|
||||
"host_open_file" => Function::new_native_with_env(store, plugin_env.clone(), host_open_file),
|
||||
"host_set_invisible_borders" => Function::new_native_with_env(store, plugin_env.clone(), host_set_invisible_borders),
|
||||
"host_set_max_height" => Function::new_native_with_env(store, plugin_env.clone(), host_set_max_height),
|
||||
"host_set_selectable" => Function::new_native_with_env(store, plugin_env.clone(), host_set_selectable),
|
||||
"host_get_help" => Function::new_native_with_env(store, plugin_env.clone(), host_get_help),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Bundle up all of the channels! Pair that with WasiEnv?
|
||||
fn host_subscribe(plugin_env: &PluginEnv) {
|
||||
let mut subscriptions = plugin_env.subscriptions.lock().unwrap();
|
||||
let new: HashSet<EventType> = serde_json::from_str(&wasi_stdout(&plugin_env.wasi_env)).unwrap();
|
||||
subscriptions.extend(new);
|
||||
}
|
||||
|
||||
fn host_unsubscribe(plugin_env: &PluginEnv) {
|
||||
let mut subscriptions = plugin_env.subscriptions.lock().unwrap();
|
||||
let old: HashSet<EventType> = serde_json::from_str(&wasi_stdout(&plugin_env.wasi_env)).unwrap();
|
||||
subscriptions.retain(|k| !old.contains(k));
|
||||
}
|
||||
|
||||
fn host_open_file(plugin_env: &PluginEnv) {
|
||||
let path = PathBuf::from(wasi_stdout(&plugin_env.wasi_env).lines().next().unwrap());
|
||||
plugin_env
|
||||
|
|
@ -67,7 +65,6 @@ fn host_open_file(plugin_env: &PluginEnv) {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
// FIXME: Think about these naming conventions – should everything be prefixed by 'host'?
|
||||
fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) {
|
||||
let selectable = selectable != 0;
|
||||
plugin_env
|
||||
|
|
@ -101,21 +98,6 @@ fn host_set_invisible_borders(plugin_env: &PluginEnv, invisible_borders: i32) {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
fn host_get_help(plugin_env: &PluginEnv) {
|
||||
let (state_tx, state_rx) = channel();
|
||||
// FIXME: If I changed the application so that threads were sent the termination
|
||||
// signal and joined one at a time, there would be an order to shutdown, so I
|
||||
// could get rid of this .is_ok() check and the .try_send()
|
||||
if plugin_env
|
||||
.send_app_instructions
|
||||
.try_send(AppInstruction::GetState(state_tx))
|
||||
.is_ok()
|
||||
{
|
||||
let help = get_help(state_rx.recv().unwrap().input_mode);
|
||||
wasi_write_string(&plugin_env.wasi_env, &serde_json::to_string(&help).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
// Helper Functions ---------------------------------------------------------------------------------------------------
|
||||
|
||||
// FIXME: Unwrap city
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ use std::time::{Duration, Instant};
|
|||
use crate::os_input_output::OsApi;
|
||||
use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes};
|
||||
|
||||
use crate::tests::utils::commands::SLEEP;
|
||||
|
||||
const MIN_TIME_BETWEEN_SNAPSHOTS: Duration = Duration::from_millis(50);
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -189,11 +191,16 @@ impl OsApi for FakeInputOutput {
|
|||
::std::thread::sleep(MIN_TIME_BETWEEN_SNAPSHOTS - last_snapshot_time.elapsed());
|
||||
}
|
||||
}
|
||||
self.stdin_commands
|
||||
let command = self
|
||||
.stdin_commands
|
||||
.lock()
|
||||
.unwrap()
|
||||
.pop_front()
|
||||
.unwrap_or(vec![])
|
||||
.unwrap_or(vec![]);
|
||||
if command == SLEEP {
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
}
|
||||
command
|
||||
}
|
||||
fn get_stdout_writer(&self) -> Box<dyn Write> {
|
||||
Box::new(self.stdout_writer.clone())
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::path::PathBuf;
|
|||
use crate::panes::PositionAndSize;
|
||||
use crate::tests::fakes::FakeInputOutput;
|
||||
use crate::tests::utils::commands::{
|
||||
PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_MODE, SPAWN_TERMINAL_IN_PANE_MODE,
|
||||
PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPAWN_TERMINAL_IN_PANE_MODE,
|
||||
TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE,
|
||||
};
|
||||
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
|
||||
|
|
@ -23,7 +23,12 @@ pub fn new_panes_are_open_inside_expansion_border() {
|
|||
y: 0,
|
||||
};
|
||||
let mut fake_input_output = get_fake_os_input(&fake_win_size);
|
||||
fake_input_output.add_terminal_input(&[&PANE_MODE, &SPAWN_TERMINAL_IN_PANE_MODE, &QUIT]);
|
||||
fake_input_output.add_terminal_input(&[
|
||||
&PANE_MODE,
|
||||
&SPAWN_TERMINAL_IN_PANE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
let mut opts = CliArgs::default();
|
||||
opts.layout = Some(PathBuf::from(
|
||||
"src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml",
|
||||
|
|
@ -55,6 +60,7 @@ pub fn resize_pane_inside_expansion_border() {
|
|||
&SPAWN_TERMINAL_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
let mut opts = CliArgs::default();
|
||||
|
|
@ -87,6 +93,7 @@ pub fn toggling_fullcsreen_in_expansion_border_expands_only_until_border() {
|
|||
&PANE_MODE,
|
||||
&SPAWN_TERMINAL_IN_PANE_MODE,
|
||||
&TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
let mut opts = CliArgs::default();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use crate::{start, CliArgs};
|
|||
|
||||
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, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||
RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE,
|
||||
SPLIT_RIGHT_IN_PANE_MODE,
|
||||
};
|
||||
|
||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||
|
|
@ -37,6 +38,7 @@ pub fn resize_down_with_pane_above() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -75,6 +77,7 @@ pub fn resize_down_with_pane_below() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -118,6 +121,7 @@ pub fn resize_down_with_panes_above_and_below() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -160,6 +164,7 @@ pub fn resize_down_with_multiple_panes_above() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -205,6 +210,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -249,6 +255,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -291,6 +298,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -334,6 +342,7 @@ pub fn resize_down_with_panes_below_aligned_right_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -380,6 +389,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -428,6 +438,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -493,6 +504,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef
|
|||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -560,6 +572,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_
|
|||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -596,6 +609,7 @@ pub fn cannot_resize_down_when_pane_below_is_at_minimum_height() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_DOWN_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{start, CliArgs};
|
|||
|
||||
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, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||
RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||
};
|
||||
|
||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||
|
|
@ -34,6 +34,7 @@ pub fn resize_left_with_pane_to_the_left() {
|
|||
&SPLIT_RIGHT_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -70,6 +71,7 @@ pub fn resize_left_with_pane_to_the_right() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -108,6 +110,7 @@ pub fn resize_left_with_panes_to_the_left_and_right() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -148,6 +151,7 @@ pub fn resize_left_with_multiple_panes_to_the_left() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -191,6 +195,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -231,6 +236,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -273,6 +279,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -314,6 +321,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -360,6 +368,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa
|
|||
&SPLIT_RIGHT_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -408,6 +417,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -473,6 +483,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov
|
|||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -541,6 +552,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo
|
|||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -577,6 +589,7 @@ pub fn cannot_resize_left_when_pane_to_the_left_is_at_minimum_width() {
|
|||
&SPLIT_RIGHT_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{start, CliArgs};
|
|||
|
||||
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, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||
RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||
};
|
||||
|
||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||
|
|
@ -34,6 +34,7 @@ pub fn resize_right_with_pane_to_the_left() {
|
|||
&SPLIT_RIGHT_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -70,6 +71,7 @@ pub fn resize_right_with_pane_to_the_right() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -108,6 +110,7 @@ pub fn resize_right_with_panes_to_the_left_and_right() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -148,6 +151,7 @@ pub fn resize_right_with_multiple_panes_to_the_left() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -191,6 +195,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -231,6 +236,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -273,6 +279,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -314,6 +321,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -360,6 +368,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p
|
|||
&SPLIT_RIGHT_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -408,6 +417,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -473,6 +483,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo
|
|||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -540,6 +551,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab
|
|||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -576,6 +588,7 @@ pub fn cannot_resize_right_when_pane_to_the_left_is_at_minimum_width() {
|
|||
&SPLIT_RIGHT_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_RIGHT_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{start, CliArgs};
|
|||
|
||||
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, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||
RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
|
||||
};
|
||||
|
||||
fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput {
|
||||
|
|
@ -36,6 +36,7 @@ pub fn resize_up_with_pane_above() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -74,6 +75,7 @@ pub fn resize_up_with_pane_below() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -117,6 +119,7 @@ pub fn resize_up_with_panes_above_and_below() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
@ -158,6 +161,7 @@ pub fn resize_up_with_multiple_panes_above() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -201,6 +205,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -245,6 +250,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -287,6 +293,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -330,6 +337,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -376,6 +384,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -424,6 +433,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() {
|
|||
&MOVE_FOCUS_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -489,6 +499,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_
|
|||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -556,6 +567,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri
|
|||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_LEFT_IN_RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
|
||||
|
|
@ -592,6 +604,7 @@ pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() {
|
|||
&SPLIT_DOWN_IN_PANE_MODE,
|
||||
&RESIZE_MODE,
|
||||
&RESIZE_UP_IN_RESIZE_MODE,
|
||||
&SLEEP,
|
||||
&QUIT,
|
||||
]);
|
||||
start(Box::new(fake_input_output.clone()), CliArgs::default());
|
||||
|
|
|
|||
|
|
@ -76,4 +76,5 @@ pub mod commands {
|
|||
pub const SWITCH_NEXT_TAB_IN_TAB_MODE: [u8; 1] = [108]; // l
|
||||
pub const SWITCH_PREV_TAB_IN_TAB_MODE: [u8; 1] = [104]; // h
|
||||
pub const CLOSE_TAB_IN_TAB_MODE: [u8; 1] = [120]; // x
|
||||
pub const SLEEP: [u8; 0] = [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,3 +9,5 @@ license = "MIT"
|
|||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
strum = "0.20.0"
|
||||
strum_macros = "0.20.0"
|
||||
84
zellij-tile/src/data.rs
Normal file
84
zellij-tile/src/data.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{EnumDiscriminants, EnumIter, EnumString, ToString};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Key {
|
||||
Backspace,
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down,
|
||||
Home,
|
||||
End,
|
||||
PageUp,
|
||||
PageDown,
|
||||
BackTab,
|
||||
Delete,
|
||||
Insert,
|
||||
F(u8),
|
||||
Char(char),
|
||||
Alt(char),
|
||||
Ctrl(char),
|
||||
Null,
|
||||
Esc,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, EnumDiscriminants, ToString, Serialize, Deserialize)]
|
||||
#[strum_discriminants(derive(EnumString, Hash, Serialize, Deserialize))]
|
||||
#[strum_discriminants(name(EventType))]
|
||||
pub enum Event {
|
||||
ModeUpdate(ModeInfo),
|
||||
TabUpdate(Vec<TabInfo>),
|
||||
KeyPress(Key),
|
||||
}
|
||||
|
||||
/// Describes the different input modes, which change the way that keystrokes will be interpreted.
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, EnumIter, Serialize, Deserialize)]
|
||||
pub enum InputMode {
|
||||
/// In `Normal` mode, input is always written to the terminal, except for the shortcuts leading
|
||||
/// to other modes
|
||||
#[serde(alias = "normal")]
|
||||
Normal,
|
||||
/// In `Locked` mode, input is always written to the terminal and all shortcuts are disabled
|
||||
/// except the one leading back to normal mode
|
||||
#[serde(alias = "locked")]
|
||||
Locked,
|
||||
/// `Resize` mode allows resizing the different existing panes.
|
||||
#[serde(alias = "resize")]
|
||||
Resize,
|
||||
/// `Pane` mode allows creating and closing panes, as well as moving between them.
|
||||
#[serde(alias = "pane")]
|
||||
Pane,
|
||||
/// `Tab` mode allows creating and closing tabs, as well as moving between them.
|
||||
#[serde(alias = "tab")]
|
||||
Tab,
|
||||
/// `Scroll` mode allows scrolling up and down within a pane.
|
||||
#[serde(alias = "scroll")]
|
||||
Scroll,
|
||||
#[serde(alias = "renametab")]
|
||||
RenameTab,
|
||||
}
|
||||
|
||||
impl Default for InputMode {
|
||||
fn default() -> InputMode {
|
||||
InputMode::Normal
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the contents of the help message that is printed in the status bar,
|
||||
/// which indicates the current [`InputMode`] and what the keybinds for that mode
|
||||
/// are. Related to the default `status-bar` plugin.
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ModeInfo {
|
||||
pub mode: InputMode,
|
||||
// FIXME: This should probably return Keys and Actions, then sort out strings plugin-side
|
||||
pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description>
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
||||
pub struct TabInfo {
|
||||
/* subset of fields to publish to plugins */
|
||||
pub position: usize,
|
||||
pub name: String,
|
||||
pub active: bool,
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
mod shim;
|
||||
pub mod data;
|
||||
pub mod prelude;
|
||||
pub mod shim;
|
||||
|
||||
use data::*;
|
||||
|
||||
pub use shim::*;
|
||||
#[allow(unused_variables)]
|
||||
pub trait ZellijTile {
|
||||
fn init(&mut self) {}
|
||||
fn draw(&mut self, rows: usize, cols: usize) {}
|
||||
fn handle_key(&mut self, key: Key) {}
|
||||
fn handle_global_key(&mut self, key: Key) {}
|
||||
fn update_tabs(&mut self) {}
|
||||
fn handle_tab_rename_keypress(&mut self, key: Key) {}
|
||||
fn load(&mut self) {}
|
||||
fn update(&mut self, event: Event) {}
|
||||
fn render(&mut self, rows: usize, cols: usize) {}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
@ -20,45 +20,22 @@ macro_rules! register_tile {
|
|||
|
||||
fn main() {
|
||||
STATE.with(|state| {
|
||||
state.borrow_mut().init();
|
||||
state.borrow_mut().load();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn draw(rows: i32, cols: i32) {
|
||||
pub fn update() {
|
||||
STATE.with(|state| {
|
||||
state.borrow_mut().draw(rows as usize, cols as usize);
|
||||
state.borrow_mut().update($crate::shim::object_from_stdin());
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn handle_key() {
|
||||
pub fn render(rows: i32, cols: i32) {
|
||||
STATE.with(|state| {
|
||||
state.borrow_mut().handle_key($crate::get_key());
|
||||
state.borrow_mut().render(rows as usize, cols as usize);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn handle_global_key() {
|
||||
STATE.with(|state| {
|
||||
state.borrow_mut().handle_global_key($crate::get_key());
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn update_tabs() {
|
||||
STATE.with(|state| {
|
||||
state.borrow_mut().update_tabs();
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn handle_tab_rename_keypress() {
|
||||
STATE.with(|state| {
|
||||
state
|
||||
.borrow_mut()
|
||||
.handle_tab_rename_keypress($crate::get_key());
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
3
zellij-tile/src/prelude.rs
Normal file
3
zellij-tile/src/prelude.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub use crate::data::*;
|
||||
pub use crate::shim::*;
|
||||
pub use crate::*;
|
||||
|
|
@ -1,105 +1,56 @@
|
|||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{io, path::Path};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Key {
|
||||
Backspace,
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down,
|
||||
Home,
|
||||
End,
|
||||
PageUp,
|
||||
PageDown,
|
||||
BackTab,
|
||||
Delete,
|
||||
Insert,
|
||||
F(u8),
|
||||
Char(char),
|
||||
Alt(char),
|
||||
Ctrl(char),
|
||||
Null,
|
||||
Esc,
|
||||
use crate::data::*;
|
||||
|
||||
// Subscription Handling
|
||||
|
||||
pub fn subscribe(event_types: &[EventType]) {
|
||||
println!("{}", serde_json::to_string(event_types).unwrap());
|
||||
unsafe { host_subscribe() };
|
||||
}
|
||||
|
||||
// TODO: use same struct from main crate?
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Help {
|
||||
pub mode: InputMode,
|
||||
pub keybinds: Vec<(String, String)>,
|
||||
pub fn unsubscribe(event_types: &[EventType]) {
|
||||
println!("{}", serde_json::to_string(event_types).unwrap());
|
||||
unsafe { host_unsubscribe() };
|
||||
}
|
||||
|
||||
// TODO: use same struct from main crate?
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum InputMode {
|
||||
Normal,
|
||||
Locked,
|
||||
Resize,
|
||||
Pane,
|
||||
Tab,
|
||||
RenameTab,
|
||||
Scroll,
|
||||
Exiting,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct TabData {
|
||||
/* subset of fields to publish to plugins */
|
||||
pub position: usize,
|
||||
pub name: String,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
impl Default for InputMode {
|
||||
fn default() -> InputMode {
|
||||
InputMode::Normal
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_key() -> Key {
|
||||
deserialize_from_stdin().unwrap()
|
||||
}
|
||||
|
||||
pub fn open_file(path: &Path) {
|
||||
println!("{}", path.to_string_lossy());
|
||||
unsafe { host_open_file() };
|
||||
}
|
||||
// Plugin Settings
|
||||
|
||||
pub fn set_max_height(max_height: i32) {
|
||||
unsafe { host_set_max_height(max_height) };
|
||||
}
|
||||
|
||||
pub fn set_invisible_borders(invisible_borders: bool) {
|
||||
let invisible_borders = if invisible_borders { 1 } else { 0 };
|
||||
unsafe { host_set_invisible_borders(invisible_borders) };
|
||||
unsafe { host_set_invisible_borders(if invisible_borders { 1 } else { 0 }) };
|
||||
}
|
||||
|
||||
pub fn set_selectable(selectable: bool) {
|
||||
let selectable = if selectable { 1 } else { 0 };
|
||||
unsafe { host_set_selectable(selectable) };
|
||||
unsafe { host_set_selectable(if selectable { 1 } else { 0 }) };
|
||||
}
|
||||
|
||||
pub fn get_help() -> Help {
|
||||
unsafe { host_get_help() };
|
||||
deserialize_from_stdin().unwrap_or_default()
|
||||
// Host Functions
|
||||
|
||||
pub fn open_file(path: &Path) {
|
||||
println!("{}", path.to_string_lossy());
|
||||
unsafe { host_open_file() };
|
||||
}
|
||||
|
||||
pub fn get_tabs() -> Vec<TabData> {
|
||||
deserialize_from_stdin().unwrap_or_default()
|
||||
}
|
||||
// Internal Functions
|
||||
|
||||
fn deserialize_from_stdin<T: DeserializeOwned>() -> Option<T> {
|
||||
#[doc(hidden)]
|
||||
pub fn object_from_stdin<T: DeserializeOwned>() -> T {
|
||||
let mut json = String::new();
|
||||
io::stdin().read_line(&mut json).unwrap();
|
||||
serde_json::from_str(&json).ok()
|
||||
serde_json::from_str(&json).unwrap()
|
||||
}
|
||||
|
||||
#[link(wasm_import_module = "zellij")]
|
||||
extern "C" {
|
||||
fn host_subscribe();
|
||||
fn host_unsubscribe();
|
||||
fn host_open_file();
|
||||
fn host_set_max_height(max_height: i32);
|
||||
fn host_set_selectable(selectable: i32);
|
||||
fn host_set_invisible_borders(invisible_borders: i32);
|
||||
fn host_get_help();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue