diff --git a/Cargo.lock b/Cargo.lock index 8130b6aa..ad8705d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1225,6 +1225,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kdl" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8388a371e0e2ede18bbd94e476fcd45b4ac65cefcedf0c06fd13bd8389574a6" +dependencies = [ + "miette 5.3.0", + "nom 7.1.1", + "thiserror", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -1412,7 +1423,7 @@ checksum = "cd2adcfcced5d625bf90a958a82ae5b93231f57f3df1383fee28c9b5096d35ed" dependencies = [ "atty", "backtrace", - "miette-derive", + "miette-derive 3.3.0", "once_cell", "owo-colors", "supports-color", @@ -1423,6 +1434,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "miette" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28d6092d7e94a90bb9ea8e6c26c99d5d112d49dda2afdb4f7ea8cf09e1a5a6d" +dependencies = [ + "miette-derive 5.3.0", + "once_cell", + "thiserror", + "unicode-width", +] + [[package]] name = "miette-derive" version = "3.3.0" @@ -1434,6 +1457,23 @@ dependencies = [ "syn", ] +[[package]] +name = "miette-derive" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2485ed7d1fe80704928e3eb86387439609bd0c6bb96db8208daa364cfd1e09" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.5.3" @@ -1503,6 +1543,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "ntapi" version = "0.3.7" @@ -2501,7 +2551,7 @@ checksum = "76971977e6121664ec1b960d1313aacfa75642adc93b9d4d53b247bd4cb1747e" dependencies = [ "dirs", "fnv", - "nom", + "nom 5.1.2", "phf", "phf_codegen", ] @@ -3312,11 +3362,12 @@ dependencies = [ "dialoguer", "insta", "log", - "miette", + "miette 3.3.0", "names", "rand 0.8.5", "ssh2", "suggest", + "thiserror", "zellij-client", "zellij-server", "zellij-utils", @@ -3329,6 +3380,9 @@ dependencies = [ "insta", "log", "mio", + "serde", + "serde_yaml", + "url", "zellij-utils", ] @@ -3393,19 +3447,20 @@ dependencies = [ "colorsys", "crossbeam", "directories-next", + "insta", "interprocess", + "kdl", "lazy_static", "libc", "log", "log4rs", - "miette", + "miette 3.3.0", "nix", "once_cell", "regex", "rmp-serde", "serde", "serde_json", - "serde_yaml", "signal-hook 0.3.14", "strip-ansi-escapes", "strum", diff --git a/Cargo.toml b/Cargo.toml index c0ec182d..f0b49a29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ rust-version = "1.59" [dependencies] anyhow = "1.0" +thiserror = "1.0.30" names = { version = "0.13.0", default-features = false } miette = { version = "3.3.0", features = ["fancy"] } zellij-client = { path = "zellij-client/", version = "0.32.0" } diff --git a/Makefile.toml b/Makefile.toml index f8ade7e6..0906d02f 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -83,7 +83,7 @@ args = [ # Simple clippy tweak [tasks.clippy] -args = ["clippy", "--all-targets","--all-features","--","--deny","warnings", "@@split(CARGO_MAKE_TASK_ARGS,;)"] +args = ["clippy", "--all-targets", "--all-features", "@@split(CARGO_MAKE_TASK_ARGS,;)"] # Release building and installing Zellij [tasks.install] diff --git a/default-plugins/status-bar/src/second_line.rs b/default-plugins/status-bar/src/second_line.rs index 26afcd94..8f0ff42a 100644 --- a/default-plugins/status-bar/src/second_line.rs +++ b/default-plugins/status-bar/src/second_line.rs @@ -161,7 +161,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { (s("Embed pane"), s("Embed"), action_key(&km, &[A::TogglePaneEmbedOrFloating, TO_NORMAL])), (s("Next"), s("Next"), action_key(&km, &[A::SwitchFocus])), (s("Select pane"), s("Select"), to_normal_key), - ]} else if mi.mode == IM::Tab { + ]} else if mi.mode == IM::Tab { // With the default bindings, "Move focus" for tabs is tricky: It binds all the arrow keys // to moving tabs focus (left/up go left, right/down go right). Since we sort the keys // above and then dedpulicate based on the actions, we will end up with LeftArrow for @@ -180,9 +180,9 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { vec![ (s("Move focus"), s("Move"), focus_keys), - (s("New"), s("New"), action_key(&km, &[A::NewTab(None), TO_NORMAL])), + (s("New"), s("New"), action_key(&km, &[A::NewTab(None, None), TO_NORMAL])), (s("Close"), s("Close"), action_key(&km, &[A::CloseTab, TO_NORMAL])), - (s("Rename"), s("Rename"), + (s("Rename"), s("Rename"), action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])), (s("Sync"), s("Sync"), action_key(&km, &[A::ToggleActiveSyncTab, TO_NORMAL])), (s("Toggle"), s("Toggle"), action_key(&km, &[A::ToggleTab])), @@ -192,7 +192,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { &[A::Resize(RDir::Left)], &[A::Resize(RDir::Down)], &[A::Resize(RDir::Up)], &[A::Resize(RDir::Right)]])), (s("Increase/Decrease size"), s("Increase/Decrease"), - action_key_group(&km, &[&[A::Resize(RDir::Increase)], &[A::Resize(RDir::Decrease)]])), + action_key_group(&km, &[&[A::Resize(RDir::Increase)], &[A::Resize(RDir::Decrease)]])), (s("Select pane"), s("Select"), to_normal_key), ]} else if mi.mode == IM::Move { vec![ (s("Move"), s("Move"), action_key_group(&km, &[ @@ -242,7 +242,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { (s("Split down"), s("Down"), action_key(&km, &[A::NewPane(Some(Dir::Down)), TO_NORMAL])), (s("Split right"), s("Right"), action_key(&km, &[A::NewPane(Some(Dir::Right)), TO_NORMAL])), (s("Fullscreen"), s("Fullscreen"), action_key(&km, &[A::ToggleFocusFullscreen, TO_NORMAL])), - (s("New tab"), s("New"), action_key(&km, &[A::NewTab(None), TO_NORMAL])), + (s("New tab"), s("New"), action_key(&km, &[A::NewTab(None, None), TO_NORMAL])), (s("Rename tab"), s("Rename"), action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])), (s("Previous Tab"), s("Previous"), action_key(&km, &[A::GoToPreviousTab, TO_NORMAL])), diff --git a/default-plugins/status-bar/src/tip/data/quicknav.rs b/default-plugins/status-bar/src/tip/data/quicknav.rs index 59b604a7..57d60a2d 100644 --- a/default-plugins/status-bar/src/tip/data/quicknav.rs +++ b/default-plugins/status-bar/src/tip/data/quicknav.rs @@ -72,13 +72,18 @@ fn add_keybinds(help: &ModeInfo) -> Keygroups { style_key_with_modifier(&new_pane_keys, &help.style.colors) }; - let resize_keys = action_key_group( + let mut resize_keys = action_key_group( &normal_keymap, &[ &[Action::Resize(ResizeDirection::Increase)], &[Action::Resize(ResizeDirection::Decrease)], ], ); + if resize_keys.contains(&Key::Alt(CharOrArrow::Char('='))) + && resize_keys.contains(&Key::Alt(CharOrArrow::Char('+'))) + { + resize_keys.retain(|k| k != &Key::Alt(CharOrArrow::Char('='))); + } let resize = if resize_keys.is_empty() { vec![Style::new().bold().paint("UNBOUND")] } else { diff --git a/example/themes/README.md b/example/themes/README.md index ade4d6cd..8572222a 100644 --- a/example/themes/README.md +++ b/example/themes/README.md @@ -1,7 +1,7 @@ # Themes -Please make sure that the theme name and the file name are the same (+`.yaml`). +Please make sure that the theme name and the file name are the same (+`.kdl`). Example: - theme: gruvbox -- filename: `gruvbox.yaml` +- filename: `gruvbox.kdl` diff --git a/example/themes/dracula.kdl b/example/themes/dracula.kdl new file mode 100644 index 00000000..26f20504 --- /dev/null +++ b/example/themes/dracula.kdl @@ -0,0 +1,17 @@ +// From https://github.com/dracula/zellij + +themes { + dracula { + fg 248 248 242 + bg 40 42 54 + black 0 0 0 + red 255 85 85 + green 80 250 123 + yellow 241 250 140 + blue 98 114 164 + magenta 255 121 198 + cyan 139 233 253 + white 255 255 255 + orange 255 184 108 + } +} diff --git a/example/themes/dracula.yaml b/example/themes/dracula.yaml deleted file mode 100644 index b9c8a5af..00000000 --- a/example/themes/dracula.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Dracula Theme - -themes: - dracula: - # From https://github.com/dracula/zellij - bg: [40, 42, 54] - red: [255, 85, 85] - green: [80, 250, 123] - yellow: [241, 250, 140] - blue: [98, 114, 164] - magenta: [255, 121, 198] - orange: [255, 184, 108] - fg: [248, 248, 242] - cyan: [139, 233, 253] - black: [0, 0, 0] - white: [255, 255, 255] diff --git a/example/themes/gruvbox-dark.kdl b/example/themes/gruvbox-dark.kdl new file mode 100644 index 00000000..53c9d6ab --- /dev/null +++ b/example/themes/gruvbox-dark.kdl @@ -0,0 +1,16 @@ +themes { + gruvbox-dark { + fg 213 196 161 + bg 40 40 40 + black 60 56 54 + red 204 36 29 + green 152 151 26 + yellow 215 153 33 + blue 69 133 136 + magenta 177 98 134 + cyan 104 157 106 + white 251 241 199 + orange 214 93 14 + } +} + diff --git a/example/themes/gruvbox-dark.yaml b/example/themes/gruvbox-dark.yaml deleted file mode 100644 index 676bc42b..00000000 --- a/example/themes/gruvbox-dark.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Gruvbox theme - -themes: - gruvbox-dark: - bg: [40, 40, 40] - red: [204, 36, 29] - green: [152, 151, 26] - yellow: [215, 153, 33] - blue: [69, 133, 136] - magenta: [177, 98, 134] - orange: [214, 93, 14] - fg: [213, 196, 161] - cyan: [104, 157, 106] - black: [60, 56, 54] - white: [251, 241, 199] diff --git a/example/themes/gruvbox-light.kdl b/example/themes/gruvbox-light.kdl new file mode 100644 index 00000000..7bb33e68 --- /dev/null +++ b/example/themes/gruvbox-light.kdl @@ -0,0 +1,16 @@ +themes { + gruvbox-light { + fg 60 56 54 + bg 251 82 75 + black 40 40 40 + red 205 75 69 + green 152 151 26 + yellow 215 153 33 + blue 69 133 136 + magenta 177 98 134 + cyan 104 157 106 + white 213 196 161 + orange 214 93 14 + } +} + diff --git a/example/themes/gruvbox-light.yaml b/example/themes/gruvbox-light.yaml deleted file mode 100644 index d672ec3b..00000000 --- a/example/themes/gruvbox-light.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Gruvbox theme - -themes: - gruvbox-light: - bg: [251, 82, 75] - red: [205, 75, 69] - green: [152, 151, 26] - yellow: [215, 153, 33] - blue: [69, 133, 136] - magenta: [177, 98, 134] - orange: [214, 93, 14] - fg: [60, 56, 54] - cyan: [104, 157, 106] - black: [40, 40, 40] - white: [213, 196, 161] diff --git a/example/themes/molokai-dark.kdl b/example/themes/molokai-dark.kdl new file mode 100644 index 00000000..6fd96f9a --- /dev/null +++ b/example/themes/molokai-dark.kdl @@ -0,0 +1,16 @@ +themes { + molokai-dark { + fg 248 248 240 + bg 27 29 30 + black 0 0 0 + red 255 0 0 + green 0 140 0 + yellow 255 255 0 + blue 102 217 239 + magenta 174 129 255 + cyan 0 255 255 + white 255 255 255 + orange 253 151 31 + } +} + diff --git a/example/themes/molokai-dark.yaml b/example/themes/molokai-dark.yaml deleted file mode 100644 index b2135fdf..00000000 --- a/example/themes/molokai-dark.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Molokai Theme - -themes: - molokai-dark: - bg: [27, 29, 30] - red: [255, 0, 0] - green: [0, 140, 0] - yellow: [255, 255, 0] - blue: [102, 217, 239] - magenta: [174, 129, 255] - orange: [253, 151, 31] - fg: [248, 248, 240] - cyan: [0, 255, 255] - black: [0, 0, 0] - white: [255, 255, 255] diff --git a/example/themes/nord.kdl b/example/themes/nord.kdl new file mode 100644 index 00000000..a56a9bfb --- /dev/null +++ b/example/themes/nord.kdl @@ -0,0 +1,15 @@ +themes { + nord { + fg 216 222 233 // #D8DEE9 + bg 46 52 64 // #2E3440 + black 59 66 82 // #3B4252 + red 191 97 106 // #BF616A + green 163 190 140 // #A3BE8C + yellow 235 203 139 // #EBCB8B + blue 129 161 193 // #81A1C1 + magenta 180 142 173 // #B48EAD + cyan 136 192 208 // #88C0D0 + white 229 233 240 // #E5E9F0 + orange 208 135 112 // #D08770 + } +} diff --git a/example/themes/nord.yaml b/example/themes/nord.yaml deleted file mode 100644 index 61851ad2..00000000 --- a/example/themes/nord.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Nord theme - -themes: - nord: - fg: [216, 222, 233] #D8DEE9 - bg: [46, 52, 64] #2E3440 - black: [59, 66, 82] #3B4252 - red: [191, 97, 106] #BF616A - green: [163, 190, 140] #A3BE8C - yellow: [235,203,139] #EBCB8B - blue: [129, 161, 193] #81A1C1 - magenta: [180, 142, 173] #B48EAD - cyan: [136, 192, 208] #88C0D0 - white: [229, 233, 240] #E5E9F0 - orange: [208, 135, 112] #D08770 - diff --git a/example/themes/one-half-dark.kdl b/example/themes/one-half-dark.kdl new file mode 100644 index 00000000..ade1874b --- /dev/null +++ b/example/themes/one-half-dark.kdl @@ -0,0 +1,16 @@ +themes { + one-half-dark { + fg 220 223 228 + bg 40 44 52 + black 27 29 35 + red 227 63 76 + green 152 195 121 + yellow 229 192 123 + blue 97 175 239 + magenta 198 120 221 + cyan 86 182 194 + white 233 225 254 + orange 216 133 76 + } +} + diff --git a/example/themes/one-half-dark.yaml b/example/themes/one-half-dark.yaml deleted file mode 100644 index 5f3b3968..00000000 --- a/example/themes/one-half-dark.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# One Half Theme - -themes: - one-half-dark: - bg: [40, 44, 52] - red: [227, 63, 76] - green: [152, 195, 121] - yellow: [229, 192, 123] - blue: [97, 175, 239] - magenta: [198, 120, 221] - orange: [216, 133, 76] - fg: [220, 223, 228] - cyan: [86, 182, 194] - black: [27, 29, 35] - white: [233, 225, 254] \ No newline at end of file diff --git a/example/themes/solarized-dark.kdl b/example/themes/solarized-dark.kdl new file mode 100644 index 00000000..20482f5c --- /dev/null +++ b/example/themes/solarized-dark.kdl @@ -0,0 +1,16 @@ +themes { + solarized-dark { + fg 253 246 227 + bg 0 43 54 + black 7 54 66 + red 220 50 47 + green 133 153 0 + yellow 181 137 0 + blue 38 139 210 + magenta 211 54 130 + cyan 42 161 152 + white 238 232 213 + orange 203 75 22 + } +} + diff --git a/example/themes/solarized-dark.yaml b/example/themes/solarized-dark.yaml deleted file mode 100644 index c93635e4..00000000 --- a/example/themes/solarized-dark.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Solarized dark - -themes: - solarized-dark: - bg: [0, 43, 54] - red: [220, 50, 47] - green: [133, 153, 0] - yellow: [181, 137, 0] - blue: [38, 139, 210] - magenta: [211, 54, 130] - orange: [203, 75, 22] - fg: [253, 246, 227] - cyan: [42, 161, 152] - black: [7, 54, 66] - white: [238, 232, 213] diff --git a/example/themes/solarized-light.kdl b/example/themes/solarized-light.kdl new file mode 100644 index 00000000..93bac49b --- /dev/null +++ b/example/themes/solarized-light.kdl @@ -0,0 +1,16 @@ +themes { + solarized-light { + fg 101 123 131 + bg 253 246 227 + black 7 54 66 + red 220 50 47 + green 133 153 0 + yellow 181 137 0 + blue 38 139 210 + magenta 211 54 130 + cyan 42 161 152 + white 238 232 213 + orange 203 75 22 + } +} + diff --git a/example/themes/solarized-light.yaml b/example/themes/solarized-light.yaml deleted file mode 100644 index 45683376..00000000 --- a/example/themes/solarized-light.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Solarized light - -themes: - solarized-light: - bg: [253, 246, 227] - red: [220, 50, 47] - green: [133, 153, 0] - yellow: [181, 137, 0] - blue: [38, 139, 210] - magenta: [211, 54, 130] - orange: [203, 75, 22] - fg: [101, 123, 131] - cyan: [42, 161, 152] - black: [7, 54, 66] - white: [238, 232, 213] diff --git a/example/themes/tokyo-night-dark.kdl b/example/themes/tokyo-night-dark.kdl new file mode 100644 index 00000000..e69de29b diff --git a/example/themes/tokyo-night-light.kdl b/example/themes/tokyo-night-light.kdl new file mode 100644 index 00000000..3ac5fb76 --- /dev/null +++ b/example/themes/tokyo-night-light.kdl @@ -0,0 +1,16 @@ +themes { + tokyo-night-light { + fg 52 59 88 + bg 213 214 219 + black 15 15 20 + red 186 75 96 + green 72 94 48 + yellow 143 94 21 + blue 52 84 138 + magenta 90 74 120 + cyan 15 75 110 + white 130 137 172 + orange 150 80 39 + } +} + diff --git a/example/themes/tokyo-night-light.yaml b/example/themes/tokyo-night-light.yaml deleted file mode 100644 index 156943cd..00000000 --- a/example/themes/tokyo-night-light.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# TokyoNight Theme -# Originally by https://github.com/enkia/tokyo-night-vscode-theme - -themes: - tokyo-night-light: - fg: [52,59,88] #343B58 - bg: [213,214,219] #D5D6DB - black: [15,15,20] #0F0F14 - red: [186,75,96] #BA4B60 - green: [72,94,48] #485E30 - yellow: [143,94,21] #8F5E15 - blue: [52,84,138] #34548A - magenta: [90,74,120] #5A4A78 - cyan: [15,75,110] #0F4B6E - white: [130,137,172] #8289AC - orange: [150,80,39] #965027 diff --git a/example/themes/tokyo-night-storm.kdl b/example/themes/tokyo-night-storm.kdl new file mode 100644 index 00000000..e727ef72 --- /dev/null +++ b/example/themes/tokyo-night-storm.kdl @@ -0,0 +1,16 @@ +themes { + tokyo-night-storm { + fg 169 177 214 + bg 36 40 59 + black 56 62 90 + red 249 51 87 + green 158 206 106 + yellow 224 175 104 + blue 122 162 247 + magenta 187 154 247 + cyan 42 195 222 + white 192 202 245 + orange 255 158 100 + } +} + diff --git a/example/themes/tokyo-night-storm.yaml b/example/themes/tokyo-night-storm.yaml deleted file mode 100644 index 9239990f..00000000 --- a/example/themes/tokyo-night-storm.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# TokyoNight Theme -# Originally by https://github.com/enkia/tokyo-night-vscode-theme - -themes: - tokyo-night-storm: - fg: [169,177,214] #A9B1D6 - bg: [36,40,59] #24283B - black: [56,62,90] #383E5A - red: [249,51,87] #F9334D - green: [158,206,106] #9ECE6A - yellow: [224,175,104] #E0AF68 - blue: [122,162,247] #7AA2F7 - magenta: [187,154,247] #BB9AF7 - cyan: [42,195,222] #2AC3DE - white: [192,202,245] #C0CAF5 - orange: [255,158,100] #FF9E64 diff --git a/example/themes/tokyo-night.kdl b/example/themes/tokyo-night.kdl new file mode 100644 index 00000000..4ea1a810 --- /dev/null +++ b/example/themes/tokyo-night.kdl @@ -0,0 +1,16 @@ +themes { + tokyo-night { + fg 169 177 214 + bg 26 27 38 + black 56 62 90 + red 249 51 87 + green 158 206 106 + yellow 224 175 104 + blue 122 162 247 + magenta 187 154 247 + cyan 42 195 222 + white 192 202 245 + orange 255 158 100 + } +} + diff --git a/example/themes/tokyo-night.yaml b/example/themes/tokyo-night.yaml deleted file mode 100644 index d62fb422..00000000 --- a/example/themes/tokyo-night.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# TokyoNight Theme -# Originally by https://github.com/enkia/tokyo-night-vscode-theme - -themes: - tokyo-night: - fg: [169,177,214] #A9B1D6 - bg: [26,27,38] #1A1B26 - black: [56,62,90] #383E5A - red: [249,51,87] #F9334D - green: [158,206,106] #9ECE6A - yellow: [224,175,104] #E0AF68 - blue: [122,162,247] #7AA2F7 - magenta: [187,154,247] #BB9AF7 - cyan: [42,195,222] #2AC3DE - white: [192,202,245] #C0CAF5 - orange: [255,158,100] #FF9E64 diff --git a/src/commands.rs b/src/commands.rs index 58a464d7..b4e2e1da 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -6,13 +6,18 @@ use crate::sessions::{ session_exists, ActiveSession, SessionNameMatch, }; use dialoguer::Confirm; -use miette::Result; +use miette::{Report, Result}; use std::path::PathBuf; use std::process; +use zellij_client::old_config_converter::{ + config_yaml_to_config_kdl, convert_old_yaml_files, layout_yaml_to_layout_kdl, +}; use zellij_client::start_client as start_client_impl; use zellij_client::{os_input_output::get_client_os_input, ClientInfo}; use zellij_server::os_input_output::get_server_os_input; use zellij_server::start_server as start_server_impl; +use zellij_utils::input::actions::Action; +use zellij_utils::input::config::ConfigError; use zellij_utils::input::options::Options; use zellij_utils::nix; use zellij_utils::{ @@ -21,10 +26,7 @@ use zellij_utils::{ setup::{get_default_data_dir, Setup}, }; -#[cfg(feature = "unstable")] -use miette::IntoDiagnostic; -#[cfg(feature = "unstable")] -use zellij_utils::input::actions::ActionsFromYaml; +use std::{fs::File, io::prelude::*}; pub(crate) use crate::sessions::list_sessions; @@ -118,69 +120,133 @@ fn find_indexed_session( } } -/// Send a vec of `[Action]` to a currently running session. -#[cfg(feature = "unstable")] -pub(crate) fn send_action_to_session(opts: zellij_utils::cli::CliArgs) { +pub(crate) fn send_action_to_session( + cli_action: zellij_utils::cli::CliAction, + requested_session_name: Option, +) { match get_active_session() { ActiveSession::None => { eprintln!("There is no active session!"); std::process::exit(1); }, ActiveSession::One(session_name) => { - attach_with_fake_client(opts, &session_name); + if let Some(requested_session_name) = requested_session_name { + if requested_session_name != session_name { + eprintln!( + "Session '{}' not found. The following sessions are active:", + requested_session_name + ); + eprintln!("{}", session_name); + std::process::exit(1); + } + } + attach_with_cli_client(cli_action, &session_name); }, ActiveSession::Many => { - if let Some(session_name) = opts.session.clone() { - attach_with_fake_client(opts, &session_name); + let existing_sessions = get_sessions().unwrap(); + if let Some(session_name) = requested_session_name { + if existing_sessions.contains(&session_name) { + attach_with_cli_client(cli_action, &session_name); + } else { + eprintln!( + "Session '{}' not found. The following sessions are active:", + session_name + ); + print_sessions(existing_sessions); + std::process::exit(1); + } } else if let Ok(session_name) = envs::get_session_name() { - attach_with_fake_client(opts, &session_name); + attach_with_cli_client(cli_action, &session_name); } else { - println!("Please specify the session name to send actions to. The following sessions are active:"); - print_sessions(get_sessions().unwrap()); + eprintln!("Please specify the session name to send actions to. The following sessions are active:"); + print_sessions(existing_sessions); std::process::exit(1); } }, }; } +pub(crate) fn convert_old_config_file(old_config_file: PathBuf) { + match File::open(&old_config_file) { + Ok(mut handle) => { + let mut raw_config_file = String::new(); + let _ = handle.read_to_string(&mut raw_config_file); + match config_yaml_to_config_kdl(&raw_config_file, false) { + Ok(kdl_config) => { + println!("{}", kdl_config); + process::exit(0); + }, + Err(e) => { + eprintln!("Failed to convert config: {}", e); + process::exit(1); + }, + } + }, + Err(e) => { + eprintln!("Failed to open file: {}", e); + process::exit(1); + }, + } +} -#[cfg(feature = "unstable")] -fn attach_with_fake_client(opts: zellij_utils::cli::CliArgs, name: &str) { - if let Some(zellij_utils::cli::Command::Sessions(zellij_utils::cli::Sessions::Action { - action: Some(action), - })) = opts.command.clone() - { - let action = format!("[{}]", action); - match zellij_utils::serde_yaml::from_str::(&action).into_diagnostic() { - Ok(parsed) => { - let (config, _, config_options) = match Setup::from_options(&opts) { - Ok(results) => results, - Err(e) => { - eprintln!("{}", e); - process::exit(1); - }, - }; - let os_input = get_os_input(zellij_client::os_input_output::get_client_os_input); +pub(crate) fn convert_old_layout_file(old_layout_file: PathBuf) { + match File::open(&old_layout_file) { + Ok(mut handle) => { + let mut raw_layout_file = String::new(); + let _ = handle.read_to_string(&mut raw_layout_file); + match layout_yaml_to_layout_kdl(&raw_layout_file) { + Ok(kdl_layout) => { + println!("{}", kdl_layout); + process::exit(0); + }, + Err(e) => { + eprintln!("Failed to convert layout: {}", e); + process::exit(1); + }, + } + }, + Err(e) => { + eprintln!("Failed to open file: {}", e); + process::exit(1); + }, + } +} - let actions = parsed.actions().to_vec(); - log::debug!("Starting fake Zellij client!"); - zellij_client::fake_client::start_fake_client( - Box::new(os_input), - opts, - *Box::new(config), - config_options, - ClientInfo::New(name.to_string()), - None, - actions, - ); - log::debug!("Quitting fake client now."); - std::process::exit(0); - }, - Err(e) => { - eprintln!("{:?}", e); - std::process::exit(1); - }, - }; - }; +pub(crate) fn convert_old_theme_file(old_theme_file: PathBuf) { + match File::open(&old_theme_file) { + Ok(mut handle) => { + let mut raw_config_file = String::new(); + let _ = handle.read_to_string(&mut raw_config_file); + match config_yaml_to_config_kdl(&raw_config_file, true) { + Ok(kdl_config) => { + println!("{}", kdl_config); + process::exit(0); + }, + Err(e) => { + eprintln!("Failed to convert config: {}", e); + process::exit(1); + }, + } + }, + Err(e) => { + eprintln!("Failed to open file: {}", e); + process::exit(1); + }, + } +} + +fn attach_with_cli_client(cli_action: zellij_utils::cli::CliAction, session_name: &str) { + let os_input = get_os_input(zellij_client::os_input_output::get_client_os_input); + match Action::actions_from_cli(cli_action) { + Ok(actions) => { + zellij_client::cli_client::start_cli_client(Box::new(os_input), session_name, actions); + std::process::exit(0); + }, + Err(e) => { + eprintln!("{}", e); + log::error!("Error sending action: {}", e); + std::process::exit(2); + }, + } } fn attach_with_session_index(config_options: Options, index: usize, create: bool) -> ClientInfo { @@ -249,10 +315,17 @@ fn attach_with_session_name( } pub(crate) fn start_client(opts: CliArgs) { - let (config, layout, config_options) = match Setup::from_options(&opts) { + // look for old YAML config/layout/theme files and convert them to KDL + convert_old_yaml_files(&opts); + let (config, layout, config_options) = match Setup::from_cli_args(&opts) { Ok(results) => results, Err(e) => { - eprintln!("{}", e); + if let ConfigError::KdlError(error) = e { + let report: Report = error.into(); + eprintln!("{:?}", report); + } else { + eprintln!("{}", e); + } process::exit(1); }, }; @@ -285,7 +358,7 @@ pub(crate) fn start_client(opts: CliArgs) { let attach_layout = match client { ClientInfo::Attach(_, _) => None, - ClientInfo::New(_) => layout, + ClientInfo::New(_) => Some(layout), }; if create { @@ -314,23 +387,21 @@ pub(crate) fn start_client(opts: CliArgs) { config, config_options, ClientInfo::New(session_name), - layout, + Some(layout), ); } else { - if let Some(layout_some) = layout.clone() { - if let Some(session_name) = layout_some.session.name { - if layout_some.session.attach.unwrap() { + if let Some(session_name) = config_options.session_name.as_ref() { + match config_options.attach_to_session { + Some(true) => { let client = attach_with_session_name( - Some(session_name), + Some(session_name.clone()), config_options.clone(), true, ); - let attach_layout = match client { ClientInfo::Attach(_, _) => None, - ClientInfo::New(_) => layout, + ClientInfo::New(_) => Some(layout), }; - start_client_impl( Box::new(os_input), opts, @@ -339,20 +410,23 @@ pub(crate) fn start_client(opts: CliArgs) { client, attach_layout, ); - } else { + }, + _ => { start_client_plan(session_name.clone()); start_client_impl( Box::new(os_input), opts, config, - config_options, - ClientInfo::New(session_name), - layout, + config_options.clone(), + ClientInfo::New(session_name.clone()), + Some(layout), ); - } - - process::exit(0); + }, } + // after we detach, this happens and so we need to exit before the rest of the + // function happens + // TODO: offload this to a different function + process::exit(0); } let session_name = names::Generator::default().next().unwrap(); @@ -363,7 +437,7 @@ pub(crate) fn start_client(opts: CliArgs) { config, config_options, ClientInfo::New(session_name), - layout, + Some(layout), ); } } diff --git a/src/main.rs b/src/main.rs index ca05dbf1..d2363e7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ mod tests; use zellij_utils::{ clap::Parser, - cli::{CliArgs, Command, Sessions}, + cli::{CliAction, CliArgs, Command, Sessions}, logging::*, }; @@ -14,10 +14,53 @@ fn main() { configure_logger(); let opts = CliArgs::parse(); - #[cfg(feature = "unstable")] { - if let Some(Command::Sessions(Sessions::Action { .. })) = opts.command { - commands::send_action_to_session(opts); + if let Some(Command::Sessions(Sessions::Action(cli_action))) = opts.command { + commands::send_action_to_session(cli_action, opts.session); + std::process::exit(0); + } + if let Some(Command::Sessions(Sessions::Command { + command, + direction, + cwd, + floating, + })) = opts.command + { + let command_cli_action = CliAction::NewPane { + command, + direction, + cwd, + floating, + }; + commands::send_action_to_session(command_cli_action, opts.session); + std::process::exit(0); + } + if let Some(Command::Sessions(Sessions::Edit { + file, + direction, + line_number, + floating, + })) = opts.command + { + let command_cli_action = CliAction::Edit { + file, + direction, + line_number, + floating, + }; + commands::send_action_to_session(command_cli_action, opts.session); + std::process::exit(0); + } + if let Some(Command::Sessions(Sessions::ConvertConfig { old_config_file })) = opts.command { + commands::convert_old_config_file(old_config_file); + std::process::exit(0); + } + if let Some(Command::Sessions(Sessions::ConvertLayout { old_layout_file })) = opts.command { + commands::convert_old_layout_file(old_layout_file); + std::process::exit(0); + } + if let Some(Command::Sessions(Sessions::ConvertTheme { old_theme_file })) = opts.command { + commands::convert_old_theme_file(old_theme_file); std::process::exit(0); } } diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index 7457ed54..63e2d677 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -458,9 +458,8 @@ pub fn close_tab() { name: "Wait for tab to close", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) + if remote_terminal.snapshot_contains("Tab #1") && !remote_terminal.snapshot_contains("Tab #2") - && remote_terminal.tip_appears() { // cursor is in the first tab again step_is_complete = true; @@ -475,7 +474,8 @@ pub fn close_tab() { break last_snapshot; } }; - assert_snapshot!(last_snapshot); + assert!(last_snapshot.contains("Tab #1")); + assert!(!last_snapshot.contains("Tab #2")); } #[test] @@ -948,41 +948,6 @@ pub fn detach_and_attach_session() { assert_snapshot!(last_snapshot); } -#[test] -#[ignore] -pub fn accepts_basic_layout() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let layout_file_name = "three-panes-with-nesting.yaml"; - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = RemoteRunner::new_with_layout(fake_win_size, layout_file_name); - runner.run_all_steps(); - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for app to load", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 1) - && remote_terminal.snapshot_contains("$ █ ││$") - && remote_terminal.snapshot_contains("$ ") { - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - assert_snapshot!(last_snapshot); -} - #[test] #[ignore] pub fn status_bar_loads_custom_keybindings() { @@ -990,7 +955,7 @@ pub fn status_bar_loads_custom_keybindings() { cols: 120, rows: 24, }; - let config_file_name = "changed_keys.yaml"; + let config_file_name = "changed_keys.kdl"; let mut test_attempts = 10; let last_snapshot = loop { RemoteRunner::kill_running_sessions(fake_win_size); @@ -1718,43 +1683,6 @@ pub fn toggle_floating_panes() { assert_snapshot!(last_snapshot); } -#[test] -#[ignore] -pub fn focus_tab_with_layout() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let layout_file_name = "focus-tab-layout.yaml"; - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = RemoteRunner::new_with_layout(fake_win_size, layout_file_name); - runner.run_all_steps(); - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for app to load", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() - && remote_terminal.tip_appears() - && remote_terminal.snapshot_contains("Tab #9") - && remote_terminal.cursor_position_is(63, 2) - { - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - assert_snapshot!(last_snapshot); -} - #[test] #[ignore] pub fn tmux_mode() { diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index 03fb619e..b0bde1db 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -19,7 +19,6 @@ use std::rc::Rc; const ZELLIJ_EXECUTABLE_LOCATION: &str = "/usr/src/zellij/x86_64-unknown-linux-musl/release/zellij"; const SET_ENV_VARIABLES: &str = "EDITOR=/usr/bin/vi"; -const ZELLIJ_LAYOUT_PATH: &str = "/usr/src/zellij/fixtures/layouts"; const ZELLIJ_CONFIG_PATH: &str = "/usr/src/zellij/fixtures/configs"; const ZELLIJ_DATA_DIR: &str = "/usr/src/zellij/e2e-data"; const ZELLIJ_FIXTURE_PATH: &str = "/usr/src/zellij/fixtures"; @@ -145,25 +144,6 @@ fn start_zellij_without_frames(channel: &mut ssh2::Channel) { std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN } -fn start_zellij_with_layout(channel: &mut ssh2::Channel, layout_path: &str) { - stop_zellij(channel); - channel - .write_all( - format!( - "{} {} --layout {} --session {} --data-dir {}\n", - SET_ENV_VARIABLES, - ZELLIJ_EXECUTABLE_LOCATION, - layout_path, - SESSION_NAME, - ZELLIJ_DATA_DIR - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); - std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN -} - fn start_zellij_with_config(channel: &mut ssh2::Channel, config_path: &str) { stop_zellij(channel); channel @@ -571,42 +551,6 @@ impl RemoteRunner { reader_thread, } } - pub fn new_with_layout(win_size: Size, layout_file_name: &'static str) -> Self { - let remote_path = Path::new(ZELLIJ_LAYOUT_PATH).join(layout_file_name); - let sess = ssh_connect(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - }; - setup_remote_environment(&mut channel, win_size); - start_zellij_with_layout(&mut channel, &remote_path.to_string_lossy()); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } pub fn new_with_config(win_size: Size, config_file_name: &'static str) -> Self { let remote_path = Path::new(ZELLIJ_CONFIG_PATH).join(config_file_name); let sess = ssh_connect(); diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__bracketed_paste.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__bracketed_paste.snap index 8b66d5ac..dcb76b9e 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__bracketed_paste.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__bracketed_paste.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1636 +assertion_line: 1671 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap index 0d431c32..ac55a9d4 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_tab.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_tab.snap index 603432fd..b4ad5a98 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_tab.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_tab.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 478 +assertion_line: 482 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + <←→> Move focus / New / Close / Rename / Sync / Toggle / Select pane diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap index 92d2a037..5f79887f 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap @@ -26,4 +26,4 @@ expression: last_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap index ef923aa2..d373cbbb 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1042 +assertion_line: 1077 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap index 68965f48..3a421290 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1307 +assertion_line: 1342 expression: first_runner_snapshot --- Zellij (mirrored_sessions)  Tab #1  Tab #2  @@ -26,4 +26,4 @@ expression: first_runner_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap index ffcb6b2f..5bf97567 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1486 +assertion_line: 1521 expression: second_runner_snapshot --- Zellij (multiple_users_in_same_pane_and_tab)  Tab #1 [ ] @@ -26,4 +26,4 @@ expression: second_runner_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap index 797448a6..2316cf55 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1485 +assertion_line: 1520 expression: first_runner_snapshot --- Zellij (multiple_users_in_same_pane_and_tab)  Tab #1 [ ] @@ -26,4 +26,4 @@ expression: first_runner_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs-2.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs-2.snap index cd4006d5..d3c93217 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs-2.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs-2.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1581 +assertion_line: 1616 expression: second_runner_snapshot --- Zellij (multiple_users_in_different_tabs)  Tab #1 [ ] Tab #2  @@ -26,4 +26,4 @@ expression: second_runner_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs.snap index 8856f1f9..86e8023d 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_tabs.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1580 +assertion_line: 1615 expression: first_runner_snapshot --- Zellij (multiple_users_in_different_tabs)  Tab #1  Tab #2 [ ] @@ -26,4 +26,4 @@ expression: first_runner_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab-2.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab-2.snap index d7328b8d..161f8eea 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab-2.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab-2.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1396 +assertion_line: 1431 expression: second_runner_snapshot --- Zellij (multiple_users_in_same_pane_and_tab)  Tab #1 [ ] @@ -26,4 +26,4 @@ expression: second_runner_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab.snap index 6bc0369c..15cc156a 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_same_pane_and_tab.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1395 +assertion_line: 1430 expression: first_runner_snapshot --- Zellij (multiple_users_in_same_pane_and_tab)  Tab #1 [ ] @@ -26,4 +26,4 @@ expression: first_runner_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap index 2d84b3f3..2aa80115 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap index f0365630..c4dd1fff 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap @@ -26,4 +26,4 @@ expression: last_snapshot │ ││ │ └────────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap index de1ef639..d7bf8cd5 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 883 +assertion_line: 863 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ ││ │ └────────────────────────────────────────────────┘└────────────────────────────────────────────────┘ Ctrl + g  p  t  n  h  s  o  q  - QuickNav: Alt + / Alt + <←↓↑→> or Alt + / Alt + <+|=|-> + QuickNav: Alt + / Alt + <←↓↑→> or Alt + / Alt + <+|-> diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap index ec416eea..e5132b9f 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1117 +assertion_line: 1152 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ ││li█e19 │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap index 22b79627..8dc5897b 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap @@ -26,4 +26,4 @@ expression: last_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap index f066d207..0fe416cf 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1163 +assertion_line: 1198 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ $ │$ █ │ │ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap index 1f4ff4f0..6f2822c5 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap index 05985a5f..e812fda8 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1767 +assertion_line: 1802 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__typing_exit_closes_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__typing_exit_closes_pane.snap index 3a1643b1..9fdd0f2d 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__typing_exit_closes_pane.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__typing_exit_closes_pane.snap @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_pane.snap index 03b44ebb..e8c27717 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_pane.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_pane.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1914 +assertion_line: 1949 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_tab.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_tab.snap index ed9a8e20..56b417d7 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_tab.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__undo_rename_tab.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1865 +assertion_line: 1900 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|=|-> => resize pane. + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/fixtures/configs/changed_keys.kdl b/src/tests/fixtures/configs/changed_keys.kdl new file mode 100644 index 00000000..6123b1d5 --- /dev/null +++ b/src/tests/fixtures/configs/changed_keys.kdl @@ -0,0 +1,12 @@ +keybinds clear-defaults=true { + normal { + bind "F1" { SwitchToMode "Locked"; } + bind "F2" { SwitchToMode "Pane"; } + bind "F3" { SwitchToMode "Tab"; } + bind "F4" { SwitchToMode "Resize"; } + bind "F5" { SwitchToMode "Move"; } + bind "F6" { SwitchToMode "Scroll"; } + bind "F7" { SwitchToMode "Session"; } + bind "F8" { Quit; } + } +} diff --git a/src/tests/fixtures/configs/changed_keys.yaml b/src/tests/fixtures/configs/changed_keys.yaml deleted file mode 100644 index 7d2a8c71..00000000 --- a/src/tests/fixtures/configs/changed_keys.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -# Configuration for zellij. - -# In order to troubleshoot your configuration try using the following command: -# `zellij setup --check` -# It should show current config locations and features that are enabled. - -keybinds: - unbind: true - normal: - - action: [SwitchToMode: Locked,] - key: [F: 1] - - action: [SwitchToMode: Pane,] - key: [F: 2] - - action: [SwitchToMode: Tab,] - key: [F: 3] - - action: [SwitchToMode: Resize,] - key: [F: 4] - - action: [SwitchToMode: Move,] - key: [F: 5] - - action: [SwitchToMode: Scroll,] - key: [F: 6] - - action: [SwitchToMode: Session,] - key: [F: 7] - - action: [Quit,] - key: [F: 8] diff --git a/src/tests/fixtures/layouts/parts-total-less-than-100-percent.yaml b/src/tests/fixtures/layouts/parts-total-less-than-100-percent.yaml deleted file mode 100644 index aac8c457..00000000 --- a/src/tests/fixtures/layouts/parts-total-less-than-100-percent.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -tabs: - - direction: Horizontal - parts: - - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 20 - - direction: Horizontal - split_size: - Percent: 50 - tabs: - - direction: Horizontal - split_size: - Percent: 80 - - direction: Vertical - split_size: - Percent: 20 diff --git a/src/tests/fixtures/layouts/parts-total-more-than-100-percent.yaml b/src/tests/fixtures/layouts/parts-total-more-than-100-percent.yaml deleted file mode 100644 index 8f3fcdbd..00000000 --- a/src/tests/fixtures/layouts/parts-total-more-than-100-percent.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -tabs: - - direction: Horizontal - parts: - - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 20 - - direction: Horizontal - split_size: - Percent: 90 - - direction: Horizontal - tabs: - - direction: Horizontal - split_size: - Percent: 80 - - direction: Vertical - split_size: - Percent: 20 diff --git a/src/tests/fixtures/layouts/three-panes-with-nesting.yaml b/src/tests/fixtures/layouts/three-panes-with-nesting.yaml deleted file mode 100644 index 2d0aed95..00000000 --- a/src/tests/fixtures/layouts/three-panes-with-nesting.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -tabs: - - direction: Horizontal - parts: - - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 20 - - direction: Horizontal - split_size: - Percent: 80 - split_size: - Percent: 80 - - direction: Vertical - split_size: - Percent: 20 diff --git a/zellij-client/Cargo.toml b/zellij-client/Cargo.toml index 30370d47..5761b0e5 100644 --- a/zellij-client/Cargo.toml +++ b/zellij-client/Cargo.toml @@ -10,6 +10,9 @@ license = "MIT" [dependencies] mio = { version = "0.7.11", features = ['os-ext'] } +serde = { version = "1.0", features = ["derive"] } +url = { version = "2.2.2", features = ["serde"] } +serde_yaml = "0.8" zellij-utils = { path = "../zellij-utils/", version = "0.32.0" } log = "0.4.17" diff --git a/zellij-client/src/cli_client.rs b/zellij-client/src/cli_client.rs new file mode 100644 index 00000000..95cd9d13 --- /dev/null +++ b/zellij-client/src/cli_client.rs @@ -0,0 +1,34 @@ +//! The `[cli_client]` is used to attach to a running server session +//! and dispatch actions, that are specified through the command line. +use std::process; +use std::{fs, path::PathBuf}; + +use crate::os_input_output::ClientOsApi; +use zellij_utils::{ + input::actions::Action, + ipc::{ClientToServerMsg, ServerToClientMsg}, +}; + +pub fn start_cli_client(os_input: Box, session_name: &str, actions: Vec) { + let zellij_ipc_pipe: PathBuf = { + let mut sock_dir = zellij_utils::consts::ZELLIJ_SOCK_DIR.clone(); + fs::create_dir_all(&sock_dir).unwrap(); + zellij_utils::shared::set_permissions(&sock_dir, 0o700).unwrap(); + sock_dir.push(session_name); + sock_dir + }; + os_input.connect_to_server(&*zellij_ipc_pipe); + for action in actions { + let msg = ClientToServerMsg::Action(action, None); + os_input.send_to_server(msg); + } + loop { + match os_input.recv_from_server() { + Some((ServerToClientMsg::UnblockInputThread, _)) => { + os_input.send_to_server(ClientToServerMsg::ClientExited); + process::exit(0); + }, + _ => {}, + } + } +} diff --git a/zellij-client/src/fake_client.rs b/zellij-client/src/fake_client.rs deleted file mode 100644 index 475298e9..00000000 --- a/zellij-client/src/fake_client.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! The `[fake_client]` is used to attach to a running server session -//! and dispatch actions, that are specified through the command line. -//! Multiple actions at the same time can be dispatched. -use log::debug; -use std::sync::{Arc, Mutex}; -use std::{fs, path::PathBuf, thread}; - -use crate::{ - command_is_executing::CommandIsExecuting, input_handler::input_actions, - os_input_output::ClientOsApi, stdin_ansi_parser::StdinAnsiParser, stdin_handler::stdin_loop, - ClientInfo, ClientInstruction, InputInstruction, -}; -use zellij_utils::{ - channels::{self, ChannelWithContext, SenderWithContext}, - cli::CliArgs, - data::{ClientId, Style}, - errors::ContextType, - input::{actions::Action, config::Config, layout::LayoutFromYaml, options::Options}, - ipc::{ClientAttributes, ClientToServerMsg, ServerToClientMsg}, -}; - -pub fn start_fake_client( - os_input: Box, - _opts: CliArgs, - config: Config, - config_options: Options, - info: ClientInfo, - _layout: Option, - actions: Vec, -) { - debug!("Starting fake Zellij client!"); - let session_name = info.get_session_name(); - - // TODO: Ideally the `fake_client` would not need to specify these options, - // but the `[NewTab:]` action depends on this state being - // even in this client. - let palette = config.themes.clone().map_or_else( - || os_input.load_palette(), - |t| { - t.theme_config(&config_options) - .unwrap_or_else(|| os_input.load_palette()) - }, - ); - - let full_screen_ws = os_input.get_terminal_size_using_fd(0); - let client_attributes = ClientAttributes { - size: full_screen_ws, - style: Style { - colors: palette, - rounded_corners: config.ui.unwrap_or_default().pane_frames.rounded_corners, - }, - keybinds: config.keybinds.clone(), - }; - - let first_msg = ClientToServerMsg::AttachClient(client_attributes, config_options.clone()); - - let zellij_ipc_pipe: PathBuf = { - let mut sock_dir = zellij_utils::consts::ZELLIJ_SOCK_DIR.clone(); - fs::create_dir_all(&sock_dir).unwrap(); - zellij_utils::shared::set_permissions(&sock_dir, 0o700).unwrap(); - sock_dir.push(session_name); - sock_dir - }; - os_input.connect_to_server(&*zellij_ipc_pipe); - os_input.send_to_server(first_msg); - - let mut command_is_executing = CommandIsExecuting::new(); - - let (send_client_instructions, receive_client_instructions): ChannelWithContext< - ClientInstruction, - > = channels::bounded(50); - let send_client_instructions = SenderWithContext::new(send_client_instructions); - - let (send_input_instructions, receive_input_instructions): ChannelWithContext< - InputInstruction, - > = channels::bounded(50); - let send_input_instructions = SenderWithContext::new(send_input_instructions); - - std::panic::set_hook({ - use zellij_utils::errors::handle_panic; - let send_client_instructions = send_client_instructions.clone(); - Box::new(move |info| { - handle_panic(info, &send_client_instructions); - }) - }); - - let stdin_ansi_parser = Arc::new(Mutex::new(StdinAnsiParser::new())); - let _stdin_thread = thread::Builder::new() - .name("stdin_handler".to_string()) - .spawn({ - let os_input = os_input.clone(); - let send_input_instructions = send_input_instructions.clone(); - move || stdin_loop(os_input, send_input_instructions, stdin_ansi_parser) - }); - - let clients: Vec; - os_input.send_to_server(ClientToServerMsg::ListClients); - #[allow(clippy::collapsible_match)] - loop { - if let Some((msg, _)) = os_input.recv_from_server() { - if let ServerToClientMsg::ActiveClients(active_clients) = msg { - clients = active_clients; - break; - } - } - } - debug!("The connected client id's are: {:?}.", clients); - - let _input_thread = thread::Builder::new() - .name("input_handler".to_string()) - .spawn({ - let send_client_instructions = send_client_instructions.clone(); - let command_is_executing = command_is_executing.clone(); - let os_input = os_input.clone(); - let default_mode = config_options.default_mode.unwrap_or_default(); - let session_name = session_name.to_string(); - move || { - input_actions( - os_input, - config, - config_options, - command_is_executing, - clients, - send_client_instructions, - default_mode, - receive_input_instructions, - actions, - session_name, - ) - } - }); - - let router_thread = thread::Builder::new() - .name("router".to_string()) - .spawn({ - let os_input = os_input.clone(); - let mut should_break = false; - move || loop { - if let Some((instruction, err_ctx)) = os_input.recv_from_server() { - err_ctx.update_thread_ctx(); - if let ServerToClientMsg::Exit(_) = instruction { - should_break = true; - } - send_client_instructions.send(instruction.into()).unwrap(); - if should_break { - break; - } - } - } - }) - .unwrap(); - - loop { - let (client_instruction, mut err_ctx) = receive_client_instructions - .recv() - .expect("failed to receive app instruction on channel"); - - err_ctx.add_call(ContextType::Client((&client_instruction).into())); - match client_instruction { - ClientInstruction::Exit(_) => { - os_input.send_to_server(ClientToServerMsg::ClientExited); - break; - }, - ClientInstruction::Error(_) => { - let _ = os_input.send_to_server(ClientToServerMsg::Action(Action::Quit, None)); - // handle_error(backtrace); - }, - ClientInstruction::Render(_) => { - // This is a fake client, that doesn't render, but - // dispatches actions. - }, - ClientInstruction::UnblockInputThread => { - command_is_executing.unblock_input_thread(); - }, - ClientInstruction::SwitchToMode(input_mode) => { - send_input_instructions - .send(InputInstruction::SwitchToMode(input_mode)) - .unwrap(); - }, - _ => {}, - } - } - router_thread.join().unwrap(); -} diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs index bebf1ee7..076ab35d 100644 --- a/zellij-client/src/input_handler.rs +++ b/zellij-client/src/input_handler.rs @@ -11,7 +11,6 @@ use zellij_utils::{ actions::Action, cast_termwiz_key, config::Config, - keybinds::Keybinds, mouse::{MouseButton, MouseEvent}, options::Options, }, @@ -133,7 +132,9 @@ impl InputHandler { } fn handle_key(&mut self, key: &Key, raw_bytes: Vec) { let keybinds = &self.config.keybinds; - for action in Keybinds::key_to_actions(key, raw_bytes, &self.mode, keybinds) { + for action in + keybinds.get_actions_for_key_in_mode_or_default_action(&self.mode, key, raw_bytes) + { let should_exit = self.dispatch_action(action, None); if should_exit { self.should_exit = true; @@ -230,65 +231,6 @@ impl InputHandler { }, } } - fn handle_actions(&mut self, actions: Vec, session_name: &str, clients: Vec) { - let mut detached = false; - for action in actions { - match action { - Action::Quit => { - crate::sessions::kill_session(session_name); - break; - }, - Action::Detach => { - let first = clients.first().unwrap(); - let last = clients.last().unwrap(); - self.os_input - .send_to_server(ClientToServerMsg::DetachSession(vec![*first, *last])); - detached = true; - break; - }, - // Actions, that are independent from the specific client - // and not session idempotent should be specified here - Action::NewTab(_) - | Action::Run(_) - | Action::NewPane(_) - | Action::WriteChars(_) - | Action::EditScrollback - | Action::DumpScreen(_) - | Action::ToggleActiveSyncTab - | Action::ToggleFloatingPanes - | Action::TogglePaneEmbedOrFloating - | Action::TogglePaneFrames - | Action::ToggleFocusFullscreen - | Action::Write(_) => { - let client_id = clients.first().unwrap(); - log::debug!("Sending action to client: {}", client_id); - self.dispatch_action(action, Some(*client_id)); - }, - Action::CloseFocus | Action::CloseTab => { - let client_id = clients.first().unwrap(); - log::debug!("Sending action to client: {}", client_id); - log::warn!("Running this action from the focused pane, can lead to unexpected behaviour."); - self.dispatch_action(action, Some(*client_id)); - }, - _ => { - // FIXME: If a specific `session_id` is specified, - // then only send the actions to that specific `client_id` - for client_id in &clients { - self.dispatch_action(action.clone(), Some(*client_id)); - } - }, - } - } - self.dispatch_action(Action::Detach, None); - self.should_exit = true; - log::error!("Quitting Now. Dispatched the actions"); - if detached { - self.exit(ExitReason::NormalDetached); - } else { - self.exit(ExitReason::Normal); - } - } - /// Dispatches an [`Action`]. /// /// This function's body dictates what each [`Action`] actually does when @@ -329,7 +271,7 @@ impl InputHandler { | Action::Run(_) | Action::ToggleFloatingPanes | Action::TogglePaneEmbedOrFloating - | Action::NewTab(_) + | Action::NewTab(..) | Action::GoToNextTab | Action::GoToPreviousTab | Action::CloseTab @@ -381,29 +323,3 @@ pub(crate) fn input_loop( ) .handle_input(); } -/// Entry point to the module. Instantiates an [`InputHandler`] and starts -/// its [`InputHandler::handle_input()`] loop. -#[allow(clippy::too_many_arguments)] -pub(crate) fn input_actions( - os_input: Box, - config: Config, - options: Options, - command_is_executing: CommandIsExecuting, - clients: Vec, - send_client_instructions: SenderWithContext, - default_mode: InputMode, - receive_input_instructions: Receiver<(InputInstruction, ErrorContext)>, - actions: Vec, - session_name: String, -) { - let _handler = InputHandler::new( - os_input, - command_is_executing, - config, - options, - send_client_instructions, - default_mode, - receive_input_instructions, - ) - .handle_actions(actions, &session_name, clients); -} diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index 9c5169cc..bac08715 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -1,9 +1,9 @@ pub mod os_input_output; +pub mod cli_client; mod command_is_executing; -pub mod fake_client; mod input_handler; -mod sessions; +pub mod old_config_converter; mod stdin_ansi_parser; mod stdin_handler; @@ -30,7 +30,7 @@ use zellij_utils::{ ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg}, termwiz::input::InputEvent, }; -use zellij_utils::{cli::CliArgs, input::layout::LayoutFromYaml}; +use zellij_utils::{cli::CliArgs, input::layout::Layout}; /// Instructions related to the client-side application #[derive(Debug, Clone)] @@ -124,7 +124,7 @@ pub fn start_client( config: Config, config_options: Options, info: ClientInfo, - layout: Option, + layout: Option, ) { info!("Starting Zellij client!"); let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l\u{1b}[?12l"; @@ -143,20 +143,16 @@ pub fn start_client( envs::set_zellij("0".to_string()); config.env.set_vars(); - let palette = config.themes.clone().map_or_else( - || os_input.load_palette(), - |t| { - t.theme_config(&config_options) - .unwrap_or_else(|| os_input.load_palette()) - }, - ); + let palette = config + .theme_config(&config_options) + .unwrap_or_else(|| os_input.load_palette()); let full_screen_ws = os_input.get_terminal_size_using_fd(0); let client_attributes = ClientAttributes { size: full_screen_ws, style: Style { colors: palette, - rounded_corners: config.ui.unwrap_or_default().pane_frames.rounded_corners, + rounded_corners: config.ui.pane_frames.rounded_corners, }, keybinds: config.keybinds.clone(), }; diff --git a/zellij-client/src/old_config_converter/convert_old_yaml_files.rs b/zellij-client/src/old_config_converter/convert_old_yaml_files.rs new file mode 100644 index 00000000..0d5bf2e5 --- /dev/null +++ b/zellij-client/src/old_config_converter/convert_old_yaml_files.rs @@ -0,0 +1,332 @@ +use super::{config_yaml_to_config_kdl, layout_yaml_to_layout_kdl}; +use std::path::PathBuf; +use zellij_utils::{ + cli::CliArgs, + setup::{find_default_config_dir, get_layout_dir, get_theme_dir}, +}; + +const OLD_CONFIG_NAME: &str = "config.yaml"; + +pub fn convert_old_yaml_files(opts: &CliArgs) { + let config_dir = opts.config_dir.clone().or_else(find_default_config_dir); + let layout_dir = get_layout_dir(config_dir.clone()); + let theme_dir = get_theme_dir(find_default_config_dir()); + let specified_config_location = opts.config.as_ref(); + + let mut layout_files_to_convert = vec![]; + let mut theme_files_to_convert = vec![]; + if let Some(layout) = opts.layout.as_ref() { + if layout.extension().map(|s| s.to_string_lossy().to_string()) == Some("yaml".into()) { + if layout.exists() { + layout_files_to_convert.push((layout.clone(), true)); + } + } + } + layout_files_to_convert.dedup(); + if let Some(layout_dir) = layout_dir { + if let Ok(files) = std::fs::read_dir(layout_dir) { + for file in files { + if let Ok(file) = file { + if file + .path() + .extension() + .map(|s| s.to_string_lossy().to_string()) + == Some("yaml".into()) + { + let mut new_file_path = file.path().clone(); + new_file_path.set_extension("kdl"); + if !new_file_path.exists() { + layout_files_to_convert.push((file.path().clone(), false)); + } + } + } + } + } + } + + if let Some(theme_dir) = theme_dir { + if theme_dir.is_dir() { + if let Ok(files) = std::fs::read_dir(theme_dir) { + for entry in files.flatten() { + if let Some(extension) = entry.path().extension() { + if extension == "yaml" { + let mut new_file_path = entry.path().clone(); + new_file_path.set_extension("kdl"); + if !new_file_path.exists() { + theme_files_to_convert.push(entry.path()) + } + } + } + } + } + } + } + + if let Some(config_dir) = config_dir { + let yaml_config_location = specified_config_location.cloned().filter(|c| { + c.extension().map(|s| s.to_string_lossy().to_string()) == Some("yaml".into()) + }); + let specified_yaml_config_location = yaml_config_location.is_some(); + let config_location = + yaml_config_location.unwrap_or_else(|| config_dir.join(OLD_CONFIG_NAME)); + match convert_yaml( + config_location, + layout_files_to_convert, + theme_files_to_convert, + specified_yaml_config_location, + ) { + Ok(should_exit) => { + if should_exit { + std::process::exit(0); + } + }, + Err(e) => { + eprintln!(""); + eprintln!("\u{1b}[1;31mFailed to convert yaml config\u{1b}[m: {}", e); + eprintln!(""); + std::process::exit(1); + }, + } + } +} + +fn print_conversion_title_message() { + println!(""); + println!("\u{1b}[1mZellij has moved to a new configuration format (KDL - https://kdl.dev) and has now been run with an old YAML configuration/layout/theme file.\u{1b}[m"); +} + +fn print_converting_config_message(old_file_name: String, new_file_name: String) { + println!( + "- Converting configuration file: \u{1b}[1;36m{}\u{1b}[m to the new configuration format at the same location: \u{1b}[1;36m{}\u{1b}[m", + old_file_name, + new_file_name + ); +} + +fn print_conversion_layouts_message(layout_files_to_convert: Vec<(PathBuf, bool)>) { + println!("- Converting the following layout YAML files to KDL files in the same location:"); + for (layout_file, _was_explicitly_set) in layout_files_to_convert.iter() { + let mut new_layout_file_name = layout_file.clone(); + new_layout_file_name.set_extension("kdl"); + println!( + "\u{1b}[1;36m{}\u{1b}[m => \u{1b}[1;36m{}\u{1b}[m", + layout_file.as_path().as_os_str().to_string_lossy(), + new_layout_file_name.as_path().as_os_str().to_string_lossy() + ); + } +} + +fn print_conversion_themes_message(theme_files_to_convert: Vec) { + println!("- Converting the following theme YAML files to KDL files in the same location:"); + for theme_file in theme_files_to_convert.iter() { + let mut new_theme_file_name = theme_file.clone(); + new_theme_file_name.set_extension("kdl"); + println!( + "\u{1b}[1;36m{}\u{1b}[m => \u{1b}[1;36m{}\u{1b}[m", + theme_file.as_path().as_os_str().to_string_lossy(), + new_theme_file_name.as_path().as_os_str().to_string_lossy() + ); + } +} + +fn print_no_actions_and_wait_for_user_input() -> Result<(), String> { + println!("\u{1b}[1;32mNo actions are required of you. Press ENTER to continue.\u{1b}[m"); + std::io::stdin() + .read_line(&mut String::new()) + .map_err(|e| format!("Failed to read from STDIN: {:?}", e))?; + Ok(()) +} + +fn print_remain_unmodified_message(will_exit: bool) { + println!("The original file(s) will remain unmodified."); + if !will_exit { + println!("Will then use the new converted file(s) for this and the next runs."); + } + println!(""); +} + +fn print_flag_help_message( + layout_files_to_convert: Vec<(PathBuf, bool)>, + yaml_config_file: &PathBuf, + yaml_config_was_explicitly_set: bool, +) -> Result<(), String> { + println!("\u{1b}[1;32mWhat do you need to do?\u{1b}[m"); + match layout_files_to_convert + .iter() + .find(|(_f, explicit)| *explicit) + { + Some((explicitly_specified_layout, _)) => { + let mut kdl_config_file_path = yaml_config_file.clone(); + let mut kdl_explicitly_specified_layout = explicitly_specified_layout.clone(); + kdl_config_file_path.set_extension("kdl"); + kdl_explicitly_specified_layout.set_extension("kdl"); + if yaml_config_was_explicitly_set { + println!("Since both the YAML config and a YAML layout file were explicitly specified, you'll need to re-run Zellij and point it to the new files:"); + println!( + "\u{1b}[1;33mzellij --config {} --layout {}\u{1b}[m", + kdl_config_file_path + .as_path() + .as_os_str() + .to_string_lossy() + .to_string(), + kdl_explicitly_specified_layout + .as_path() + .as_os_str() + .to_string_lossy() + .to_string(), + ); + } else { + println!("Since a YAML layout was explicitly specified, you'll need to re-run Zellij and point it to the new layout:"); + println!( + "\u{1b}[1;33mzellij --layout {}\u{1b}[m", + kdl_explicitly_specified_layout + .as_path() + .as_os_str() + .to_string_lossy() + .to_string(), + ); + } + }, + None => { + if yaml_config_was_explicitly_set { + let mut kdl_config_file_path = yaml_config_file.clone(); + kdl_config_file_path.set_extension("kdl"); + println!("Since the YAML config was explicitly specified, you'll need to re-run Zellij and point it to the new config:"); + println!( + "\u{1b}[1;33mzellij --config {}\u{1b}[m", + kdl_config_file_path + .as_path() + .as_os_str() + .to_string_lossy() + .to_string(), + ); + } + }, + } + println!(""); + println!("\u{1b}[1;32mPress ENTER to continue.\u{1b}[m"); + std::io::stdin() + .read_line(&mut String::new()) + .map_err(|e| format!("Failed to read from STDIN: {:?}", e))?; + Ok(()) +} + +fn convert_layouts(layout_files_to_convert: Vec<(PathBuf, bool)>) -> Result<(), String> { + for (layout_file, _was_explicitly_set) in layout_files_to_convert { + let raw_layout_file = std::fs::read_to_string(&layout_file) + .map_err(|e| format!("Failed to read layout file {:?}: {:?}", layout_file, e))?; + let kdl_layout = layout_yaml_to_layout_kdl(&raw_layout_file)?; + let mut new_layout_file = layout_file.clone(); + new_layout_file.set_extension("kdl"); + std::fs::write(&new_layout_file, kdl_layout).map_err(|e| { + format!( + "Failed to write new layout file to {:?}: {:?}", + new_layout_file, e + ) + })?; + } + Ok(()) +} + +fn convert_themes(theme_files_to_convert: Vec) -> Result<(), String> { + for theme_file in theme_files_to_convert { + let raw_theme_file = std::fs::read_to_string(&theme_file) + .map_err(|e| format!("Failed to read theme file {:?}: {:?}", theme_file, e))?; + let kdl_theme = config_yaml_to_config_kdl(&raw_theme_file, true)?; + let mut new_theme_file = theme_file.clone(); + new_theme_file.set_extension("kdl"); + std::fs::write(&new_theme_file, kdl_theme).map_err(|e| { + format!( + "Failed to write new theme file to {:?}: {:?}", + new_theme_file, e + ) + })?; + } + Ok(()) +} + +fn convert_config(yaml_config_file: PathBuf, new_config_file: PathBuf) -> Result<(), String> { + if yaml_config_file.exists() && !new_config_file.exists() { + let raw_config_file = std::fs::read_to_string(&yaml_config_file) + .map_err(|e| format!("Failed to read config file {:?}: {:?}", yaml_config_file, e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + std::fs::write(&new_config_file, kdl_config).map_err(|e| { + format!( + "Failed to write new config file to {:?}: {:?}", + new_config_file, e + ) + })?; + } + Ok(()) +} + +fn convert_yaml( + yaml_config_file: PathBuf, + layout_files_to_convert: Vec<(PathBuf, bool)>, + theme_files_to_convert: Vec, + yaml_config_was_explicitly_set: bool, +) -> Result { + let mut should_exit = false; + let mut new_config_file = yaml_config_file.clone(); + new_config_file.set_extension("kdl"); + let yaml_config_file_exists = yaml_config_file.exists(); + let layout_was_explicitly_set = layout_files_to_convert + .iter() + .find(|(_l, was_explicitly_set)| *was_explicitly_set) + .is_some(); + let new_config_file_exists = new_config_file.exists(); + let no_need_to_convert_config = + (new_config_file_exists && !yaml_config_was_explicitly_set) || !yaml_config_file_exists; + if no_need_to_convert_config + && layout_files_to_convert.is_empty() + && theme_files_to_convert.is_empty() + && !layout_was_explicitly_set + { + // Nothing to do... + return Ok(should_exit); + } + print_conversion_title_message(); + if yaml_config_file_exists && !new_config_file_exists { + print_converting_config_message( + yaml_config_file + .as_path() + .as_os_str() + .to_string_lossy() + .to_string(), + new_config_file + .as_path() + .as_os_str() + .to_string_lossy() + .to_string(), + ); + } else if yaml_config_file_exists && new_config_file_exists && yaml_config_was_explicitly_set { + return Err( + format!( + "Specified old YAML format config (--config {}) but a new KDL file exists in that location. To fix, point to it the new file instead: zellij --config {}", + yaml_config_file.as_path().as_os_str().to_string_lossy().to_string(), + new_config_file.as_path().as_os_str().to_string_lossy().to_string() + ) + ); + } + if !layout_files_to_convert.is_empty() { + print_conversion_layouts_message(layout_files_to_convert.clone()); + } + if !theme_files_to_convert.is_empty() { + print_conversion_themes_message(theme_files_to_convert.clone()); + } + print_remain_unmodified_message(layout_was_explicitly_set || yaml_config_was_explicitly_set); + if layout_was_explicitly_set || yaml_config_was_explicitly_set { + print_flag_help_message( + layout_files_to_convert.clone(), + &yaml_config_file, + yaml_config_was_explicitly_set, + )?; + should_exit = true; + } else { + print_no_actions_and_wait_for_user_input()?; + } + convert_layouts(layout_files_to_convert)?; + convert_themes(theme_files_to_convert)?; + convert_config(yaml_config_file, new_config_file)?; + Ok(should_exit) +} diff --git a/zellij-client/src/old_config_converter/mod.rs b/zellij-client/src/old_config_converter/mod.rs new file mode 100644 index 00000000..ac6d7676 --- /dev/null +++ b/zellij-client/src/old_config_converter/mod.rs @@ -0,0 +1,6 @@ +mod convert_old_yaml_files; +mod old_config; +mod old_layout; +pub use convert_old_yaml_files::convert_old_yaml_files; +pub use old_config::config_yaml_to_config_kdl; +pub use old_layout::layout_yaml_to_layout_kdl; diff --git a/zellij-client/src/old_config_converter/old_config.rs b/zellij-client/src/old_config_converter/old_config.rs new file mode 100644 index 00000000..73e098b7 --- /dev/null +++ b/zellij-client/src/old_config_converter/old_config.rs @@ -0,0 +1,1292 @@ +// This is a converter from the old yaml config to the new KDL config. +// +// It is supposed to be mostly self containing - please refrain from adding to it, importing +// from it or changing it +use std::fmt; +use std::path::PathBuf; + +use serde::de::{Error, Visitor}; +use serde::{Deserialize, Deserializer, Serialize}; +use std::collections::{BTreeMap, HashMap}; +use url::Url; + +const ON_FORCE_CLOSE_DESCRIPTION: &'static str = " +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +"; + +const SIMPLIFIED_UI_DESCRIPTION: &'static str = " +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +"; + +const DEFAULT_SHELL_DESCRIPTION: &'static str = " +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +"; + +const PANE_FRAMES_DESCRIPTION: &'static str = " +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +"; + +const DEFAULT_THEME_DESCRIPTION: &'static str = " +// Choose the theme that is specified in the themes section. +// Default: default +// +"; + +const DEFAULT_MODE_DESCRIPTION: &'static str = " +// Choose the mode that zellij uses when starting up. +// Default: normal +// +"; + +const MOUSE_MODE_DESCRIPTION: &'static str = " +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +"; + +const SCROLL_BUFFER_SIZE_DESCRIPTION: &'static str = " +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +"; + +const COPY_COMMAND_DESCRIPTION: &'static str = " +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command \"xclip -selection clipboard\" // x11 +// copy_command \"wl-copy\" // wayland +// copy_command \"pbcopy\" // osx +"; + +const COPY_CLIPBOARD_DESCRIPTION: &'static str = " +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +"; + +const COPY_ON_SELECT_DESCRIPTION: &'static str = " +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +"; + +const SCROLLBACK_EDITOR_DESCRIPTION: &'static str = " +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +"; + +const MIRROR_SESSION_DESCRIPTION: &'static str = " +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +"; + +const DEFAULT_LAYOUT_DESCRIPTION: &'static str = " +// The name of the default layout to load on startup +// Default: \"default\" +// +"; + +const LAYOUT_DIR_DESCRIPTION: &'static str = " +// The folder in which Zellij will look for layouts +// +"; + +const THEME_DIR_DESCRIPTION: &'static str = " +// The folder in which Zellij will look for themes +// +"; + +fn options_yaml_to_options_kdl(options_yaml: &OldOptions, no_comments: bool) -> String { + let mut options_kdl = String::new(); + + macro_rules! push_option { + ($attribute_name:ident, $description_text:ident, $present_pattern:expr) => { + if !no_comments { + options_kdl.push_str($description_text); + } + if let Some($attribute_name) = &options_yaml.$attribute_name { + options_kdl.push_str(&format!($present_pattern, $attribute_name)); + options_kdl.push('\n'); + }; + }; + ($attribute_name:ident, $description_text:ident, $present_pattern:expr, $absent_pattern:expr) => { + if !no_comments { + options_kdl.push_str($description_text); + } + match &options_yaml.$attribute_name { + Some($attribute_name) => { + options_kdl.push_str(&format!($present_pattern, $attribute_name)); + }, + None => { + if !no_comments { + options_kdl.push_str(&format!($absent_pattern)); + } + }, + }; + if !no_comments || options_yaml.$attribute_name.is_some() { + options_kdl.push('\n'); + } + }; + } + + push_option!( + on_force_close, + ON_FORCE_CLOSE_DESCRIPTION, + "on_force_close \"{}\"", + "// on_force_close \"quit\"" + ); + push_option!( + simplified_ui, + SIMPLIFIED_UI_DESCRIPTION, + "simplified_ui {}", + "// simplified_ui true" + ); + push_option!( + default_shell, + DEFAULT_SHELL_DESCRIPTION, + "default_shell {:?}", + "// default_shell \"fish\"" + ); + push_option!( + pane_frames, + PANE_FRAMES_DESCRIPTION, + "pane_frames {}", + "// pane_frames true" + ); + push_option!( + theme, + DEFAULT_THEME_DESCRIPTION, + "theme {:?} ", + "// theme \"default\"" + ); + push_option!( + default_layout, + DEFAULT_LAYOUT_DESCRIPTION, + "default_layout {:?}", + "// default_layout \"compact\"" + ); + push_option!( + default_mode, + DEFAULT_MODE_DESCRIPTION, + "default_mode \"{}\"", + "// default_mode \"locked\"" + ); + push_option!( + mouse_mode, + MOUSE_MODE_DESCRIPTION, + "mouse_mode {}", + "// mouse_mode false" + ); + push_option!( + scroll_buffer_size, + SCROLL_BUFFER_SIZE_DESCRIPTION, + "scroll_buffer_size {}", + "// scroll_buffer_size 10000" + ); + push_option!(copy_command, COPY_COMMAND_DESCRIPTION, "copy_command {:?}"); + push_option!( + copy_clipboard, + COPY_CLIPBOARD_DESCRIPTION, + "copy_clipboard \"{}\"", + "// copy_clipboard \"primary\"" + ); + push_option!( + copy_on_select, + COPY_ON_SELECT_DESCRIPTION, + "copy_on_select {}", + "// copy_on_select false" + ); + push_option!( + scrollback_editor, + SCROLLBACK_EDITOR_DESCRIPTION, + "scrollback_editor {:?}", + "// scrollback_editor \"/usr/bin/vim\"" + ); + push_option!( + mirror_session, + MIRROR_SESSION_DESCRIPTION, + "mirror_session {}", + "// mirror_session true" + ); + push_option!( + layout_dir, + LAYOUT_DIR_DESCRIPTION, + "layout_dir {:?}", + "// layout_dir /path/to/my/layout_dir" + ); + push_option!( + theme_dir, + THEME_DIR_DESCRIPTION, + "theme_dir {:?}", + "// theme_dir \"/path/to/my/theme_dir\"" + ); + + options_kdl +} + +fn env_yaml_to_env_kdl(env_yaml: &OldEnvironmentVariablesFromYaml) -> String { + let mut env_kdl = String::new(); + let mut env_vars: Vec<(String, String)> = env_yaml + .env + .iter() + .map(|(name, val)| (name.clone(), val.clone())) + .collect(); + env_vars.sort_unstable(); + env_kdl.push_str("env {\n"); + for (name, val) in env_vars { + env_kdl.push_str(&format!(" {} \"{}\"\n", name, val)); + } + env_kdl.push_str("}\n"); + env_kdl +} + +fn plugins_yaml_to_plugins_kdl(plugins_yaml_to_plugins_kdl: &OldPluginsConfigFromYaml) -> String { + let mut plugins_kdl = String::new(); + if !&plugins_yaml_to_plugins_kdl.0.is_empty() { + plugins_kdl.push_str("\n"); + plugins_kdl.push_str("plugins {\n") + } + for plugin_config in &plugins_yaml_to_plugins_kdl.0 { + if plugin_config._allow_exec_host_cmd { + plugins_kdl.push_str(&format!( + " {} {{ path {:?}; _allow_exec_host_cmd true; }}\n", + plugin_config.tag.0, plugin_config.path + )); + } else { + plugins_kdl.push_str(&format!( + " {} {{ path {:?}; }}\n", + plugin_config.tag.0, plugin_config.path + )); + } + } + if !&plugins_yaml_to_plugins_kdl.0.is_empty() { + plugins_kdl.push_str("}\n") + } + plugins_kdl +} + +fn ui_config_yaml_to_ui_config_kdl(ui_config_yaml: &OldUiConfigFromYaml) -> String { + let mut kdl_ui_config = String::new(); + if ui_config_yaml.pane_frames.rounded_corners { + kdl_ui_config.push_str("\n"); + kdl_ui_config.push_str("ui {\n"); + kdl_ui_config.push_str(" pane_frames {\n"); + kdl_ui_config.push_str(" rounded_corners true\n"); + kdl_ui_config.push_str(" }\n"); + kdl_ui_config.push_str("}\n"); + } else { + // I'm not sure this is a thing, but since it's possible, why not? + kdl_ui_config.push_str("\n"); + kdl_ui_config.push_str("ui {\n"); + kdl_ui_config.push_str(" pane_frames {\n"); + kdl_ui_config.push_str(" rounded_corners false\n"); + kdl_ui_config.push_str(" }\n"); + kdl_ui_config.push_str("}\n"); + } + kdl_ui_config +} + +fn theme_config_yaml_to_theme_config_kdl( + theme_config_yaml: &OldThemesFromYamlIntermediate, +) -> String { + macro_rules! theme_color { + ($theme:ident, $color:ident, $color_name:expr, $kdl_theme_config:expr) => { + match $theme.palette.$color { + OldPaletteColorFromYaml::Rgb((r, g, b)) => { + $kdl_theme_config + .push_str(&format!(" {} {} {} {}\n", $color_name, r, g, b)); + }, + OldPaletteColorFromYaml::EightBit(eight_bit_color) => { + $kdl_theme_config + .push_str(&format!(" {} {}\n", $color_name, eight_bit_color)); + }, + OldPaletteColorFromYaml::Hex(OldHexColor(r, g, b)) => { + $kdl_theme_config + .push_str(&format!(" {} {} {} {}\n", $color_name, r, g, b)); + }, + } + }; + } + + let mut kdl_theme_config = String::new(); + if !theme_config_yaml.0.is_empty() { + kdl_theme_config.push_str("themes {\n") + } + let mut themes: Vec<(String, OldTheme)> = theme_config_yaml + .0 + .iter() + .map(|(theme_name, theme)| (theme_name.clone(), theme.clone())) + .collect(); + themes.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + for (theme_name, theme) in themes { + kdl_theme_config.push_str(&format!(" {} {{\n", theme_name)); + theme_color!(theme, fg, "fg", kdl_theme_config); + theme_color!(theme, bg, "bg", kdl_theme_config); + theme_color!(theme, black, "black", kdl_theme_config); + theme_color!(theme, red, "red", kdl_theme_config); + theme_color!(theme, green, "green", kdl_theme_config); + theme_color!(theme, yellow, "yellow", kdl_theme_config); + theme_color!(theme, blue, "blue", kdl_theme_config); + theme_color!(theme, magenta, "magenta", kdl_theme_config); + theme_color!(theme, cyan, "cyan", kdl_theme_config); + theme_color!(theme, white, "white", kdl_theme_config); + theme_color!(theme, orange, "orange", kdl_theme_config); + kdl_theme_config.push_str(" }\n"); + } + if !theme_config_yaml.0.is_empty() { + kdl_theme_config.push_str("}\n") + } + kdl_theme_config +} + +fn keybinds_yaml_to_keybinds_kdl(keybinds_yaml: &OldKeybindsFromYaml) -> String { + let mut kdl_keybinds = String::new(); + let modes = vec![ + // mode sort order + OldInputMode::Normal, + OldInputMode::Locked, + OldInputMode::Pane, + OldInputMode::Tab, + OldInputMode::Resize, + OldInputMode::Move, + OldInputMode::Scroll, + OldInputMode::Session, + OldInputMode::Search, + OldInputMode::EnterSearch, + OldInputMode::RenameTab, + OldInputMode::RenamePane, + OldInputMode::Prompt, + OldInputMode::Tmux, + ]; + + // title and global unbinds / clear-defaults + match &keybinds_yaml.unbind { + OldUnbind::Keys(keys_to_unbind) => { + kdl_keybinds.push_str("keybinds {\n"); + let key_string: String = keys_to_unbind + .iter() + .map(|k| format!("\"{}\"", k)) + .collect::>() + .join(" "); + kdl_keybinds.push_str(&format!(" unbind {}\n", key_string)); + }, + OldUnbind::All(should_unbind_all_defaults) => { + if *should_unbind_all_defaults { + kdl_keybinds.push_str("keybinds clear-defaults=true {\n"); + } else { + kdl_keybinds.push_str("keybinds {\n"); + } + }, + } + + for mode in modes { + if let Some(mode_keybinds) = keybinds_yaml.keybinds.get(&mode) { + let mut should_clear_mode_defaults = false; + let mut kdl_mode_keybinds = String::new(); + for key_action_unbind in mode_keybinds { + match key_action_unbind { + OldKeyActionUnbind::KeyAction(key_action) => { + let keys = &key_action.key; + let actions = &key_action.action; + let key_string: String = keys + .iter() + .map(|k| format!("\"{}\"", k)) + .collect::>() + .join(" "); + let actions_string: String = actions + .iter() + .map(|a| format!("{};", a)) + .collect::>() + .join(" "); + kdl_mode_keybinds.push_str(&format!( + " bind {} {{ {} }}\n", + key_string, actions_string + )); + }, + OldKeyActionUnbind::Unbind(unbind) => match &unbind.unbind { + OldUnbind::Keys(keys_to_unbind) => { + let key_string: String = keys_to_unbind + .iter() + .map(|k| format!("\"{}\"", k)) + .collect::>() + .join(" "); + kdl_mode_keybinds.push_str(&format!(" unbind {}\n", key_string)); + }, + OldUnbind::All(unbind_all) => { + if *unbind_all { + should_clear_mode_defaults = true; + } + }, + }, + } + } + if should_clear_mode_defaults { + kdl_keybinds.push_str(&format!(" {} clear-defaults=true {{\n", mode)); + } else { + kdl_keybinds.push_str(&format!(" {} {{\n", mode)); + } + kdl_keybinds.push_str(&kdl_mode_keybinds); + kdl_keybinds.push_str(" }\n"); + } + } + kdl_keybinds.push_str("}\n"); + kdl_keybinds +} + +pub fn config_yaml_to_config_kdl( + raw_yaml_config: &str, + no_comments: bool, +) -> Result { + // returns the raw kdl config + let config_from_yaml: OldConfigFromYaml = serde_yaml::from_str(raw_yaml_config) + .map_err(|e| format!("Failed to parse yaml: {:?}", e))?; + let mut kdl_config = String::new(); + if let Some(old_config_keybinds) = config_from_yaml.keybinds.as_ref() { + kdl_config.push_str(&keybinds_yaml_to_keybinds_kdl(old_config_keybinds)); + } + if let Some(old_config_options) = config_from_yaml.options.as_ref() { + kdl_config.push_str(&options_yaml_to_options_kdl( + old_config_options, + no_comments, + )); + } + if let Some(old_config_env_variables) = config_from_yaml.env.as_ref() { + kdl_config.push_str(&env_yaml_to_env_kdl(old_config_env_variables)); + } + kdl_config.push_str(&plugins_yaml_to_plugins_kdl(&config_from_yaml.plugins)); + if let Some(old_ui_config) = config_from_yaml.ui.as_ref() { + kdl_config.push_str(&ui_config_yaml_to_ui_config_kdl(old_ui_config)); + } + if let Some(old_themes_config) = config_from_yaml.themes.as_ref() { + kdl_config.push_str(&theme_config_yaml_to_theme_config_kdl(old_themes_config)); + } + Ok(kdl_config) +} + +#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq)] +pub struct OldConfigFromYaml { + #[serde(flatten)] + pub options: Option, + pub keybinds: Option, + pub themes: Option, + #[serde(flatten)] + pub env: Option, + #[serde(default)] + pub plugins: OldPluginsConfigFromYaml, + pub ui: Option, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct OldKeybindsFromYaml { + #[serde(flatten)] + keybinds: HashMap>, + #[serde(default)] + unbind: OldUnbind, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[serde(untagged)] +enum OldUnbind { + // This is the correct order, don't rearrange! + // Suspected Bug in the untagged macro. + // 1. Keys + Keys(Vec), + // 2. All + All(bool), +} + +impl Default for OldUnbind { + fn default() -> OldUnbind { + OldUnbind::All(false) + } +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +enum OldKeyActionUnbind { + KeyAction(OldKeyActionFromYaml), + Unbind(OldUnbindFromYaml), +} + +/// Intermediate struct used for deserialisation +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +struct OldKeyActionFromYaml { + action: Vec, + key: Vec, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +struct OldUnbindFromYaml { + unbind: OldUnbind, +} + +/// Main configuration. +#[derive(Debug, Clone, PartialEq, Deserialize)] +struct OldConfig { + pub keybinds: OldKeybinds, + pub options: OldOptions, + pub themes: Option, + pub plugins: OldPluginsConfig, + pub ui: Option, + pub env: OldEnvironmentVariablesFromYaml, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +struct OldKeybinds(HashMap); + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +struct OldModeKeybinds(BTreeMap>); + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct OldThemesFromYamlIntermediate(HashMap); + +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Default)] +struct OldPaletteFromYaml { + pub fg: OldPaletteColorFromYaml, + pub bg: OldPaletteColorFromYaml, + pub black: OldPaletteColorFromYaml, + pub red: OldPaletteColorFromYaml, + pub green: OldPaletteColorFromYaml, + pub yellow: OldPaletteColorFromYaml, + pub blue: OldPaletteColorFromYaml, + pub magenta: OldPaletteColorFromYaml, + pub cyan: OldPaletteColorFromYaml, + pub white: OldPaletteColorFromYaml, + pub orange: OldPaletteColorFromYaml, +} + +/// Intermediate deserialization enum +// This is here in order to make the untagged enum work +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[serde(untagged)] +enum OldPaletteColorFromYaml { + Rgb((u8, u8, u8)), + EightBit(u8), + Hex(OldHexColor), +} + +impl From for (u8, u8, u8) { + fn from(e: OldHexColor) -> (u8, u8, u8) { + let OldHexColor(r, g, b) = e; + (r, g, b) + } +} + +struct OldHexColorVisitor(); + +impl<'de> Visitor<'de> for OldHexColorVisitor { + type Value = OldHexColor; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a hex color in the format #RGB or #RRGGBB") + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + if let Some(stripped) = s.strip_prefix('#') { + return self.visit_str(stripped); + } + + if s.len() == 3 { + Ok(OldHexColor( + u8::from_str_radix(&s[0..1], 16).map_err(E::custom)? * 0x11, + u8::from_str_radix(&s[1..2], 16).map_err(E::custom)? * 0x11, + u8::from_str_radix(&s[2..3], 16).map_err(E::custom)? * 0x11, + )) + } else if s.len() == 6 { + Ok(OldHexColor( + u8::from_str_radix(&s[0..2], 16).map_err(E::custom)?, + u8::from_str_radix(&s[2..4], 16).map_err(E::custom)?, + u8::from_str_radix(&s[4..6], 16).map_err(E::custom)?, + )) + } else { + Err(Error::custom( + "Hex color must be of form \"#RGB\" or \"#RRGGBB\"", + )) + } + } +} + +impl<'de> Deserialize<'de> for OldHexColor { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(OldHexColorVisitor()) + } +} + +impl Default for OldPaletteColorFromYaml { + fn default() -> Self { + OldPaletteColorFromYaml::EightBit(0) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] +struct OldHexColor(u8, u8, u8); + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +struct OldTheme { + #[serde(flatten)] + palette: OldPaletteFromYaml, +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)] +pub struct OldUiConfigFromYaml { + pub pane_frames: OldFrameConfigFromYaml, +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)] +pub struct OldFrameConfigFromYaml { + pub rounded_corners: bool, +} + +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +pub struct OldEnvironmentVariablesFromYaml { + env: HashMap, +} + +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub struct OldPluginsConfigFromYaml(Vec); + +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +struct OldPluginConfigFromYaml { + pub path: PathBuf, + pub tag: OldPluginTag, + #[serde(default)] + pub run: OldPluginTypeFromYaml, + #[serde(default)] + pub config: serde_yaml::Value, + #[serde(default)] + pub _allow_exec_host_cmd: bool, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +enum OldPluginTypeFromYaml { + Headless, + Pane, +} + +impl Default for OldPluginTypeFromYaml { + fn default() -> Self { + Self::Pane + } +} + +/// Tag used to identify the plugin in layout and config yaml files +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] +struct OldPluginTag(String); + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +struct OldPluginsConfig(HashMap); + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +struct OldPluginConfig { + /// Path of the plugin, see resolve_wasm_bytes for resolution semantics + pub path: PathBuf, + /// Plugin type + pub run: OldPluginType, + /// Allow command execution from plugin + pub _allow_exec_host_cmd: bool, + /// Original location of the + pub location: OldRunPluginLocation, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +enum OldRunPluginLocation { + File(PathBuf), + Zellij(OldPluginTag), +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +enum OldPluginType { + /// Starts immediately when Zellij is started and runs without a visible pane + Headless, + /// Runs once per pane declared inside a layout file + Pane(Option), // tab_index +} + +#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)] +pub enum OldOnForceClose { + #[serde(alias = "quit")] + Quit, + #[serde(alias = "detach")] + Detach, +} + +impl std::fmt::Display for OldOnForceClose { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::Quit => write!(f, "quit"), + Self::Detach => write!(f, "detach"), + } + } +} + +impl Default for OldOnForceClose { + fn default() -> Self { + Self::Detach + } +} + +#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)] +pub enum OldClipboard { + #[serde(alias = "system")] + System, + #[serde(alias = "primary")] + Primary, +} + +impl std::fmt::Display for OldClipboard { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::System => write!(f, "system"), + Self::Primary => write!(f, "primary"), + } + } +} + +impl Default for OldClipboard { + fn default() -> Self { + Self::System + } +} + +#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize)] +pub struct OldOptions { + #[serde(default)] + pub simplified_ui: Option, + pub theme: Option, + pub default_mode: Option, + pub default_shell: Option, + pub default_layout: Option, + pub layout_dir: Option, + pub theme_dir: Option, + #[serde(default)] + pub mouse_mode: Option, + #[serde(default)] + pub pane_frames: Option, + #[serde(default)] + pub mirror_session: Option, + pub on_force_close: Option, + pub scroll_buffer_size: Option, + #[serde(default)] + pub copy_command: Option, + #[serde(default)] + pub copy_clipboard: Option, + #[serde(default)] + pub copy_on_select: Option, + pub scrollback_editor: Option, +} + +/// Describes the different input modes, which change the way that keystrokes will be interpreted. +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)] +pub enum OldInputMode { + /// 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, + /// `EnterSearch` mode allows for typing in the needle for a search in the scroll buffer of a pane. + #[serde(alias = "entersearch")] + EnterSearch, + /// `Search` mode allows for searching a term in a pane (superset of `Scroll`). + #[serde(alias = "search")] + Search, + /// `RenameTab` mode allows assigning a new name to a tab. + #[serde(alias = "renametab")] + RenameTab, + /// `RenamePane` mode allows assigning a new name to a pane. + #[serde(alias = "renamepane")] + RenamePane, + /// `Session` mode allows detaching sessions + #[serde(alias = "session")] + Session, + /// `Move` mode allows moving the different existing panes within a tab + #[serde(alias = "move")] + Move, + /// `Prompt` mode allows interacting with active prompts. + #[serde(alias = "prompt")] + Prompt, + /// `Tmux` mode allows for basic tmux keybindings functionality + #[serde(alias = "tmux")] + Tmux, +} + +impl std::fmt::Display for OldInputMode { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::Normal => write!(f, "normal"), + Self::Locked => write!(f, "locked"), + Self::Resize => write!(f, "resize"), + Self::Pane => write!(f, "pane"), + Self::Tab => write!(f, "tab"), + Self::Scroll => write!(f, "scroll"), + Self::EnterSearch => write!(f, "entersearch"), + Self::Search => write!(f, "search"), + Self::RenameTab => write!(f, "RenameTab"), + Self::RenamePane => write!(f, "RenamePane"), + Self::Session => write!(f, "session"), + Self::Move => write!(f, "move"), + Self::Prompt => write!(f, "prompt"), + Self::Tmux => write!(f, "tmux"), + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] +enum OldKey { + PageDown, + PageUp, + Left, + Down, + Up, + Right, + Home, + End, + Backspace, + Delete, + Insert, + F(u8), + Char(char), + Alt(OldCharOrArrow), + Ctrl(char), + BackTab, + Null, + Esc, +} + +impl std::fmt::Display for OldKey { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::PageDown => write!(f, "PageDown"), + Self::PageUp => write!(f, "PageUp"), + Self::Left => write!(f, "Left"), + Self::Down => write!(f, "Down"), + Self::Up => write!(f, "Up"), + Self::Right => write!(f, "Right"), + Self::Home => write!(f, "Home"), + Self::End => write!(f, "End"), + Self::Backspace => write!(f, "Backspace"), + Self::Delete => write!(f, "Delete"), + Self::Insert => write!(f, "Insert"), + Self::F(index) => write!(f, "F{}", index), + Self::Char(c) => match c { + '\n' => write!(f, "Enter"), + '\t' => write!(f, "Tab"), + '\"' => write!(f, "\\\""), // make sure it is escaped because otherwise it will be + // seen as a KDL string starter/terminator + ' ' => write!(f, "Space"), + _ => write!(f, "{}", c), + }, + Self::Alt(char_or_arrow) => match char_or_arrow { + OldCharOrArrow::Char(c) => write!(f, "Alt {}", c), + OldCharOrArrow::Direction(direction) => match direction { + OldDirection::Left => write!(f, "Alt Left"), + OldDirection::Right => write!(f, "Alt Right"), + OldDirection::Up => write!(f, "Alt Up"), + OldDirection::Down => write!(f, "Alt Down"), + }, + }, + Self::Ctrl(c) => write!(f, "Ctrl {}", c), + Self::BackTab => write!(f, "Tab"), + Self::Null => write!(f, "Null"), + Self::Esc => write!(f, "Esc"), + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] +#[serde(untagged)] +enum OldCharOrArrow { + Char(char), + Direction(OldDirection), +} + +/// The four directions (left, right, up, down). +#[derive(Eq, Clone, Copy, Debug, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord)] +enum OldDirection { + Left, + Right, + Up, + Down, +} + +impl std::fmt::Display for OldDirection { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::Left => write!(f, "Left"), + Self::Right => write!(f, "Right"), + Self::Up => write!(f, "Up"), + Self::Down => write!(f, "Down"), + } + } +} + +impl Default for OldDirection { + fn default() -> Self { + OldDirection::Left + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +enum OldAction { + Quit, + Write(Vec), + WriteChars(String), + SwitchToMode(OldInputMode), + Resize(OldResizeDirection), + FocusNextPane, + FocusPreviousPane, + SwitchFocus, + MoveFocus(OldDirection), + MoveFocusOrTab(OldDirection), + MovePane(Option), + DumpScreen(String), + EditScrollback, + ScrollUp, + ScrollUpAt(OldPosition), + ScrollDown, + ScrollDownAt(OldPosition), + ScrollToBottom, + PageScrollUp, + PageScrollDown, + HalfPageScrollUp, + HalfPageScrollDown, + ToggleFocusFullscreen, + TogglePaneFrames, + ToggleActiveSyncTab, + NewPane(Option), + TogglePaneEmbedOrFloating, + ToggleFloatingPanes, + CloseFocus, + PaneNameInput(Vec), + UndoRenamePane, + NewTab(Option), + NoOp, + GoToNextTab, + GoToPreviousTab, + CloseTab, + GoToTab(u32), + ToggleTab, + TabNameInput(Vec), + UndoRenameTab, + Run(OldRunCommandAction), + Detach, + LeftClick(OldPosition), + RightClick(OldPosition), + MiddleClick(OldPosition), + LeftMouseRelease(OldPosition), + RightMouseRelease(OldPosition), + MiddleMouseRelease(OldPosition), + MouseHoldLeft(OldPosition), + MouseHoldRight(OldPosition), + MouseHoldMiddle(OldPosition), + Copy, + Confirm, + Deny, + SkipConfirm(Box), + SearchInput(Vec), + Search(OldSearchDirection), + SearchToggleOption(OldSearchOption), +} + +impl std::fmt::Display for OldAction { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::Quit => write!(f, "Quit"), + Self::Write(bytes) => write!( + f, + "Write {}", + bytes + .iter() + .map(|c| format!("{}", *c)) + .collect::>() + .join(" ") + ), + Self::WriteChars(chars) => write!(f, "WriteChars \"{}\"", chars), + Self::SwitchToMode(input_mode) => write!(f, "SwitchToMode \"{}\"", input_mode), + Self::Resize(resize_direction) => write!(f, "Resize \"{}\"", resize_direction), + Self::FocusNextPane => write!(f, "FocusNextPane"), + Self::FocusPreviousPane => write!(f, "FocusPreviousPane"), + Self::SwitchFocus => write!(f, "SwitchFocus"), + Self::MoveFocus(direction) => write!(f, "MoveFocus \"{}\"", direction), + Self::MoveFocusOrTab(direction) => write!(f, "MoveFocusOrTab \"{}\"", direction), + Self::MovePane(direction) => match direction { + Some(direction) => write!(f, "MovePane \"{}\"", direction), + None => write!(f, "MovePane"), + }, + Self::DumpScreen(file) => write!(f, "DumpScreen \"{}\"", file), + Self::EditScrollback => write!(f, "EditScrollback"), + Self::ScrollUp => write!(f, "ScrollUp"), + Self::ScrollDown => write!(f, "ScrollDown"), + Self::ScrollToBottom => write!(f, "ScrollToBottom"), + Self::PageScrollUp => write!(f, "PageScrollUp"), + Self::PageScrollDown => write!(f, "PageScrollDown"), + Self::HalfPageScrollUp => write!(f, "HalfPageScrollUp"), + Self::HalfPageScrollDown => write!(f, "HalfPageScrollDown"), + Self::ToggleFocusFullscreen => write!(f, "ToggleFocusFullscreen"), + Self::TogglePaneFrames => write!(f, "TogglePaneFrames"), + Self::ToggleActiveSyncTab => write!(f, "ToggleActiveSyncTab"), + Self::NewPane(direction) => match direction { + Some(direction) => write!(f, "NewPane \"{}\"", direction), + None => write!(f, "NewPane"), + }, + Self::TogglePaneEmbedOrFloating => write!(f, "TogglePaneEmbedOrFloating"), + Self::ToggleFloatingPanes => write!(f, "ToggleFloatingPanes"), + Self::CloseFocus => write!(f, "CloseFocus"), + Self::PaneNameInput(bytes) => write!( + f, + "PaneNameInput {}", + bytes + .iter() + .map(|c| format!("{}", *c)) + .collect::>() + .join(" ") + ), + Self::UndoRenamePane => write!(f, "UndoRenamePane"), + Self::NewTab(_) => write!(f, "NewTab"), + Self::NoOp => write!(f, "NoOp"), + Self::GoToNextTab => write!(f, "GoToNextTab"), + Self::GoToPreviousTab => write!(f, "GoToPreviousTab"), + Self::CloseTab => write!(f, "CloseTab"), + Self::GoToTab(index) => write!(f, "GoToTab {}", index), + Self::ToggleTab => write!(f, "ToggleTab"), + // Self::TabNameInput(bytes) => write!(f, "TabNameInput {}", format!("{}", bytes.iter().map(|c| format!("{}", *c)).collect::>().join(" "))), + Self::TabNameInput(bytes) => write!( + f, + "TabNameInput {}", + bytes + .iter() + .map(|c| format!("{}", *c)) + .collect::>() + .join(" ") + ), + Self::UndoRenameTab => write!(f, "UndoRenameTab"), + Self::Run(run_command_action) => { + let mut run_block_serialized = format!("Run {:?}", run_command_action.command); + for arg in &run_command_action.args { + run_block_serialized.push_str(&format!(" \"{}\"", arg)); + } + match (&run_command_action.cwd, run_command_action.direction) { + (Some(cwd), Some(direction)) => { + run_block_serialized.push_str(&format!( + "{{ cwd {:?}; direction \"{}\"; }}", + cwd, direction + )); + }, + (None, Some(direction)) => { + run_block_serialized + .push_str(&format!("{{ direction \"{}\"; }}", direction)); + }, + (Some(cwd), None) => { + run_block_serialized.push_str(&format!("{{ cwd {:?}; }}", cwd)); + }, + (None, None) => {}, + } + write!(f, "{}", run_block_serialized) + }, + Self::Detach => write!(f, "Detach"), + Self::Copy => write!(f, "Copy"), + Self::Confirm => write!(f, "Confirm"), + Self::Deny => write!(f, "Deny"), + Self::SearchInput(bytes) => write!( + f, + "SearchInput {}", + bytes + .iter() + .map(|c| format!("{}", *c)) + .collect::>() + .join(" ") + ), + Self::Search(direction) => write!(f, "Search \"{}\"", direction), + Self::SearchToggleOption(option) => write!(f, "SearchToggleOption \"{}\"", option), + _ => Err(std::fmt::Error), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] +enum OldSearchDirection { + Down, + Up, +} + +impl std::fmt::Display for OldSearchDirection { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::Down => write!(f, "Down"), + Self::Up => write!(f, "Up"), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +enum OldSearchOption { + CaseSensitivity, + WholeWord, + Wrap, +} + +impl std::fmt::Display for OldSearchOption { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::CaseSensitivity => write!(f, "CaseSensitivity"), + Self::WholeWord => write!(f, "WholeWord"), + Self::Wrap => write!(f, "Wrap"), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +enum OldResizeDirection { + Left, + Right, + Up, + Down, + Increase, + Decrease, +} + +impl std::fmt::Display for OldResizeDirection { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + Self::Left => write!(f, "Left"), + Self::Right => write!(f, "Right"), + Self::Up => write!(f, "Up"), + Self::Down => write!(f, "Down"), + Self::Increase => write!(f, "Increase"), + Self::Decrease => write!(f, "Decrease"), + } + } +} + +#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, PartialOrd, Deserialize, Serialize)] +struct OldPosition { + pub line: OldLine, + pub column: OldColumn, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, PartialOrd)] +struct OldLine(pub isize); +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, PartialOrd)] +struct OldColumn(pub usize); + +#[derive(Clone, Debug, Deserialize, Default, Serialize, PartialEq, Eq)] +struct OldRunCommandAction { + #[serde(rename = "cmd")] + pub command: PathBuf, + #[serde(default)] + pub args: Vec, + #[serde(default)] + pub cwd: Option, + #[serde(default)] + pub direction: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +struct OldTabLayout { + #[serde(default)] + pub direction: OldDirection, + pub pane_name: Option, + #[serde(default)] + pub borderless: bool, + #[serde(default)] + pub parts: Vec, + pub split_size: Option, + #[serde(default)] + pub name: String, + pub focus: Option, + pub run: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +enum OldSplitSize { + #[serde(alias = "percent")] + Percent(u64), // 1 to 100 + #[serde(alias = "fixed")] + Fixed(usize), // An absolute number of columns or rows +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +enum OldRunFromYaml { + #[serde(rename = "plugin")] + Plugin(OldRunPluginFromYaml), + #[serde(rename = "command")] + Command(OldRunCommand), +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +struct OldRunPluginFromYaml { + #[serde(default)] + pub _allow_exec_host_cmd: bool, + pub location: Url, +} + +#[derive(Clone, Debug, Deserialize, Default, Serialize, PartialEq, Eq)] +pub struct OldRunCommand { + #[serde(alias = "cmd")] + pub command: PathBuf, + #[serde(default)] + pub args: Vec, + #[serde(default)] + pub cwd: Option, +} + +// The unit test location. +#[path = "./unit/convert_config_tests.rs"] +#[cfg(test)] +mod convert_config_test; diff --git a/zellij-client/src/old_config_converter/old_layout.rs b/zellij-client/src/old_config_converter/old_layout.rs new file mode 100644 index 00000000..cd1aa66f --- /dev/null +++ b/zellij-client/src/old_config_converter/old_layout.rs @@ -0,0 +1,557 @@ +// This is a converter from the old yaml layout to the new KDL layout. +// +// It is supposed to be mostly self containing - please refrain from adding to it, importing +// from it or changing it +use super::old_config::{config_yaml_to_config_kdl, OldConfigFromYaml, OldRunCommand}; +use serde::{Deserialize, Serialize}; +use std::vec::Vec; +use std::{fmt, path::PathBuf}; +use url::Url; + +fn pane_line( + pane_name: Option<&String>, + split_size: Option, + focus: Option, + borderless: bool, +) -> String { + let mut pane_line = format!("pane"); + if let Some(pane_name) = pane_name { + pane_line.push_str(&format!(" name=\"{}\"", pane_name)); + } + if let Some(split_size) = split_size { + pane_line.push_str(&format!(" size={}", split_size)); + } + if let Some(focus) = focus { + pane_line.push_str(&format!(" focus={}", focus)); + } + if borderless { + pane_line.push_str(" borderless=true"); + } + pane_line +} + +fn tab_line( + pane_name: Option<&String>, + split_size: Option, + focus: Option, + borderless: bool, +) -> String { + let mut pane_line = format!("tab"); + if let Some(pane_name) = pane_name { + pane_line.push_str(&format!(" name=\"{}\"", pane_name)); + } + if let Some(split_size) = split_size { + pane_line.push_str(&format!(" size={}", split_size)); + } + if let Some(focus) = focus { + pane_line.push_str(&format!(" focus={}", focus)); + } + if borderless { + pane_line.push_str(" borderless=true"); + } + pane_line +} + +fn pane_line_with_children( + pane_name: Option<&String>, + split_size: Option, + focus: Option, + borderless: bool, + split_direction: OldDirection, +) -> String { + let mut pane_line = format!("pane"); + if let Some(pane_name) = pane_name { + pane_line.push_str(&format!(" name=\"{}\"", pane_name)); + } + if let Some(split_size) = split_size { + pane_line.push_str(&format!(" size={}", split_size)); + } + if let Some(focus) = focus { + pane_line.push_str(&format!(" focus={}", focus)); + } + pane_line.push_str(&format!(" split_direction=\"{}\"", split_direction)); + if borderless { + pane_line.push_str(" borderless=true"); + } + pane_line +} + +fn pane_command_line( + pane_name: Option<&String>, + split_size: Option, + focus: Option, + borderless: bool, + command: &PathBuf, +) -> String { + let mut pane_line = format!("pane command={:?}", command); + if let Some(pane_name) = pane_name { + pane_line.push_str(&format!(" name=\"{}\"", pane_name)); + } + if let Some(split_size) = split_size { + pane_line.push_str(&format!(" size={}", split_size)); + } + if let Some(focus) = focus { + pane_line.push_str(&format!(" focus={}", focus)); + } + if borderless { + pane_line.push_str(" borderless=true"); + } + pane_line +} + +fn tab_line_with_children( + pane_name: Option<&String>, + split_size: Option, + focus: Option, + borderless: bool, + split_direction: OldDirection, +) -> String { + let mut pane_line = format!("tab"); + if let Some(pane_name) = pane_name { + pane_line.push_str(&format!(" name=\"{}\"", pane_name)); + } + if let Some(split_size) = split_size { + pane_line.push_str(&format!(" size={}", split_size)); + } + if let Some(focus) = focus { + pane_line.push_str(&format!(" focus={}", focus)); + } + pane_line.push_str(&format!(" split_direction=\"{}\"", split_direction)); + if borderless { + pane_line.push_str(" borderless=true"); + } + pane_line +} + +fn stringify_template( + template: &OldLayoutTemplate, + indentation: String, + has_no_tabs: bool, + is_base: bool, +) -> String { + let mut stringified = if is_base { + String::new() + } else { + String::from("\n") + }; + if is_base && !template.parts.is_empty() && template.direction == OldDirection::Vertical { + // we don't support specifying the split direction in the layout node + // eg. layout split_direction="Vertical" { .. } <== this is not supported!! + // so we need to add a child wrapper with the split direction instead: + // layout { + // pane split_direction="Vertical" { .. } + // } + let child_indentation = format!("{} ", &indentation); + stringified.push_str(&stringify_template( + template, + child_indentation, + has_no_tabs, + false, + )); + } else if !template.parts.is_empty() { + if !is_base { + stringified.push_str(&format!( + "{}{} {{", + indentation, + pane_line_with_children( + template.pane_name.as_ref(), + template.split_size, + template.focus, + template.borderless, + template.direction + ) + )); + } + for part in &template.parts { + let child_indentation = format!("{} ", &indentation); + stringified.push_str(&stringify_template( + &part, + child_indentation, + has_no_tabs, + false, + )); + } + if !is_base { + stringified.push_str(&format!("\n{}}}", indentation)); + } + } else if template.body && !has_no_tabs { + stringified.push_str(&format!("{}children", indentation)); + } else { + match template.run.as_ref() { + Some(OldRunFromYaml::Plugin(plugin_from_yaml)) => { + stringified.push_str(&format!( + "{}{} {{\n", + &indentation, + pane_line( + template.pane_name.as_ref(), + template.split_size, + template.focus, + template.borderless + ) + )); + stringified.push_str(&format!( + "{} plugin location=\"{}\"\n", + &indentation, plugin_from_yaml.location + )); + stringified.push_str(&format!("{}}}", &indentation)); + }, + Some(OldRunFromYaml::Command(command_from_yaml)) => { + stringified.push_str(&format!( + "{}{}", + &indentation, + &pane_command_line( + template.pane_name.as_ref(), + template.split_size, + template.focus, + template.borderless, + &command_from_yaml.command + ) + )); + if let Some(cwd) = command_from_yaml.cwd.as_ref() { + stringified.push_str(&format!(" cwd={:?}", cwd)); + } + if !command_from_yaml.args.is_empty() { + stringified.push_str(" {\n"); + stringified.push_str(&format!( + "{} args {}\n", + &indentation, + command_from_yaml + .args + .iter() + .map(|s| format!("\"{}\"", s)) + .collect::>() + .join(" ") + )); + stringified.push_str(&format!("{}}}", &indentation)); + } + }, + None => { + stringified.push_str(&format!( + "{}{}", + &indentation, + pane_line( + template.pane_name.as_ref(), + template.split_size, + template.focus, + template.borderless + ) + )); + }, + }; + } + stringified +} + +fn stringify_tabs(tabs: Vec) -> String { + let mut stringified = String::new(); + for tab in tabs { + let child_indentation = String::from(" "); + if !tab.parts.is_empty() { + stringified.push_str(&format!( + "\n{}{} {{", + child_indentation, + tab_line_with_children( + tab.pane_name.as_ref(), + tab.split_size, + tab.focus, + tab.borderless, + tab.direction + ) + )); + let tab_template = OldLayoutTemplate::from(tab); + stringified.push_str(&stringify_template( + &tab_template, + child_indentation.clone(), + true, + true, + )); + stringified.push_str(&format!("\n{}}}", child_indentation)); + } else { + stringified.push_str(&format!( + "\n{}{}", + child_indentation, + tab_line( + tab.pane_name.as_ref(), + tab.split_size, + tab.focus, + tab.borderless + ) + )); + } + } + stringified +} + +pub fn layout_yaml_to_layout_kdl(raw_yaml_layout: &str) -> Result { + // returns the raw kdl config + let layout_from_yaml: OldLayoutFromYamlIntermediate = serde_yaml::from_str(raw_yaml_layout) + .map_err(|e| format!("Failed to parse yaml: {:?}", e))?; + let mut kdl_layout = String::new(); + kdl_layout.push_str("layout {"); + let template = layout_from_yaml.template; + let tabs = layout_from_yaml.tabs; + let has_no_tabs = tabs.is_empty() + || tabs.len() == 1 && tabs.get(0).map(|t| t.parts.is_empty()).unwrap_or(false); + if has_no_tabs { + let indentation = String::from(""); + kdl_layout.push_str(&stringify_template( + &template, + indentation, + has_no_tabs, + true, + )); + } else { + kdl_layout.push_str("\n default_tab_template {"); + let indentation = String::from(" "); + kdl_layout.push_str(&stringify_template( + &template, + indentation, + has_no_tabs, + true, + )); + kdl_layout.push_str("\n }"); + kdl_layout.push_str(&stringify_tabs(tabs)); + } + kdl_layout.push_str("\n}"); + let layout_config = config_yaml_to_config_kdl(raw_yaml_layout, true)?; + if let Some(session_name) = layout_from_yaml.session.name { + kdl_layout.push_str(&format!("\nsession_name \"{}\"", session_name)); + if let Some(attach_to_session) = layout_from_yaml.session.attach { + kdl_layout.push_str(&format!("\nattach_to_session {}", attach_to_session)); + } + } + if !layout_config.is_empty() { + kdl_layout.push('\n'); + } + kdl_layout.push_str(&layout_config); + Ok(kdl_layout) +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)] +pub enum OldDirection { + #[serde(alias = "horizontal")] + Horizontal, + #[serde(alias = "vertical")] + Vertical, +} + +impl fmt::Display for OldDirection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + match self { + Self::Horizontal => write!(f, "Horizontal"), + Self::Vertical => write!(f, "Vertical"), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +pub enum OldSplitSize { + #[serde(alias = "percent")] + Percent(u64), // 1 to 100 + #[serde(alias = "fixed")] + Fixed(usize), // An absolute number of columns or rows +} + +impl fmt::Display for OldSplitSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + match self { + Self::Percent(percent) => write!(f, "\"{}%\"", percent), + Self::Fixed(fixed_size) => write!(f, "{}", fixed_size), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub enum OldRunFromYaml { + #[serde(rename = "plugin")] + Plugin(OldRunPluginFromYaml), + #[serde(rename = "command")] + Command(OldRunCommand), +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct OldRunPluginFromYaml { + #[serde(default)] + pub _allow_exec_host_cmd: bool, + pub location: Url, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[serde(default)] +pub struct OldLayoutFromYamlIntermediate { + #[serde(default)] + pub template: OldLayoutTemplate, + #[serde(default)] + pub borderless: bool, + #[serde(default)] + pub tabs: Vec, + #[serde(default)] + pub session: OldSessionFromYaml, + #[serde(flatten)] + pub config: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] +#[serde(default)] +pub struct OldLayoutFromYaml { + #[serde(default)] + pub session: OldSessionFromYaml, + #[serde(default)] + pub template: OldLayoutTemplate, + #[serde(default)] + pub borderless: bool, + #[serde(default)] + pub tabs: Vec, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] +pub struct OldSessionFromYaml { + pub name: Option, + #[serde(default = "default_as_some_true")] + pub attach: Option, +} + +fn default_as_some_true() -> Option { + Some(true) +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct OldLayoutTemplate { + pub direction: OldDirection, + #[serde(default)] + pub pane_name: Option, + #[serde(default)] + pub borderless: bool, + #[serde(default)] + pub parts: Vec, + #[serde(default)] + pub body: bool, + pub split_size: Option, + pub focus: Option, + pub run: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct OldTabLayout { + #[serde(default)] + pub direction: OldDirection, + pub pane_name: Option, + #[serde(default)] + pub borderless: bool, + #[serde(default)] + pub parts: Vec, + pub split_size: Option, + #[serde(default)] + pub name: String, + pub focus: Option, + pub run: Option, +} + +impl From for OldLayoutTemplate { + fn from(old_tab_layout: OldTabLayout) -> Self { + OldLayoutTemplate { + direction: old_tab_layout.direction, + pane_name: old_tab_layout.pane_name.clone(), + borderless: old_tab_layout.borderless, + parts: old_tab_layout.parts.iter().map(|o| o.into()).collect(), + split_size: old_tab_layout.split_size, + focus: old_tab_layout.focus, + run: old_tab_layout.run.clone(), + body: false, + } + } +} + +impl From<&OldTabLayout> for OldLayoutTemplate { + fn from(old_tab_layout: &OldTabLayout) -> Self { + OldLayoutTemplate { + direction: old_tab_layout.direction, + pane_name: old_tab_layout.pane_name.clone(), + borderless: old_tab_layout.borderless, + parts: old_tab_layout.parts.iter().map(|o| o.into()).collect(), + split_size: old_tab_layout.split_size, + focus: old_tab_layout.focus, + run: old_tab_layout.run.clone(), + body: false, + } + } +} + +impl From<&mut OldTabLayout> for OldLayoutTemplate { + fn from(old_tab_layout: &mut OldTabLayout) -> Self { + OldLayoutTemplate { + direction: old_tab_layout.direction, + pane_name: old_tab_layout.pane_name.clone(), + borderless: old_tab_layout.borderless, + parts: old_tab_layout.parts.iter().map(|o| o.into()).collect(), + split_size: old_tab_layout.split_size, + focus: old_tab_layout.focus, + run: old_tab_layout.run.clone(), + body: false, + } + } +} + +impl From for OldLayoutFromYaml { + fn from(layout_from_yaml_intermediate: OldLayoutFromYamlIntermediate) -> Self { + Self { + template: layout_from_yaml_intermediate.template, + borderless: layout_from_yaml_intermediate.borderless, + tabs: layout_from_yaml_intermediate.tabs, + session: layout_from_yaml_intermediate.session, + } + } +} + +impl From for OldLayoutFromYamlIntermediate { + fn from(layout_from_yaml: OldLayoutFromYaml) -> Self { + Self { + template: layout_from_yaml.template, + borderless: layout_from_yaml.borderless, + tabs: layout_from_yaml.tabs, + config: None, + session: layout_from_yaml.session, + } + } +} + +impl Default for OldLayoutFromYamlIntermediate { + fn default() -> Self { + OldLayoutFromYaml::default().into() + } +} + +impl Default for OldLayoutTemplate { + fn default() -> Self { + Self { + direction: OldDirection::Horizontal, + pane_name: None, + body: false, + borderless: false, + parts: vec![OldLayoutTemplate { + direction: OldDirection::Horizontal, + pane_name: None, + body: true, + borderless: false, + split_size: None, + focus: None, + run: None, + parts: vec![], + }], + split_size: None, + focus: None, + run: None, + } + } +} + +impl Default for OldDirection { + fn default() -> Self { + OldDirection::Horizontal + } +} + +// The unit test location. +#[path = "./unit/convert_layout_tests.rs"] +#[cfg(test)] +mod convert_layout_test; diff --git a/zellij-client/src/old_config_converter/unit/convert_config_tests.rs b/zellij-client/src/old_config_converter/unit/convert_config_tests.rs new file mode 100644 index 00000000..444d8775 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/convert_config_tests.rs @@ -0,0 +1,126 @@ +use crate::old_config_converter::config_yaml_to_config_kdl; +use insta::assert_snapshot; +use std::path::PathBuf; +use std::{fs::File, io::prelude::*}; + +#[test] +fn properly_convert_default_config() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_default_yaml_config.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn convert_config_with_custom_options() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_yaml_config_with_custom_options.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn convert_config_with_keybind_unbinds_in_mode() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbinds_in_mode.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn convert_config_with_global_keybind_unbinds() -> Result<(), String> { + let fixture = PathBuf::from(format!("{}/src/old_config_converter/unit/fixtures/old_yaml_config_with_global_keybind_unbinds.yaml", env!("CARGO_MANIFEST_DIR"))); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn convert_config_with_unbind_all_keys_per_mode() -> Result<(), String> { + let fixture = PathBuf::from(format!("{}/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbind_all_keys_per_mode.yaml", env!("CARGO_MANIFEST_DIR"))); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn convert_config_with_env_variables() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_yaml_config_with_env_variables.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn convert_config_with_ui_config() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_yaml_config_with_ui.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn convert_config_with_themes_config() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_yaml_config_with_themes.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = config_yaml_to_config_kdl(&raw_config_file, false)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} diff --git a/zellij-client/src/old_config_converter/unit/convert_layout_tests.rs b/zellij-client/src/old_config_converter/unit/convert_layout_tests.rs new file mode 100644 index 00000000..30e689bb --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/convert_layout_tests.rs @@ -0,0 +1,142 @@ +use crate::old_config_converter::layout_yaml_to_layout_kdl; +use insta::assert_snapshot; +use std::path::PathBuf; +use std::{fs::File, io::prelude::*}; + +#[test] +fn properly_convert_default_layout() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_default_yaml_layout.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_with_session_name() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_with_session_name_and_attach_false() -> Result<(), String> { + let fixture = PathBuf::from(format!("{}/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name_and_attach_false.yaml", env!("CARGO_MANIFEST_DIR"))); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_with_config() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_with_config_and_session_name() -> Result<(), String> { + let fixture = PathBuf::from(format!("{}/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config_and_session_name.yaml", env!("CARGO_MANIFEST_DIR"))); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_example_1() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/multiple_tabs_layout.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_example_2() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/multiple_tabs_layout_htop_command.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_example_3() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/run_htop_layout.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} + +#[test] +fn properly_convert_layout_example_4() -> Result<(), String> { + let fixture = PathBuf::from(format!( + "{}/src/old_config_converter/unit/fixtures/run_htop_layout_with_plugins.yaml", + env!("CARGO_MANIFEST_DIR") + )); + let mut handle = File::open(&fixture).map_err(|e| format!("{}", e))?; + let mut raw_config_file = String::new(); + handle + .read_to_string(&mut raw_config_file) + .map_err(|e| format!("{}", e))?; + let kdl_config = layout_yaml_to_layout_kdl(&raw_config_file)?; + assert_snapshot!(format!("{}", kdl_config)); + Ok(()) +} diff --git a/src/tests/fixtures/layouts/focus-tab-layout.yaml b/zellij-client/src/old_config_converter/unit/fixtures/multiple_tabs_layout.yaml similarity index 98% rename from src/tests/fixtures/layouts/focus-tab-layout.yaml rename to zellij-client/src/old_config_converter/unit/fixtures/multiple_tabs_layout.yaml index 1d019020..04fca4a5 100644 --- a/src/tests/fixtures/layouts/focus-tab-layout.yaml +++ b/zellij-client/src/old_config_converter/unit/fixtures/multiple_tabs_layout.yaml @@ -30,13 +30,11 @@ tabs: Percent: 50 - direction: Vertical - direction: Vertical - focus: true parts: - direction: Vertical split_size: Percent: 50 - direction: Vertical - focus: true split_size: Percent: 50 - direction: Vertical diff --git a/zellij-client/src/old_config_converter/unit/fixtures/multiple_tabs_layout_htop_command.yaml b/zellij-client/src/old_config_converter/unit/fixtures/multiple_tabs_layout_htop_command.yaml new file mode 100644 index 00000000..1449aa71 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/multiple_tabs_layout_htop_command.yaml @@ -0,0 +1,93 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: + location: "zellij:tab-bar" + borderless: true + - direction: Vertical + body: true + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: + location: "zellij:status-bar" + borderless: true + +tabs: +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop} + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Horizontal + split_size: + Percent: 50 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical +- direction: Vertical + run: + command: {cmd: htop, args: ["-C"]} +- direction: Vertical +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 20 + run: + plugin: + location: "zellij:strider" + - direction: Horizontal + split_size: + Percent: 80 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 40 + - direction: Horizontal + split_size: + Percent: 60 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 diff --git a/zellij-utils/assets/config/default.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_default_yaml_config.yaml similarity index 99% rename from zellij-utils/assets/config/default.yaml rename to zellij-client/src/old_config_converter/unit/fixtures/old_default_yaml_config.yaml index 2aecc6d8..cf0e5150 100644 --- a/zellij-utils/assets/config/default.yaml +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_default_yaml_config.yaml @@ -573,13 +573,13 @@ plugins: # Options: # - detach (Default) # - quit -#on_force_close: quit +# on_force_close: quit # Send a request for a simplified ui (without arrow fonts) to plugins # Options: # - true # - false (Default) -#simplified_ui: true +# simplified_ui: true # Choose the path to the default shell that zellij will use for opening new panes # Default: $SHELL diff --git a/zellij-utils/assets/layouts/default.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_default_yaml_layout.yaml similarity index 100% rename from zellij-utils/assets/layouts/default.yaml rename to zellij-client/src/old_config_converter/unit/fixtures/old_default_yaml_layout.yaml diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_custom_options.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_custom_options.yaml new file mode 100644 index 00000000..797a3f22 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_custom_options.yaml @@ -0,0 +1,639 @@ +--- +# Configuration for zellij. + +# In order to troubleshoot your configuration try using the following command: +# `zellij setup --check` +# It should show current config locations and features that are enabled. + +keybinds: + unbind: true + normal: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [NewPane: ] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right ] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up, ] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + locked: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'g',] + resize: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'n', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [Resize: Left,] + key: [Char: 'h', Left,] + - action: [Resize: Down,] + key: [Char: 'j', Down,] + - action: [Resize: Up,] + key: [Char: 'k', Up, ] + - action: [Resize: Right,] + key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Char: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + pane: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'p', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [MoveFocus: Left,] + key: [ Char: 'h', Left,] + - action: [MoveFocus: Right,] + key: [ Char: 'l', Right,] + - action: [MoveFocus: Down,] + key: [ Char: 'j', Down,] + - action: [MoveFocus: Up,] + key: [ Char: 'k', Up,] + - action: [SwitchFocus,] + key: [Char: 'p'] + - action: [NewPane: , SwitchToMode: Normal,] + key: [Char: 'n',] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: 'd',] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: 'r',] + - action: [CloseFocus, SwitchToMode: Normal,] + key: [Char: 'x',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'f',] + - action: [TogglePaneFrames, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [ToggleFloatingPanes, SwitchToMode: Normal,] + key: [Char: 'w'] + - action: [TogglePaneEmbedOrFloating, SwitchToMode: Normal,] + key: [Char: 'e'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: RenamePane, PaneNameInput: [0],] + key: [Char: 'c'] + move: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'h', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] + - action: [MovePane: Left,] + key: [Char: 'h', Left,] + - action: [MovePane: Down,] + key: [Char: 'j', Down,] + - action: [MovePane: Up,] + key: [Char: 'k', Up, ] + - action: [MovePane: Right,] + key: [Char: 'l', Right,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tab: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 't', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: 'r'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [GoToPreviousTab,] + key: [ Char: 'h', Left, Up, Char: 'k',] + - action: [GoToNextTab,] + key: [ Char: 'l', Right,Down, Char: 'j'] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'n',] + - action: [CloseTab, SwitchToMode: Normal,] + key: [ Char: 'x',] + - action: [ToggleActiveSyncTab, SwitchToMode: Normal,] + key: [Char: 's'] + - action: [GoToTab: 1, SwitchToMode: Normal,] + key: [ Char: '1',] + - action: [GoToTab: 2, SwitchToMode: Normal,] + key: [ Char: '2',] + - action: [GoToTab: 3, SwitchToMode: Normal,] + key: [ Char: '3',] + - action: [GoToTab: 4, SwitchToMode: Normal,] + key: [ Char: '4',] + - action: [GoToTab: 5, SwitchToMode: Normal,] + key: [ Char: '5',] + - action: [GoToTab: 6, SwitchToMode: Normal,] + key: [ Char: '6',] + - action: [GoToTab: 7, SwitchToMode: Normal,] + key: [ Char: '7',] + - action: [GoToTab: 8, SwitchToMode: Normal,] + key: [ Char: '8',] + - action: [GoToTab: 9, SwitchToMode: Normal,] + key: [ Char: '9',] + - action: [ToggleTab] + key: [ Char: "\t" ] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + scroll: + - action: [EditScrollback, SwitchToMode: Normal] + key: [Char: 'e'] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + entersearch: + - action: [SwitchToMode: Search,] + key: [Char: "\n"] + - action: [SearchInput: [27], SwitchToMode: Scroll,] + key: [Ctrl: 'c', Esc] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + search: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + - action: [Search: Down] + key: [Char: 'n'] + - action: [Search: Up] + key: [Char: 'p'] + - action: [SearchToggleOption: CaseSensitivity] + key: [Char: 'c'] + - action: [SearchToggleOption: Wrap] + key: [Char: 'w'] + - action: [SearchToggleOption: WholeWord] + key: [Char: 'o'] + renametab: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenameTab , SwitchToMode: Tab,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + renamepane: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenamePane , SwitchToMode: Pane,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + session: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Detach,] + key: [Char: 'd',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tmux: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Scroll,] + key: [ Char: '['] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Write: [2,], SwitchToMode: Normal] + key: [Ctrl: 'b'] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: "\"",] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: '%',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'c',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: ','] + - action: [GoToPreviousTab, SwitchToMode: Normal,] + key: [ Char: 'p'] + - action: [GoToNextTab, SwitchToMode: Normal,] + key: [ Char: 'n'] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Left,] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Right,] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Down,] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Up,] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Char: 'h'] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Char: 'l'] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Char: 'j'] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Char: 'k'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [FocusNextPane,] + key: [ Char: 'o'] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [Detach,] + key: [Char: 'd',] +plugins: + - path: tab-bar + tag: tab-bar + - path: status-bar + tag: status-bar + - path: strider + tag: strider + - path: compact-bar + tag: compact-bar + +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# eg. when terminal window with an active zellij session is closed +# Options: +# - detach (Default) +# - quit +on_force_close: quit + +# Send a request for a simplified ui (without arrow fonts) to plugins +# Options: +# - true +# - false (Default) +simplified_ui: true + +# Choose the path to the default shell that zellij will use for opening new panes +# Default: $SHELL +default_shell: fish + +# Toggle between having pane frames around the panes +# Options: +# - true (default) +# - false +pane_frames: true + +# Choose the theme that is specified in the themes section. +# For some examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +# Default: default +theme: default + +# Choose the mode that zellij uses when starting up. +# Default: normal +default_mode: locked + +# Toggle enabling the mouse mode. +# On certain configurations, or terminals this could +# potentially interfere with copying text. +# Options: +# - true (default) +# - false +mouse_mode: false + +# Configure the scroll back buffer size +# This is the number of lines zellij stores for each pane in the scroll back +# buffer. Excess number of lines are discarded in a FIFO fashion. +# Valid values: positive integers +# Default value: 10000 +scroll_buffer_size: 10000 + +# Provide a command to execute when copying text. The text will be piped to +# the stdin of the program to perform the copy. This can be used with +# terminal emulators which do not support the OSC 52 ANSI control sequence +# that will be used by default if this option is not set. +# Examples: +#copy_command: "xclip -selection clipboard" # x11 +#copy_command: "wl-copy" # wayland +copy_command: "pbcopy" # osx + +# Choose the destination for copied text +# Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +# Does not apply when using copy_command. +# Options: +# - system (default) +# - primary +copy_clipboard: primary + +# Enable or disable automatic copy (and clear) of selection when releasing mouse +copy_on_select: true + +# Path to the default editor to use to edit pane scrollbuffer +scrollback_editor: /usr/bin/nano diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_env_variables.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_env_variables.yaml new file mode 100644 index 00000000..26006ba3 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_env_variables.yaml @@ -0,0 +1,644 @@ +--- +# Configuration for zellij. + +# In order to troubleshoot your configuration try using the following command: +# `zellij setup --check` +# It should show current config locations and features that are enabled. + +keybinds: + unbind: true + normal: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [NewPane: ] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right ] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up, ] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + locked: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'g',] + resize: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'n', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [Resize: Left,] + key: [Char: 'h', Left,] + - action: [Resize: Down,] + key: [Char: 'j', Down,] + - action: [Resize: Up,] + key: [Char: 'k', Up, ] + - action: [Resize: Right,] + key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Char: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + pane: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'p', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [MoveFocus: Left,] + key: [ Char: 'h', Left,] + - action: [MoveFocus: Right,] + key: [ Char: 'l', Right,] + - action: [MoveFocus: Down,] + key: [ Char: 'j', Down,] + - action: [MoveFocus: Up,] + key: [ Char: 'k', Up,] + - action: [SwitchFocus,] + key: [Char: 'p'] + - action: [NewPane: , SwitchToMode: Normal,] + key: [Char: 'n',] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: 'd',] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: 'r',] + - action: [CloseFocus, SwitchToMode: Normal,] + key: [Char: 'x',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'f',] + - action: [TogglePaneFrames, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [ToggleFloatingPanes, SwitchToMode: Normal,] + key: [Char: 'w'] + - action: [TogglePaneEmbedOrFloating, SwitchToMode: Normal,] + key: [Char: 'e'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: RenamePane, PaneNameInput: [0],] + key: [Char: 'c'] + move: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'h', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] + - action: [MovePane: Left,] + key: [Char: 'h', Left,] + - action: [MovePane: Down,] + key: [Char: 'j', Down,] + - action: [MovePane: Up,] + key: [Char: 'k', Up, ] + - action: [MovePane: Right,] + key: [Char: 'l', Right,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tab: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 't', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: 'r'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [GoToPreviousTab,] + key: [ Char: 'h', Left, Up, Char: 'k',] + - action: [GoToNextTab,] + key: [ Char: 'l', Right,Down, Char: 'j'] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'n',] + - action: [CloseTab, SwitchToMode: Normal,] + key: [ Char: 'x',] + - action: [ToggleActiveSyncTab, SwitchToMode: Normal,] + key: [Char: 's'] + - action: [GoToTab: 1, SwitchToMode: Normal,] + key: [ Char: '1',] + - action: [GoToTab: 2, SwitchToMode: Normal,] + key: [ Char: '2',] + - action: [GoToTab: 3, SwitchToMode: Normal,] + key: [ Char: '3',] + - action: [GoToTab: 4, SwitchToMode: Normal,] + key: [ Char: '4',] + - action: [GoToTab: 5, SwitchToMode: Normal,] + key: [ Char: '5',] + - action: [GoToTab: 6, SwitchToMode: Normal,] + key: [ Char: '6',] + - action: [GoToTab: 7, SwitchToMode: Normal,] + key: [ Char: '7',] + - action: [GoToTab: 8, SwitchToMode: Normal,] + key: [ Char: '8',] + - action: [GoToTab: 9, SwitchToMode: Normal,] + key: [ Char: '9',] + - action: [ToggleTab] + key: [ Char: "\t" ] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + scroll: + - action: [EditScrollback, SwitchToMode: Normal] + key: [Char: 'e'] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + entersearch: + - action: [SwitchToMode: Search,] + key: [Char: "\n"] + - action: [SearchInput: [27], SwitchToMode: Scroll,] + key: [Ctrl: 'c', Esc] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + search: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + - action: [Search: Down] + key: [Char: 'n'] + - action: [Search: Up] + key: [Char: 'p'] + - action: [SearchToggleOption: CaseSensitivity] + key: [Char: 'c'] + - action: [SearchToggleOption: Wrap] + key: [Char: 'w'] + - action: [SearchToggleOption: WholeWord] + key: [Char: 'o'] + renametab: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenameTab , SwitchToMode: Tab,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + renamepane: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenamePane , SwitchToMode: Pane,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + session: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Detach,] + key: [Char: 'd',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tmux: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Scroll,] + key: [ Char: '['] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Write: [2,], SwitchToMode: Normal] + key: [Ctrl: 'b'] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: "\"",] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: '%',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'c',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: ','] + - action: [GoToPreviousTab, SwitchToMode: Normal,] + key: [ Char: 'p'] + - action: [GoToNextTab, SwitchToMode: Normal,] + key: [ Char: 'n'] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Left,] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Right,] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Down,] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Up,] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Char: 'h'] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Char: 'l'] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Char: 'j'] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Char: 'k'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [FocusNextPane,] + key: [ Char: 'o'] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [Detach,] + key: [Char: 'd',] +plugins: + - path: tab-bar + tag: tab-bar + - path: status-bar + tag: status-bar + - path: strider + tag: strider + - path: compact-bar + tag: compact-bar + +env: + foo: bar + bar: baz + RUST_BACKTRACE: "1" + +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# eg. when terminal window with an active zellij session is closed +# Options: +# - detach (Default) +# - quit +# on_force_close: quit + +# Send a request for a simplified ui (without arrow fonts) to plugins +# Options: +# - true +# - false (Default) +# simplified_ui: true + +# Choose the path to the default shell that zellij will use for opening new panes +# Default: $SHELL +# default_shell: fish + +# Toggle between having pane frames around the panes +# Options: +# - true (default) +# - false +#pane_frames: true + +# Choose the theme that is specified in the themes section. +# For some examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +# Default: default +#theme: default + +# Choose the mode that zellij uses when starting up. +# Default: normal +#default_mode: locked + +# Toggle enabling the mouse mode. +# On certain configurations, or terminals this could +# potentially interfere with copying text. +# Options: +# - true (default) +# - false +#mouse_mode: false + +# Configure the scroll back buffer size +# This is the number of lines zellij stores for each pane in the scroll back +# buffer. Excess number of lines are discarded in a FIFO fashion. +# Valid values: positive integers +# Default value: 10000 +#scroll_buffer_size: 10000 + +# Provide a command to execute when copying text. The text will be piped to +# the stdin of the program to perform the copy. This can be used with +# terminal emulators which do not support the OSC 52 ANSI control sequence +# that will be used by default if this option is not set. +# Examples: +#copy_command: "xclip -selection clipboard" # x11 +#copy_command: "wl-copy" # wayland +#copy_command: "pbcopy" # osx + +# Choose the destination for copied text +# Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +# Does not apply when using copy_command. +# Options: +# - system (default) +# - primary +#copy_clipboard: primary + +# Enable or disable automatic copy (and clear) of selection when releasing mouse +#copy_on_select: true + +# Path to the default editor to use to edit pane scrollbuffer +# scrollback_editor: /usr/bin/nano diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_global_keybind_unbinds.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_global_keybind_unbinds.yaml new file mode 100644 index 00000000..819764cb --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_global_keybind_unbinds.yaml @@ -0,0 +1,639 @@ +--- +# Configuration for zellij. + +# In order to troubleshoot your configuration try using the following command: +# `zellij setup --check` +# It should show current config locations and features that are enabled. + +keybinds: + unbind: [Ctrl: 'g', Char: ' '] + normal: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [NewPane: ] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right ] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up, ] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + locked: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'g',] + resize: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'n', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [Resize: Left,] + key: [Char: 'h', Left,] + - action: [Resize: Down,] + key: [Char: 'j', Down,] + - action: [Resize: Up,] + key: [Char: 'k', Up, ] + - action: [Resize: Right,] + key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Char: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + pane: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'p', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [MoveFocus: Left,] + key: [ Char: 'h', Left,] + - action: [MoveFocus: Right,] + key: [ Char: 'l', Right,] + - action: [MoveFocus: Down,] + key: [ Char: 'j', Down,] + - action: [MoveFocus: Up,] + key: [ Char: 'k', Up,] + - action: [SwitchFocus,] + key: [Char: 'p'] + - action: [NewPane: , SwitchToMode: Normal,] + key: [Char: 'n',] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: 'd',] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: 'r',] + - action: [CloseFocus, SwitchToMode: Normal,] + key: [Char: 'x',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'f',] + - action: [TogglePaneFrames, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [ToggleFloatingPanes, SwitchToMode: Normal,] + key: [Char: 'w'] + - action: [TogglePaneEmbedOrFloating, SwitchToMode: Normal,] + key: [Char: 'e'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: RenamePane, PaneNameInput: [0],] + key: [Char: 'c'] + move: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'h', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] + - action: [MovePane: Left,] + key: [Char: 'h', Left,] + - action: [MovePane: Down,] + key: [Char: 'j', Down,] + - action: [MovePane: Up,] + key: [Char: 'k', Up, ] + - action: [MovePane: Right,] + key: [Char: 'l', Right,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tab: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 't', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: 'r'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [GoToPreviousTab,] + key: [ Char: 'h', Left, Up, Char: 'k',] + - action: [GoToNextTab,] + key: [ Char: 'l', Right,Down, Char: 'j'] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'n',] + - action: [CloseTab, SwitchToMode: Normal,] + key: [ Char: 'x',] + - action: [ToggleActiveSyncTab, SwitchToMode: Normal,] + key: [Char: 's'] + - action: [GoToTab: 1, SwitchToMode: Normal,] + key: [ Char: '1',] + - action: [GoToTab: 2, SwitchToMode: Normal,] + key: [ Char: '2',] + - action: [GoToTab: 3, SwitchToMode: Normal,] + key: [ Char: '3',] + - action: [GoToTab: 4, SwitchToMode: Normal,] + key: [ Char: '4',] + - action: [GoToTab: 5, SwitchToMode: Normal,] + key: [ Char: '5',] + - action: [GoToTab: 6, SwitchToMode: Normal,] + key: [ Char: '6',] + - action: [GoToTab: 7, SwitchToMode: Normal,] + key: [ Char: '7',] + - action: [GoToTab: 8, SwitchToMode: Normal,] + key: [ Char: '8',] + - action: [GoToTab: 9, SwitchToMode: Normal,] + key: [ Char: '9',] + - action: [ToggleTab] + key: [ Char: "\t" ] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + scroll: + - action: [EditScrollback, SwitchToMode: Normal] + key: [Char: 'e'] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + entersearch: + - action: [SwitchToMode: Search,] + key: [Char: "\n"] + - action: [SearchInput: [27], SwitchToMode: Scroll,] + key: [Ctrl: 'c', Esc] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + search: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + - action: [Search: Down] + key: [Char: 'n'] + - action: [Search: Up] + key: [Char: 'p'] + - action: [SearchToggleOption: CaseSensitivity] + key: [Char: 'c'] + - action: [SearchToggleOption: Wrap] + key: [Char: 'w'] + - action: [SearchToggleOption: WholeWord] + key: [Char: 'o'] + renametab: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenameTab , SwitchToMode: Tab,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + renamepane: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenamePane , SwitchToMode: Pane,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + session: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Detach,] + key: [Char: 'd',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tmux: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Scroll,] + key: [ Char: '['] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Write: [2,], SwitchToMode: Normal] + key: [Ctrl: 'b'] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: "\"",] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: '%',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'c',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: ','] + - action: [GoToPreviousTab, SwitchToMode: Normal,] + key: [ Char: 'p'] + - action: [GoToNextTab, SwitchToMode: Normal,] + key: [ Char: 'n'] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Left,] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Right,] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Down,] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Up,] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Char: 'h'] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Char: 'l'] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Char: 'j'] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Char: 'k'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [FocusNextPane,] + key: [ Char: 'o'] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [Detach,] + key: [Char: 'd',] +plugins: + - path: tab-bar + tag: tab-bar + - path: status-bar + tag: status-bar + - path: strider + tag: strider + - path: compact-bar + tag: compact-bar + +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# eg. when terminal window with an active zellij session is closed +# Options: +# - detach (Default) +# - quit +# on_force_close: quit + +# Send a request for a simplified ui (without arrow fonts) to plugins +# Options: +# - true +# - false (Default) +# simplified_ui: true + +# Choose the path to the default shell that zellij will use for opening new panes +# Default: $SHELL +# default_shell: fish + +# Toggle between having pane frames around the panes +# Options: +# - true (default) +# - false +#pane_frames: true + +# Choose the theme that is specified in the themes section. +# For some examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +# Default: default +#theme: default + +# Choose the mode that zellij uses when starting up. +# Default: normal +#default_mode: locked + +# Toggle enabling the mouse mode. +# On certain configurations, or terminals this could +# potentially interfere with copying text. +# Options: +# - true (default) +# - false +#mouse_mode: false + +# Configure the scroll back buffer size +# This is the number of lines zellij stores for each pane in the scroll back +# buffer. Excess number of lines are discarded in a FIFO fashion. +# Valid values: positive integers +# Default value: 10000 +#scroll_buffer_size: 10000 + +# Provide a command to execute when copying text. The text will be piped to +# the stdin of the program to perform the copy. This can be used with +# terminal emulators which do not support the OSC 52 ANSI control sequence +# that will be used by default if this option is not set. +# Examples: +#copy_command: "xclip -selection clipboard" # x11 +#copy_command: "wl-copy" # wayland +#copy_command: "pbcopy" # osx + +# Choose the destination for copied text +# Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +# Does not apply when using copy_command. +# Options: +# - system (default) +# - primary +#copy_clipboard: primary + +# Enable or disable automatic copy (and clear) of selection when releasing mouse +#copy_on_select: true + +# Path to the default editor to use to edit pane scrollbuffer +# scrollback_editor: /usr/bin/nano diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_themes.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_themes.yaml new file mode 100644 index 00000000..d2839a64 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_themes.yaml @@ -0,0 +1,677 @@ +--- +# Configuration for zellij. + +# In order to troubleshoot your configuration try using the following command: +# `zellij setup --check` +# It should show current config locations and features that are enabled. + +keybinds: + unbind: true + normal: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [NewPane: ] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right ] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up, ] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + locked: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'g',] + resize: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'n', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [Resize: Left,] + key: [Char: 'h', Left,] + - action: [Resize: Down,] + key: [Char: 'j', Down,] + - action: [Resize: Up,] + key: [Char: 'k', Up, ] + - action: [Resize: Right,] + key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Char: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + pane: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'p', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [MoveFocus: Left,] + key: [ Char: 'h', Left,] + - action: [MoveFocus: Right,] + key: [ Char: 'l', Right,] + - action: [MoveFocus: Down,] + key: [ Char: 'j', Down,] + - action: [MoveFocus: Up,] + key: [ Char: 'k', Up,] + - action: [SwitchFocus,] + key: [Char: 'p'] + - action: [NewPane: , SwitchToMode: Normal,] + key: [Char: 'n',] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: 'd',] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: 'r',] + - action: [CloseFocus, SwitchToMode: Normal,] + key: [Char: 'x',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'f',] + - action: [TogglePaneFrames, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [ToggleFloatingPanes, SwitchToMode: Normal,] + key: [Char: 'w'] + - action: [TogglePaneEmbedOrFloating, SwitchToMode: Normal,] + key: [Char: 'e'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: RenamePane, PaneNameInput: [0],] + key: [Char: 'c'] + move: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'h', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] + - action: [MovePane: Left,] + key: [Char: 'h', Left,] + - action: [MovePane: Down,] + key: [Char: 'j', Down,] + - action: [MovePane: Up,] + key: [Char: 'k', Up, ] + - action: [MovePane: Right,] + key: [Char: 'l', Right,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tab: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 't', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: 'r'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [GoToPreviousTab,] + key: [ Char: 'h', Left, Up, Char: 'k',] + - action: [GoToNextTab,] + key: [ Char: 'l', Right,Down, Char: 'j'] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'n',] + - action: [CloseTab, SwitchToMode: Normal,] + key: [ Char: 'x',] + - action: [ToggleActiveSyncTab, SwitchToMode: Normal,] + key: [Char: 's'] + - action: [GoToTab: 1, SwitchToMode: Normal,] + key: [ Char: '1',] + - action: [GoToTab: 2, SwitchToMode: Normal,] + key: [ Char: '2',] + - action: [GoToTab: 3, SwitchToMode: Normal,] + key: [ Char: '3',] + - action: [GoToTab: 4, SwitchToMode: Normal,] + key: [ Char: '4',] + - action: [GoToTab: 5, SwitchToMode: Normal,] + key: [ Char: '5',] + - action: [GoToTab: 6, SwitchToMode: Normal,] + key: [ Char: '6',] + - action: [GoToTab: 7, SwitchToMode: Normal,] + key: [ Char: '7',] + - action: [GoToTab: 8, SwitchToMode: Normal,] + key: [ Char: '8',] + - action: [GoToTab: 9, SwitchToMode: Normal,] + key: [ Char: '9',] + - action: [ToggleTab] + key: [ Char: "\t" ] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + scroll: + - action: [EditScrollback, SwitchToMode: Normal] + key: [Char: 'e'] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + entersearch: + - action: [SwitchToMode: Search,] + key: [Char: "\n"] + - action: [SearchInput: [27], SwitchToMode: Scroll,] + key: [Ctrl: 'c', Esc] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + search: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + - action: [Search: Down] + key: [Char: 'n'] + - action: [Search: Up] + key: [Char: 'p'] + - action: [SearchToggleOption: CaseSensitivity] + key: [Char: 'c'] + - action: [SearchToggleOption: Wrap] + key: [Char: 'w'] + - action: [SearchToggleOption: WholeWord] + key: [Char: 'o'] + renametab: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenameTab , SwitchToMode: Tab,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + renamepane: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenamePane , SwitchToMode: Pane,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + session: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Detach,] + key: [Char: 'd',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tmux: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Scroll,] + key: [ Char: '['] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Write: [2,], SwitchToMode: Normal] + key: [Ctrl: 'b'] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: "\"",] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: '%',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'c',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: ','] + - action: [GoToPreviousTab, SwitchToMode: Normal,] + key: [ Char: 'p'] + - action: [GoToNextTab, SwitchToMode: Normal,] + key: [ Char: 'n'] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Left,] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Right,] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Down,] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Up,] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Char: 'h'] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Char: 'l'] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Char: 'j'] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Char: 'k'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [FocusNextPane,] + key: [ Char: 'o'] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [Detach,] + key: [Char: 'd',] +plugins: + - path: tab-bar + tag: tab-bar + - path: status-bar + tag: status-bar + - path: strider + tag: strider + - path: compact-bar + tag: compact-bar + +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# eg. when terminal window with an active zellij session is closed +# Options: +# - detach (Default) +# - quit +# on_force_close: quit + +# Send a request for a simplified ui (without arrow fonts) to plugins +# Options: +# - true +# - false (Default) +# simplified_ui: true + +# Choose the path to the default shell that zellij will use for opening new panes +# Default: $SHELL +# default_shell: fish + +# Toggle between having pane frames around the panes +# Options: +# - true (default) +# - false +#pane_frames: true + +# Choose the theme that is specified in the themes section. +# For some examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +# Default: default +#theme: default + +# Choose the mode that zellij uses when starting up. +# Default: normal +#default_mode: locked + +# Toggle enabling the mouse mode. +# On certain configurations, or terminals this could +# potentially interfere with copying text. +# Options: +# - true (default) +# - false +#mouse_mode: false + +# Configure the scroll back buffer size +# This is the number of lines zellij stores for each pane in the scroll back +# buffer. Excess number of lines are discarded in a FIFO fashion. +# Valid values: positive integers +# Default value: 10000 +#scroll_buffer_size: 10000 + +# Provide a command to execute when copying text. The text will be piped to +# the stdin of the program to perform the copy. This can be used with +# terminal emulators which do not support the OSC 52 ANSI control sequence +# that will be used by default if this option is not set. +# Examples: +#copy_command: "xclip -selection clipboard" # x11 +#copy_command: "wl-copy" # wayland +#copy_command: "pbcopy" # osx + +# Choose the destination for copied text +# Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +# Does not apply when using copy_command. +# Options: +# - system (default) +# - primary +#copy_clipboard: primary + +# Enable or disable automatic copy (and clear) of selection when releasing mouse +#copy_on_select: true + +# Path to the default editor to use to edit pane scrollbuffer +# scrollback_editor: /usr/bin/nano +# +themes: + nord: + fg: "D8DEE9" + bg: "#2E3440" + black: "#3B4252" + red: "#BF616A" + green: "#A3BE8C" + yellow: "#EBCB8B" + blue: "#81A1C1" + magenta: "#B48EAD" + cyan: "#88C0D0" + white: "#E5E9F0" + orange: "#D08770" + molokai-dark: + bg: [27, 29, 30] + red: [255, 0, 0] + green: [0, 140, 0] + yellow: [255, 255, 0] + blue: [102, 217, 239] + magenta: [174, 129, 255] + orange: [253, 151, 31] + fg: [248, 248, 240] + cyan: [0, 255, 255] + black: [0, 0, 0] + white: [255, 255, 255] + some-eightbit-theme: + bg: 0 + red: 2 + green: 3 + yellow: 4 + blue: 5 + magenta: 6 + orange: 7 + fg: 8 + cyan: 9 + black: 10 + white: 255 diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_ui.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_ui.yaml new file mode 100644 index 00000000..edf4af81 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_ui.yaml @@ -0,0 +1,643 @@ +--- +# Configuration for zellij. + +# In order to troubleshoot your configuration try using the following command: +# `zellij setup --check` +# It should show current config locations and features that are enabled. + +keybinds: + unbind: true + normal: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [NewPane: ] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right ] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up, ] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + locked: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'g',] + resize: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'n', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [Resize: Left,] + key: [Char: 'h', Left,] + - action: [Resize: Down,] + key: [Char: 'j', Down,] + - action: [Resize: Up,] + key: [Char: 'k', Up, ] + - action: [Resize: Right,] + key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Char: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + pane: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'p', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [MoveFocus: Left,] + key: [ Char: 'h', Left,] + - action: [MoveFocus: Right,] + key: [ Char: 'l', Right,] + - action: [MoveFocus: Down,] + key: [ Char: 'j', Down,] + - action: [MoveFocus: Up,] + key: [ Char: 'k', Up,] + - action: [SwitchFocus,] + key: [Char: 'p'] + - action: [NewPane: , SwitchToMode: Normal,] + key: [Char: 'n',] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: 'd',] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: 'r',] + - action: [CloseFocus, SwitchToMode: Normal,] + key: [Char: 'x',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'f',] + - action: [TogglePaneFrames, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [ToggleFloatingPanes, SwitchToMode: Normal,] + key: [Char: 'w'] + - action: [TogglePaneEmbedOrFloating, SwitchToMode: Normal,] + key: [Char: 'e'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: RenamePane, PaneNameInput: [0],] + key: [Char: 'c'] + move: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'h', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] + - action: [MovePane: Left,] + key: [Char: 'h', Left,] + - action: [MovePane: Down,] + key: [Char: 'j', Down,] + - action: [MovePane: Up,] + key: [Char: 'k', Up, ] + - action: [MovePane: Right,] + key: [Char: 'l', Right,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tab: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 't', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: 'r'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [GoToPreviousTab,] + key: [ Char: 'h', Left, Up, Char: 'k',] + - action: [GoToNextTab,] + key: [ Char: 'l', Right,Down, Char: 'j'] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'n',] + - action: [CloseTab, SwitchToMode: Normal,] + key: [ Char: 'x',] + - action: [ToggleActiveSyncTab, SwitchToMode: Normal,] + key: [Char: 's'] + - action: [GoToTab: 1, SwitchToMode: Normal,] + key: [ Char: '1',] + - action: [GoToTab: 2, SwitchToMode: Normal,] + key: [ Char: '2',] + - action: [GoToTab: 3, SwitchToMode: Normal,] + key: [ Char: '3',] + - action: [GoToTab: 4, SwitchToMode: Normal,] + key: [ Char: '4',] + - action: [GoToTab: 5, SwitchToMode: Normal,] + key: [ Char: '5',] + - action: [GoToTab: 6, SwitchToMode: Normal,] + key: [ Char: '6',] + - action: [GoToTab: 7, SwitchToMode: Normal,] + key: [ Char: '7',] + - action: [GoToTab: 8, SwitchToMode: Normal,] + key: [ Char: '8',] + - action: [GoToTab: 9, SwitchToMode: Normal,] + key: [ Char: '9',] + - action: [ToggleTab] + key: [ Char: "\t" ] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + scroll: + - action: [EditScrollback, SwitchToMode: Normal] + key: [Char: 'e'] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + entersearch: + - action: [SwitchToMode: Search,] + key: [Char: "\n"] + - action: [SearchInput: [27], SwitchToMode: Scroll,] + key: [Ctrl: 'c', Esc] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + search: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + - action: [Search: Down] + key: [Char: 'n'] + - action: [Search: Up] + key: [Char: 'p'] + - action: [SearchToggleOption: CaseSensitivity] + key: [Char: 'c'] + - action: [SearchToggleOption: Wrap] + key: [Char: 'w'] + - action: [SearchToggleOption: WholeWord] + key: [Char: 'o'] + renametab: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenameTab , SwitchToMode: Tab,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + renamepane: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenamePane , SwitchToMode: Pane,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + session: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Detach,] + key: [Char: 'd',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tmux: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Scroll,] + key: [ Char: '['] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Write: [2,], SwitchToMode: Normal] + key: [Ctrl: 'b'] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: "\"",] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: '%',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'c',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: ','] + - action: [GoToPreviousTab, SwitchToMode: Normal,] + key: [ Char: 'p'] + - action: [GoToNextTab, SwitchToMode: Normal,] + key: [ Char: 'n'] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Left,] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Right,] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Down,] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Up,] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Char: 'h'] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Char: 'l'] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Char: 'j'] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Char: 'k'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [FocusNextPane,] + key: [ Char: 'o'] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [Detach,] + key: [Char: 'd',] +plugins: + - path: tab-bar + tag: tab-bar + - path: status-bar + tag: status-bar + - path: strider + tag: strider + - path: compact-bar + tag: compact-bar + +ui: + pane_frames: + rounded_corners: true +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# eg. when terminal window with an active zellij session is closed +# Options: +# - detach (Default) +# - quit +# on_force_close: quit + +# Send a request for a simplified ui (without arrow fonts) to plugins +# Options: +# - true +# - false (Default) +# simplified_ui: true + +# Choose the path to the default shell that zellij will use for opening new panes +# Default: $SHELL +# default_shell: fish + +# Toggle between having pane frames around the panes +# Options: +# - true (default) +# - false +#pane_frames: true + +# Choose the theme that is specified in the themes section. +# For some examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +# Default: default +#theme: default + +# Choose the mode that zellij uses when starting up. +# Default: normal +#default_mode: locked + +# Toggle enabling the mouse mode. +# On certain configurations, or terminals this could +# potentially interfere with copying text. +# Options: +# - true (default) +# - false +#mouse_mode: false + +# Configure the scroll back buffer size +# This is the number of lines zellij stores for each pane in the scroll back +# buffer. Excess number of lines are discarded in a FIFO fashion. +# Valid values: positive integers +# Default value: 10000 +#scroll_buffer_size: 10000 + +# Provide a command to execute when copying text. The text will be piped to +# the stdin of the program to perform the copy. This can be used with +# terminal emulators which do not support the OSC 52 ANSI control sequence +# that will be used by default if this option is not set. +# Examples: +#copy_command: "xclip -selection clipboard" # x11 +#copy_command: "wl-copy" # wayland +#copy_command: "pbcopy" # osx + +# Choose the destination for copied text +# Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +# Does not apply when using copy_command. +# Options: +# - system (default) +# - primary +#copy_clipboard: primary + +# Enable or disable automatic copy (and clear) of selection when releasing mouse +#copy_on_select: true + +# Path to the default editor to use to edit pane scrollbuffer +# scrollback_editor: /usr/bin/nano diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbind_all_keys_per_mode.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbind_all_keys_per_mode.yaml new file mode 100644 index 00000000..5cf962b8 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbind_all_keys_per_mode.yaml @@ -0,0 +1,639 @@ +--- +# Configuration for zellij. + +# In order to troubleshoot your configuration try using the following command: +# `zellij setup --check` +# It should show current config locations and features that are enabled. + +keybinds: + normal: + - unbind: true + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [NewPane: ] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right ] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up, ] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + locked: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'g',] + resize: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'n', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [Resize: Left,] + key: [Char: 'h', Left,] + - action: [Resize: Down,] + key: [Char: 'j', Down,] + - action: [Resize: Up,] + key: [Char: 'k', Up, ] + - action: [Resize: Right,] + key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Char: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + pane: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'p', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [MoveFocus: Left,] + key: [ Char: 'h', Left,] + - action: [MoveFocus: Right,] + key: [ Char: 'l', Right,] + - action: [MoveFocus: Down,] + key: [ Char: 'j', Down,] + - action: [MoveFocus: Up,] + key: [ Char: 'k', Up,] + - action: [SwitchFocus,] + key: [Char: 'p'] + - action: [NewPane: , SwitchToMode: Normal,] + key: [Char: 'n',] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: 'd',] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: 'r',] + - action: [CloseFocus, SwitchToMode: Normal,] + key: [Char: 'x',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'f',] + - action: [TogglePaneFrames, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [ToggleFloatingPanes, SwitchToMode: Normal,] + key: [Char: 'w'] + - action: [TogglePaneEmbedOrFloating, SwitchToMode: Normal,] + key: [Char: 'e'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: RenamePane, PaneNameInput: [0],] + key: [Char: 'c'] + move: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'h', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] + - action: [MovePane: Left,] + key: [Char: 'h', Left,] + - action: [MovePane: Down,] + key: [Char: 'j', Down,] + - action: [MovePane: Up,] + key: [Char: 'k', Up, ] + - action: [MovePane: Right,] + key: [Char: 'l', Right,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tab: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 't', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: 'r'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [GoToPreviousTab,] + key: [ Char: 'h', Left, Up, Char: 'k',] + - action: [GoToNextTab,] + key: [ Char: 'l', Right,Down, Char: 'j'] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'n',] + - action: [CloseTab, SwitchToMode: Normal,] + key: [ Char: 'x',] + - action: [ToggleActiveSyncTab, SwitchToMode: Normal,] + key: [Char: 's'] + - action: [GoToTab: 1, SwitchToMode: Normal,] + key: [ Char: '1',] + - action: [GoToTab: 2, SwitchToMode: Normal,] + key: [ Char: '2',] + - action: [GoToTab: 3, SwitchToMode: Normal,] + key: [ Char: '3',] + - action: [GoToTab: 4, SwitchToMode: Normal,] + key: [ Char: '4',] + - action: [GoToTab: 5, SwitchToMode: Normal,] + key: [ Char: '5',] + - action: [GoToTab: 6, SwitchToMode: Normal,] + key: [ Char: '6',] + - action: [GoToTab: 7, SwitchToMode: Normal,] + key: [ Char: '7',] + - action: [GoToTab: 8, SwitchToMode: Normal,] + key: [ Char: '8',] + - action: [GoToTab: 9, SwitchToMode: Normal,] + key: [ Char: '9',] + - action: [ToggleTab] + key: [ Char: "\t" ] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + scroll: + - action: [EditScrollback, SwitchToMode: Normal] + key: [Char: 'e'] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + entersearch: + - action: [SwitchToMode: Search,] + key: [Char: "\n"] + - action: [SearchInput: [27], SwitchToMode: Scroll,] + key: [Ctrl: 'c', Esc] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + search: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + - action: [Search: Down] + key: [Char: 'n'] + - action: [Search: Up] + key: [Char: 'p'] + - action: [SearchToggleOption: CaseSensitivity] + key: [Char: 'c'] + - action: [SearchToggleOption: Wrap] + key: [Char: 'w'] + - action: [SearchToggleOption: WholeWord] + key: [Char: 'o'] + renametab: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenameTab , SwitchToMode: Tab,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + renamepane: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenamePane , SwitchToMode: Pane,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + session: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Detach,] + key: [Char: 'd',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tmux: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Scroll,] + key: [ Char: '['] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Write: [2,], SwitchToMode: Normal] + key: [Ctrl: 'b'] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: "\"",] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: '%',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'c',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: ','] + - action: [GoToPreviousTab, SwitchToMode: Normal,] + key: [ Char: 'p'] + - action: [GoToNextTab, SwitchToMode: Normal,] + key: [ Char: 'n'] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Left,] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Right,] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Down,] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Up,] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Char: 'h'] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Char: 'l'] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Char: 'j'] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Char: 'k'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [FocusNextPane,] + key: [ Char: 'o'] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [Detach,] + key: [Char: 'd',] +plugins: + - path: tab-bar + tag: tab-bar + - path: status-bar + tag: status-bar + - path: strider + tag: strider + - path: compact-bar + tag: compact-bar + +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# eg. when terminal window with an active zellij session is closed +# Options: +# - detach (Default) +# - quit +# on_force_close: quit + +# Send a request for a simplified ui (without arrow fonts) to plugins +# Options: +# - true +# - false (Default) +# simplified_ui: true + +# Choose the path to the default shell that zellij will use for opening new panes +# Default: $SHELL +# default_shell: fish + +# Toggle between having pane frames around the panes +# Options: +# - true (default) +# - false +#pane_frames: true + +# Choose the theme that is specified in the themes section. +# For some examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +# Default: default +#theme: default + +# Choose the mode that zellij uses when starting up. +# Default: normal +#default_mode: locked + +# Toggle enabling the mouse mode. +# On certain configurations, or terminals this could +# potentially interfere with copying text. +# Options: +# - true (default) +# - false +#mouse_mode: false + +# Configure the scroll back buffer size +# This is the number of lines zellij stores for each pane in the scroll back +# buffer. Excess number of lines are discarded in a FIFO fashion. +# Valid values: positive integers +# Default value: 10000 +#scroll_buffer_size: 10000 + +# Provide a command to execute when copying text. The text will be piped to +# the stdin of the program to perform the copy. This can be used with +# terminal emulators which do not support the OSC 52 ANSI control sequence +# that will be used by default if this option is not set. +# Examples: +#copy_command: "xclip -selection clipboard" # x11 +#copy_command: "wl-copy" # wayland +#copy_command: "pbcopy" # osx + +# Choose the destination for copied text +# Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +# Does not apply when using copy_command. +# Options: +# - system (default) +# - primary +#copy_clipboard: primary + +# Enable or disable automatic copy (and clear) of selection when releasing mouse +#copy_on_select: true + +# Path to the default editor to use to edit pane scrollbuffer +# scrollback_editor: /usr/bin/nano diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbinds_in_mode.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbinds_in_mode.yaml new file mode 100644 index 00000000..fff9a528 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_config_with_unbinds_in_mode.yaml @@ -0,0 +1,640 @@ +--- +# Configuration for zellij. + +# In order to troubleshoot your configuration try using the following command: +# `zellij setup --check` +# It should show current config locations and features that are enabled. + +keybinds: + unbind: true + normal: + - unbind: [Ctrl: 'a', Char: "\n"] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [NewPane: ] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right ] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up, ] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + locked: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'g',] + resize: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'n', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [Resize: Left,] + key: [Char: 'h', Left,] + - action: [Resize: Down,] + key: [Char: 'j', Down,] + - action: [Resize: Up,] + key: [Char: 'k', Up, ] + - action: [Resize: Right,] + key: [Char: 'l', Right,] + - action: [Resize: Increase,] + key: [Char: '='] + - action: [Resize: Increase,] + key: [ Char: '+'] + - action: [Resize: Decrease,] + key: [Char: '-'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + pane: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'p', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [MoveFocus: Left,] + key: [ Char: 'h', Left,] + - action: [MoveFocus: Right,] + key: [ Char: 'l', Right,] + - action: [MoveFocus: Down,] + key: [ Char: 'j', Down,] + - action: [MoveFocus: Up,] + key: [ Char: 'k', Up,] + - action: [SwitchFocus,] + key: [Char: 'p'] + - action: [NewPane: , SwitchToMode: Normal,] + key: [Char: 'n',] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: 'd',] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: 'r',] + - action: [CloseFocus, SwitchToMode: Normal,] + key: [Char: 'x',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'f',] + - action: [TogglePaneFrames, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [ToggleFloatingPanes, SwitchToMode: Normal,] + key: [Char: 'w'] + - action: [TogglePaneEmbedOrFloating, SwitchToMode: Normal,] + key: [Char: 'e'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: RenamePane, PaneNameInput: [0],] + key: [Char: 'c'] + move: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'h', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [Quit] + key: [Ctrl: 'q'] + - action: [MovePane: ,] + key: [Char: 'n', Char: "\t",] + - action: [MovePane: Left,] + key: [Char: 'h', Left,] + - action: [MovePane: Down,] + key: [Char: 'j', Down,] + - action: [MovePane: Up,] + key: [Char: 'k', Up, ] + - action: [MovePane: Right,] + key: [Char: 'l', Right,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tab: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 't', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: 'r'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [GoToPreviousTab,] + key: [ Char: 'h', Left, Up, Char: 'k',] + - action: [GoToNextTab,] + key: [ Char: 'l', Right,Down, Char: 'j'] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'n',] + - action: [CloseTab, SwitchToMode: Normal,] + key: [ Char: 'x',] + - action: [ToggleActiveSyncTab, SwitchToMode: Normal,] + key: [Char: 's'] + - action: [GoToTab: 1, SwitchToMode: Normal,] + key: [ Char: '1',] + - action: [GoToTab: 2, SwitchToMode: Normal,] + key: [ Char: '2',] + - action: [GoToTab: 3, SwitchToMode: Normal,] + key: [ Char: '3',] + - action: [GoToTab: 4, SwitchToMode: Normal,] + key: [ Char: '4',] + - action: [GoToTab: 5, SwitchToMode: Normal,] + key: [ Char: '5',] + - action: [GoToTab: 6, SwitchToMode: Normal,] + key: [ Char: '6',] + - action: [GoToTab: 7, SwitchToMode: Normal,] + key: [ Char: '7',] + - action: [GoToTab: 8, SwitchToMode: Normal,] + key: [ Char: '8',] + - action: [GoToTab: 9, SwitchToMode: Normal,] + key: [ Char: '9',] + - action: [ToggleTab] + key: [ Char: "\t" ] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + scroll: + - action: [EditScrollback, SwitchToMode: Normal] + key: [Char: 'e'] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + # uncomment this and adjust key if using copy_on_select=false + # - action: [Copy: ] + # key: [ Alt: 'c'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + entersearch: + - action: [SwitchToMode: Search,] + key: [Char: "\n"] + - action: [SearchInput: [27], SwitchToMode: Scroll,] + key: [Ctrl: 'c', Esc] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + search: + - action: [SwitchToMode: Normal,] + key: [Ctrl: 's', Char: ' ', Char: "\n", Esc] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Session,] + key: [Ctrl: 'o',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [ScrollToBottom, SwitchToMode: Normal,] + key: [Ctrl: 'c',] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [ScrollDown,] + key: [Char: 'j', Down,] + - action: [ScrollUp,] + key: [Char: 'k', Up,] + - action: [PageScrollDown,] + key: [Ctrl: 'f', PageDown, Right, Char: 'l',] + - action: [PageScrollUp,] + key: [Ctrl: 'b', PageUp, Left, Char: 'h',] + - action: [HalfPageScrollDown,] + key: [Char: 'd',] + - action: [HalfPageScrollUp,] + key: [Char: 'u',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them! + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [SwitchToMode: EnterSearch, SearchInput: [0],] + key: [Char: 's'] + - action: [Search: Down] + key: [Char: 'n'] + - action: [Search: Up] + key: [Char: 'p'] + - action: [SearchToggleOption: CaseSensitivity] + key: [Char: 'c'] + - action: [SearchToggleOption: Wrap] + key: [Char: 'w'] + - action: [SearchToggleOption: WholeWord] + key: [Char: 'o'] + renametab: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenameTab , SwitchToMode: Tab,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + renamepane: + - action: [SwitchToMode: Normal,] + key: [Char: "\n", Ctrl: 'c', Esc] + - action: [UndoRenamePane , SwitchToMode: Pane,] + key: [Esc,] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + session: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tmux,] + key: [Ctrl: 'b',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Detach,] + key: [Char: 'd',] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + tmux: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g'] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Move,] + key: [Ctrl: 'h',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] + - action: [SwitchToMode: Normal,] + key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc] + - action: [SwitchToMode: Scroll,] + key: [Ctrl: 's'] + - action: [SwitchToMode: Scroll,] + key: [ Char: '['] + - action: [Quit,] + key: [Ctrl: 'q',] + - action: [Write: [2,], SwitchToMode: Normal] + key: [Ctrl: 'b'] + - action: [NewPane: Down, SwitchToMode: Normal,] + key: [Char: "\"",] + - action: [NewPane: Right, SwitchToMode: Normal,] + key: [Char: '%',] + - action: [ToggleFocusFullscreen, SwitchToMode: Normal,] + key: [Char: 'z',] + - action: [NewTab: , SwitchToMode: Normal,] + key: [ Char: 'c',] + - action: [SwitchToMode: RenameTab, TabNameInput: [0],] + key: [Char: ','] + - action: [GoToPreviousTab, SwitchToMode: Normal,] + key: [ Char: 'p'] + - action: [GoToNextTab, SwitchToMode: Normal,] + key: [ Char: 'n'] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Left,] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Right,] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Down,] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Up,] + - action: [MoveFocus: Left, SwitchToMode: Normal,] + key: [ Char: 'h'] + - action: [MoveFocus: Right, SwitchToMode: Normal,] + key: [ Char: 'l'] + - action: [MoveFocus: Down, SwitchToMode: Normal,] + key: [ Char: 'j'] + - action: [MoveFocus: Up, SwitchToMode: Normal,] + key: [ Char: 'k'] + - action: [NewPane: ,] + key: [ Alt: 'n',] + - action: [MoveFocusOrTab: Left,] + key: [ Alt: 'h', Alt: Left] + - action: [MoveFocusOrTab: Right,] + key: [ Alt: 'l', Alt: Right] + - action: [MoveFocus: Down,] + key: [ Alt: 'j', Alt: Down] + - action: [MoveFocus: Up,] + key: [ Alt: 'k', Alt: Up] + - action: [FocusNextPane,] + key: [ Char: 'o'] + - action: [Resize: Increase,] + key: [ Alt: '='] + - action: [Resize: Increase,] + key: [ Alt: '+'] + - action: [Resize: Decrease,] + key: [ Alt: '-'] + - action: [Detach,] + key: [Char: 'd',] +plugins: + - path: tab-bar + tag: tab-bar + - path: status-bar + tag: status-bar + - path: strider + tag: strider + - path: compact-bar + tag: compact-bar + +# Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +# eg. when terminal window with an active zellij session is closed +# Options: +# - detach (Default) +# - quit +# on_force_close: quit + +# Send a request for a simplified ui (without arrow fonts) to plugins +# Options: +# - true +# - false (Default) +# simplified_ui: true + +# Choose the path to the default shell that zellij will use for opening new panes +# Default: $SHELL +# default_shell: fish + +# Toggle between having pane frames around the panes +# Options: +# - true (default) +# - false +#pane_frames: true + +# Choose the theme that is specified in the themes section. +# For some examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +# Default: default +#theme: default + +# Choose the mode that zellij uses when starting up. +# Default: normal +#default_mode: locked + +# Toggle enabling the mouse mode. +# On certain configurations, or terminals this could +# potentially interfere with copying text. +# Options: +# - true (default) +# - false +#mouse_mode: false + +# Configure the scroll back buffer size +# This is the number of lines zellij stores for each pane in the scroll back +# buffer. Excess number of lines are discarded in a FIFO fashion. +# Valid values: positive integers +# Default value: 10000 +#scroll_buffer_size: 10000 + +# Provide a command to execute when copying text. The text will be piped to +# the stdin of the program to perform the copy. This can be used with +# terminal emulators which do not support the OSC 52 ANSI control sequence +# that will be used by default if this option is not set. +# Examples: +#copy_command: "xclip -selection clipboard" # x11 +#copy_command: "wl-copy" # wayland +#copy_command: "pbcopy" # osx + +# Choose the destination for copied text +# Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +# Does not apply when using copy_command. +# Options: +# - system (default) +# - primary +#copy_clipboard: primary + +# Enable or disable automatic copy (and clear) of selection when releasing mouse +#copy_on_select: true + +# Path to the default editor to use to edit pane scrollbuffer +# scrollback_editor: /usr/bin/nano diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config.yaml new file mode 100644 index 00000000..0d5f40b9 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config.yaml @@ -0,0 +1,34 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + borderless: true + split_size: + Fixed: 1 + run: + plugin: + location: "zellij:tab-bar" + - direction: Vertical + body: true + - direction: Vertical + borderless: true + split_size: + Fixed: 2 + run: + plugin: + location: "zellij:status-bar" +tabs: + - direction: Vertical +default_shell: fish +keybinds: + unbind: true + normal: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] diff --git a/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config_and_session_name.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config_and_session_name.yaml new file mode 100644 index 00000000..7e6fa2cb --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_config_and_session_name.yaml @@ -0,0 +1,36 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + borderless: true + split_size: + Fixed: 1 + run: + plugin: + location: "zellij:tab-bar" + - direction: Vertical + body: true + - direction: Vertical + borderless: true + split_size: + Fixed: 2 + run: + plugin: + location: "zellij:status-bar" +tabs: + - direction: Vertical +session: + name: foo +default_shell: fish +keybinds: + unbind: true + normal: + - action: [SwitchToMode: Locked,] + key: [Ctrl: 'g',] + - action: [SwitchToMode: Pane,] + key: [Ctrl: 'p',] + - action: [SwitchToMode: Resize,] + key: [Ctrl: 'n',] + - action: [SwitchToMode: Tab,] + key: [Ctrl: 't',] diff --git a/zellij-utils/assets/layouts/strider.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name.yaml similarity index 69% rename from zellij-utils/assets/layouts/strider.yaml rename to zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name.yaml index 26e1eba4..9e452574 100644 --- a/zellij-utils/assets/layouts/strider.yaml +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name.yaml @@ -20,11 +20,5 @@ template: location: "zellij:status-bar" tabs: - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 20 - run: - plugin: - location: "zellij:strider" - - direction: Horizontal +session: + name: foo diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-default-plugins.yaml b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name_and_attach_false.yaml similarity index 52% rename from zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-default-plugins.yaml rename to zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name_and_attach_false.yaml index 8148fd20..1f33f1c3 100644 --- a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-default-plugins.yaml +++ b/zellij-client/src/old_config_converter/unit/fixtures/old_yaml_layout_with_session_name_and_attach_false.yaml @@ -3,14 +3,16 @@ template: direction: Horizontal parts: - direction: Vertical + borderless: true split_size: Fixed: 1 run: plugin: location: "zellij:tab-bar" - - direction: Horizontal + - direction: Vertical body: true - direction: Vertical + borderless: true split_size: Fixed: 2 run: @@ -18,15 +20,6 @@ template: location: "zellij:status-bar" tabs: - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 50 - - direction: Horizontal - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 +session: + name: foo + attach: false diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab.yaml b/zellij-client/src/old_config_converter/unit/fixtures/run_htop_layout.yaml similarity index 70% rename from zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab.yaml rename to zellij-client/src/old_config_converter/unit/fixtures/run_htop_layout.yaml index 83f05076..91f4f63c 100644 --- a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab.yaml +++ b/zellij-client/src/old_config_converter/unit/fixtures/run_htop_layout.yaml @@ -1,17 +1,10 @@ --- -template: - direction: Horizontal - parts: - - direction: Horizontal - body: true - tabs: - direction: Vertical parts: - direction: Horizontal split_size: Percent: 50 - - direction: Horizontal parts: - direction: Vertical split_size: @@ -19,3 +12,10 @@ tabs: - direction: Vertical split_size: Percent: 50 + run: + command: {cmd: htop} + - direction: Horizontal + split_size: + Percent: 50 + run: + command: {cmd: htop} diff --git a/zellij-client/src/old_config_converter/unit/fixtures/run_htop_layout_with_plugins.yaml b/zellij-client/src/old_config_converter/unit/fixtures/run_htop_layout_with_plugins.yaml new file mode 100644 index 00000000..05d2798f --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/fixtures/run_htop_layout_with_plugins.yaml @@ -0,0 +1,35 @@ +--- +tabs: + - direction: Horizontal + parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: + location: "zellij:tab-bar" + borderless: true + - direction: Vertical + parts: + - direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop} + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop, args: ["-C", "--tree"]} + - direction: Vertical + split_size: + Fixed: 5 + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: + location: "zellij:status-bar" + borderless: true diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_custom_options.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_custom_options.snap new file mode 100644 index 00000000..34539e60 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_custom_options.snap @@ -0,0 +1,411 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 24 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx +copy_command "pbcopy" + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +copy_on_select true + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +scrollback_editor "/usr/bin/nano" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_env_variables.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_env_variables.snap new file mode 100644 index 00000000..c28f4afa --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_env_variables.snap @@ -0,0 +1,415 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 68 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" +env { + RUST_BACKTRACE "1" + bar "baz" + foo "bar" +} + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_global_keybind_unbinds.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_global_keybind_unbinds.snap new file mode 100644 index 00000000..5ce03e24 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_global_keybind_unbinds.snap @@ -0,0 +1,411 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 46 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds { + unbind "Ctrl g" "Space" + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_keybind_unbinds_in_mode.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_keybind_unbinds_in_mode.snap new file mode 100644 index 00000000..d7ac6474 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_keybind_unbinds_in_mode.snap @@ -0,0 +1,411 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 35 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds clear-defaults=true { + normal { + unbind "Ctrl a" "Enter" + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_themes_config.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_themes_config.snap new file mode 100644 index 00000000..f8a65133 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_themes_config.snap @@ -0,0 +1,451 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 90 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} +themes { + molokai-dark { + fg 248 248 240 + bg 27 29 30 + black 0 0 0 + red 255 0 0 + green 0 140 0 + yellow 255 255 0 + blue 102 217 239 + magenta 174 129 255 + cyan 0 255 255 + white 255 255 255 + orange 253 151 31 + } + nord { + fg 216 222 233 + bg 46 52 64 + black 59 66 82 + red 191 97 106 + green 163 190 140 + yellow 235 203 139 + blue 129 161 193 + magenta 180 142 173 + cyan 136 192 208 + white 229 233 240 + orange 208 135 112 + } + some-eightbit-theme { + fg 8 + bg 0 + black 10 + red 2 + green 3 + yellow 4 + blue 5 + magenta 6 + cyan 9 + white 255 + orange 7 + } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_ui_config.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_ui_config.snap new file mode 100644 index 00000000..e805563a --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_ui_config.snap @@ -0,0 +1,416 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 79 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + +ui { + pane_frames { + rounded_corners true + } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_unbind_all_keys_per_mode.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_unbind_all_keys_per_mode.snap new file mode 100644 index 00000000..2b35143e --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__convert_config_with_unbind_all_keys_per_mode.snap @@ -0,0 +1,410 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 57 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds { + normal clear-defaults=true { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__properly_convert_default_config.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__properly_convert_default_config.snap new file mode 100644 index 00000000..461258e4 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_config__convert_config_test__properly_convert_default_config.snap @@ -0,0 +1,410 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_config_tests.rs +assertion_line: 13 +expression: "format!(\"{}\", kdl_config)" +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl p" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "d" { NewPane "Down"; SwitchToMode "normal"; } + bind "r" { NewPane "Right"; SwitchToMode "normal"; } + bind "x" { CloseFocus; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0; } + } + tab { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "Ctrl q" { Quit; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "Tab" { ToggleTab; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + resize { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl q" { Quit; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" { Resize "Increase"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + move { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl h" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl q" { Quit; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + session { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "d" { Detach; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + search { + bind "Ctrl s" "Space" "Enter" "Esc" { SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl b" { SwitchToMode "tmux"; } + bind "Ctrl o" { SwitchToMode "session"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "Ctrl q" { Quit; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + bind "n" { Search "Down"; } + bind "p" { Search "Up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Enter" { SwitchToMode "search"; } + bind "Ctrl c" "Esc" { SearchInput 27; SwitchToMode "scroll"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenameTab { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "tab"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + RenamePane { + bind "Enter" "Ctrl c" "Esc" { SwitchToMode "normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "pane"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + tmux { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl h" { SwitchToMode "move"; } + bind "Ctrl t" { SwitchToMode "tab"; } + bind "Ctrl o" "Enter" "Space" "Esc" { SwitchToMode "normal"; } + bind "Ctrl s" { SwitchToMode "scroll"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl q" { Quit; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "normal"; } + bind "%" { NewPane "Right"; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "," { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "normal"; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "o" { FocusNextPane; } + bind "Alt =" { Resize "Increase"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "d" { Detach; } + } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir /path/to/my/layout_dir + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_default_layout.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_default_layout.snap new file mode 100644 index 00000000..94a9a4f3 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_default_layout.snap @@ -0,0 +1,14 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 13 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } +} diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_1.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_1.snap new file mode 100644 index 00000000..67cb8a60 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_1.snap @@ -0,0 +1,61 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 68 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + default_tab_template { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + children + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="50%" + pane size="50%" + } + } + tab + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="50%" + pane size="50%" + } + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="50%" + pane size="50%" split_direction="Horizontal" { + pane size="50%" + pane size="50%" + } + } + } + tab + tab + tab + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="20%" { + plugin location="zellij:strider" + } + pane size="80%" split_direction="Horizontal" { + pane size="50%" + pane size="50%" + } + } + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="40%" + pane size="60%" split_direction="Horizontal" { + pane size="50%" + pane size="50%" + } + } + } +} diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_2.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_2.snap new file mode 100644 index 00000000..0c5145a1 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_2.snap @@ -0,0 +1,60 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 79 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + default_tab_template { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + children + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane command="htop" size="50%" + pane size="50%" + } + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="50%" + pane size="50%" + } + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="50%" + pane size="50%" split_direction="Horizontal" { + pane size="50%" + pane size="50%" + } + } + } + tab + tab + tab + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="20%" { + plugin location="zellij:strider" + } + pane size="80%" split_direction="Horizontal" { + pane size="50%" + pane size="50%" + } + } + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="40%" + pane size="60%" split_direction="Horizontal" { + pane size="50%" + pane size="50%" + } + } + } +} diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_3.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_3.snap new file mode 100644 index 00000000..733e2aff --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_3.snap @@ -0,0 +1,19 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 90 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + default_tab_template { + children + } + tab split_direction="Vertical" { + pane split_direction="Vertical" { + pane size="50%" split_direction="Horizontal" { + pane size="50%" + pane command="htop" size="50%" + } + pane command="htop" size="50%" + } + } +} diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_4.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_4.snap new file mode 100644 index 00000000..ed6d2d6d --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_example_4.snap @@ -0,0 +1,27 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 101 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + default_tab_template { + children + } + tab split_direction="Horizontal" { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane split_direction="Vertical" { + pane split_direction="Vertical" { + pane command="htop" size="50%" + pane command="htop" size="50%" { + args "-C" "--tree" + } + } + } + pane size=5 + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } + } +} diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_config.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_config.snap new file mode 100644 index 00000000..a063d917 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_config.snap @@ -0,0 +1,24 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 46 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } +} +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + } +} +default_shell "fish" + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_config_and_session_name.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_config_and_session_name.snap new file mode 100644 index 00000000..a77bc525 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_config_and_session_name.snap @@ -0,0 +1,26 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 57 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } +} +session_name "foo" +attach_to_session true +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Ctrl p" { SwitchToMode "pane"; } + bind "Ctrl n" { SwitchToMode "resize"; } + bind "Ctrl t" { SwitchToMode "tab"; } + } +} +default_shell "fish" + diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_session_name.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_session_name.snap new file mode 100644 index 00000000..7b607256 --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_session_name.snap @@ -0,0 +1,16 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 24 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } +} +session_name "foo" +attach_to_session true diff --git a/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_session_name_and_attach_false.snap b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_session_name_and_attach_false.snap new file mode 100644 index 00000000..4a09faea --- /dev/null +++ b/zellij-client/src/old_config_converter/unit/snapshots/zellij_client__old_config_converter__old_layout__convert_layout_test__properly_convert_layout_with_session_name_and_attach_false.snap @@ -0,0 +1,16 @@ +--- +source: zellij-client/src/old_config_converter/./unit/convert_layout_tests.rs +assertion_line: 35 +expression: "format!(\"{}\", kdl_config)" +--- +layout { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } +} +session_name "foo" +attach_to_session false diff --git a/zellij-client/src/sessions.rs b/zellij-client/src/sessions.rs deleted file mode 100644 index 6a3c0799..00000000 --- a/zellij-client/src/sessions.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::process; - -use zellij_utils::consts::ZELLIJ_SOCK_DIR; -use zellij_utils::interprocess::local_socket::LocalSocketStream; -use zellij_utils::ipc::{ClientToServerMsg, IpcSenderWithContext}; - -pub(crate) fn kill_session(name: &str) { - let path = &*ZELLIJ_SOCK_DIR.join(name); - match LocalSocketStream::connect(path) { - Ok(stream) => { - let _ = IpcSenderWithContext::new(stream).send(ClientToServerMsg::KillSession); - }, - Err(e) => { - eprintln!("Error occurred: {:?}", e); - process::exit(1); - }, - }; -} diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index b3f17ad3..1f642534 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -44,7 +44,7 @@ use zellij_utils::{ input::{ command::{RunCommand, TerminalAction}, get_mode_info, - layout::LayoutFromYaml, + layout::Layout, options::Options, plugins::PluginsConfig, }, @@ -61,7 +61,7 @@ pub enum ServerInstruction { ClientAttributes, Box, Box, - Box, + Box, ClientId, Option, ), @@ -118,10 +118,18 @@ impl Drop for SessionMetaData { let _ = self.senders.send_to_screen(ScreenInstruction::Exit); let _ = self.senders.send_to_plugin(PluginInstruction::Exit); let _ = self.senders.send_to_pty_writer(PtyWriteInstruction::Exit); - let _ = self.screen_thread.take().unwrap().join(); - let _ = self.pty_thread.take().unwrap().join(); - let _ = self.wasm_thread.take().unwrap().join(); - let _ = self.pty_writer_thread.take().unwrap().join(); + if let Some(screen_thread) = self.screen_thread.take() { + let _ = screen_thread.join(); + } + if let Some(pty_thread) = self.pty_thread.take() { + let _ = pty_thread.join(); + } + if let Some(wasm_thread) = self.wasm_thread.take() { + let _ = wasm_thread.join(); + } + if let Some(pty_writer_thread) = self.pty_writer_thread.take() { + let _ = pty_writer_thread.join(); + } } } @@ -316,7 +324,7 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { }) }); - let spawn_tabs = |tab_layout| { + let spawn_tabs = |tab_layout, tab_name| { session_data .read() .unwrap() @@ -326,33 +334,32 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { .send_to_pty(PtyInstruction::NewTab( default_shell.clone(), tab_layout, + tab_name, client_id, )) .unwrap() }; - if !&layout.tabs.is_empty() { - for tab_layout in layout.clone().tabs { - spawn_tabs(Some(tab_layout.clone())); + if layout.has_tabs() { + for (tab_name, tab_layout) in layout.tabs() { + spawn_tabs(Some(tab_layout.clone()), tab_name); } - let focused_tab = layout - .tabs - .into_iter() - .enumerate() - .find(|(_, tab_layout)| tab_layout.focus.unwrap_or(false)); - if let Some((tab_index, _)) = focused_tab { + if let Some(focused_tab_index) = layout.focused_tab_index() { session_data .read() .unwrap() .as_ref() .unwrap() .senders - .send_to_pty(PtyInstruction::GoToTab((tab_index + 1) as u32, client_id)) + .send_to_pty(PtyInstruction::GoToTab( + (focused_tab_index + 1) as u32, + client_id, + )) .unwrap(); } } else { - spawn_tabs(None); + spawn_tabs(None, None); } session_data .read() @@ -594,7 +601,7 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { pub struct SessionOptions { pub opts: Box, pub config_options: Box, - pub layout: Box, + pub layout: Box, pub plugins: Option, } diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index d8b6c605..8b1beeac 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -427,6 +427,7 @@ impl Pane for TerminalPane { self.pane_name.push_str(c); }, } + self.set_should_render(true); } fn pid(&self) -> PaneId { PaneId::Terminal(self.pid) diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index 03fa0c06..81911e12 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -14,7 +14,7 @@ use std::rc::Rc; use std::time::Instant; use zellij_utils::{ data::{ModeInfo, Style}, - input::layout::Direction, + input::layout::SplitDirection, pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport}, }; @@ -211,7 +211,7 @@ impl TiledPanes { pub fn pane_ids(&self) -> impl Iterator { self.panes.keys() } - pub fn relayout(&mut self, direction: Direction) { + pub fn relayout(&mut self, direction: SplitDirection) { let mut pane_grid = TiledPaneGrid::new( &mut self.panes, &self.panes_to_hide, @@ -219,10 +219,12 @@ impl TiledPanes { *self.viewport.borrow(), ); let result = match direction { - Direction::Horizontal => { + SplitDirection::Horizontal => { pane_grid.layout(direction, (*self.display_area.borrow()).cols) }, - Direction::Vertical => pane_grid.layout(direction, (*self.display_area.borrow()).rows), + SplitDirection::Vertical => { + pane_grid.layout(direction, (*self.display_area.borrow()).rows) + }, }; if let Err(e) = &result { log::error!("{:?} relayout of the tab failed: {}", direction, e); @@ -269,7 +271,7 @@ impl TiledPanes { if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2 { return false; } else { - return split(Direction::Horizontal, &full_pane_size).is_some(); + return split(SplitDirection::Horizontal, &full_pane_size).is_some(); } } } @@ -282,7 +284,7 @@ impl TiledPanes { if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2 { return false; } - return split(Direction::Vertical, &full_pane_size).is_some(); + return split(SplitDirection::Vertical, &full_pane_size).is_some(); } } false @@ -296,11 +298,13 @@ impl TiledPanes { let active_pane_id = &self.active_panes.get(&client_id).unwrap(); let active_pane = self.panes.get_mut(active_pane_id).unwrap(); let full_pane_size = active_pane.position_and_size(); - if let Some((top_winsize, bottom_winsize)) = split(Direction::Horizontal, &full_pane_size) { + if let Some((top_winsize, bottom_winsize)) = + split(SplitDirection::Horizontal, &full_pane_size) + { active_pane.set_geom(top_winsize); new_pane.set_geom(bottom_winsize); self.panes.insert(pid, new_pane); - self.relayout(Direction::Vertical); + self.relayout(SplitDirection::Vertical); } } pub fn split_pane_vertically( @@ -312,11 +316,13 @@ impl TiledPanes { let active_pane_id = &self.active_panes.get(&client_id).unwrap(); let active_pane = self.panes.get_mut(active_pane_id).unwrap(); let full_pane_size = active_pane.position_and_size(); - if let Some((left_winsize, right_winsize)) = split(Direction::Vertical, &full_pane_size) { + if let Some((left_winsize, right_winsize)) = + split(SplitDirection::Vertical, &full_pane_size) + { active_pane.set_geom(left_winsize); new_pane.set_geom(right_winsize); self.panes.insert(pid, new_pane); - self.relayout(Direction::Horizontal); + self.relayout(SplitDirection::Horizontal); } } pub fn focus_pane(&mut self, pane_id: PaneId, client_id: ClientId) { @@ -455,15 +461,18 @@ impl TiledPanes { *display_area, *viewport, ); - if pane_grid.layout(Direction::Horizontal, cols).is_ok() { - let column_difference = cols as isize - display_area.cols as isize; - // FIXME: Should the viewport be an Offset? - viewport.cols = (viewport.cols as isize + column_difference) as usize; - display_area.cols = cols; - } else { - log::error!("Failed to horizontally resize the tab!!!"); - } - if pane_grid.layout(Direction::Vertical, rows).is_ok() { + match pane_grid.layout(SplitDirection::Horizontal, cols) { + Ok(_) => { + let column_difference = cols as isize - display_area.cols as isize; + // FIXME: Should the viewport be an Offset? + viewport.cols = (viewport.cols as isize + column_difference) as usize; + display_area.cols = cols; + }, + Err(e) => { + log::error!("Failed to horizontally resize the tab: {:?}", e); + }, + }; + if pane_grid.layout(SplitDirection::Vertical, rows).is_ok() { let row_difference = rows as isize - display_area.rows as isize; viewport.rows = (viewport.rows as isize + row_difference) as usize; display_area.rows = rows; diff --git a/zellij-server/src/panes/tiled_panes/pane_resizer.rs b/zellij-server/src/panes/tiled_panes/pane_resizer.rs index 6819a0a8..8667e2f6 100644 --- a/zellij-server/src/panes/tiled_panes/pane_resizer.rs +++ b/zellij-server/src/panes/tiled_panes/pane_resizer.rs @@ -8,7 +8,7 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::rc::Rc; use zellij_utils::{ - input::layout::Direction, + input::layout::SplitDirection, pane_size::{Constraint, Dimension, PaneGeom}, }; @@ -23,7 +23,7 @@ pub struct PaneResizer<'a> { #[derive(Debug, Clone, Copy)] struct Span { pid: PaneId, - direction: Direction, + direction: SplitDirection, pos: usize, size: Dimension, size_var: Variable, @@ -44,7 +44,7 @@ impl<'a> PaneResizer<'a> { } } - pub fn layout(&mut self, direction: Direction, space: usize) -> Result<(), String> { + pub fn layout(&mut self, direction: SplitDirection, space: usize) -> Result<(), String> { self.solver.reset(); let grid = self.solve(direction, space)?; let spans = self.discretize_spans(grid, space)?; @@ -52,7 +52,7 @@ impl<'a> PaneResizer<'a> { Ok(()) } - fn solve(&mut self, direction: Direction, space: usize) -> Result { + fn solve(&mut self, direction: SplitDirection, space: usize) -> Result { let grid: Grid = self .grid_boundaries(direction) .into_iter() @@ -127,12 +127,12 @@ impl<'a> PaneResizer<'a> { for span in spans { let pane = panes.get_mut(&span.pid).unwrap(); let new_geom = match span.direction { - Direction::Horizontal => PaneGeom { + SplitDirection::Horizontal => PaneGeom { x: span.pos, cols: span.size, ..pane.current_geom() }, - Direction::Vertical => PaneGeom { + SplitDirection::Vertical => PaneGeom { y: span.pos, rows: span.size, ..pane.current_geom() @@ -147,7 +147,7 @@ impl<'a> PaneResizer<'a> { } // FIXME: Functions like this should have unit tests! - fn grid_boundaries(&self, direction: Direction) -> Vec<(usize, usize)> { + fn grid_boundaries(&self, direction: SplitDirection) -> Vec<(usize, usize)> { // Select the spans running *perpendicular* to the direction of resize let spans: Vec = self .panes @@ -169,7 +169,7 @@ impl<'a> PaneResizer<'a> { bounds } - fn spans_in_boundary(&self, direction: Direction, boundary: (usize, usize)) -> Vec { + fn spans_in_boundary(&self, direction: SplitDirection, boundary: (usize, usize)) -> Vec { let bwn = |v, (s, e)| s <= v && v < e; let mut spans: Vec<_> = self .panes @@ -188,19 +188,19 @@ impl<'a> PaneResizer<'a> { spans } - fn get_span(&self, direction: Direction, pane: &dyn Pane) -> Span { + fn get_span(&self, direction: SplitDirection, pane: &dyn Pane) -> Span { let pas = pane.current_geom(); // let size_var = self.vars[&pane.pid()]; let size_var = *self.vars.get(&pane.pid()).unwrap(); match direction { - Direction::Horizontal => Span { + SplitDirection::Horizontal => Span { pid: pane.pid(), direction, pos: pas.x, size: pas.cols, size_var, }, - Direction::Vertical => Span { + SplitDirection::Vertical => Span { pid: pane.pid(), direction, pos: pas.y, diff --git a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs index 6bb90e9d..b8efc5ec 100644 --- a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs +++ b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs @@ -5,7 +5,7 @@ use crate::{panes::PaneId, tab::Pane}; use std::cmp::Reverse; use std::collections::{HashMap, HashSet}; use zellij_utils::{ - input::layout::Direction, + input::layout::SplitDirection, pane_size::{Dimension, PaneGeom, Size, Viewport}, }; @@ -42,7 +42,7 @@ impl<'a> TiledPaneGrid<'a> { } } - pub fn layout(&mut self, direction: Direction, space: usize) -> Result<(), String> { + pub fn layout(&mut self, direction: SplitDirection, space: usize) -> Result<(), String> { let mut pane_resizer = PaneResizer::new(self.panes.clone()); pane_resizer.layout(direction, space) } @@ -187,7 +187,7 @@ impl<'a> TiledPaneGrid<'a> { } fn can_reduce_pane_and_surroundings_right(&self, pane_id: &PaneId, reduce_by: f64) -> bool { let ids_left = self.pane_ids_directly_left_of(pane_id); - let flexible_left = self.ids_are_flexible(Direction::Horizontal, ids_left); + let flexible_left = self.ids_are_flexible(SplitDirection::Horizontal, ids_left); if flexible_left { self.can_reduce_pane_width(pane_id, reduce_by) } else { @@ -196,7 +196,7 @@ impl<'a> TiledPaneGrid<'a> { } fn can_reduce_pane_and_surroundings_left(&self, pane_id: &PaneId, reduce_by: f64) -> bool { let ids_right = self.pane_ids_directly_right_of(pane_id); - let flexible_right = self.ids_are_flexible(Direction::Horizontal, ids_right); + let flexible_right = self.ids_are_flexible(SplitDirection::Horizontal, ids_right); if flexible_right { self.can_reduce_pane_width(pane_id, reduce_by) } else { @@ -205,7 +205,7 @@ impl<'a> TiledPaneGrid<'a> { } fn can_reduce_pane_and_surroundings_down(&self, pane_id: &PaneId, reduce_by: f64) -> bool { let ids_above = self.pane_ids_directly_above(pane_id); - let flexible_above = self.ids_are_flexible(Direction::Vertical, ids_above); + let flexible_above = self.ids_are_flexible(SplitDirection::Vertical, ids_above); if flexible_above { self.can_reduce_pane_height(pane_id, reduce_by) } else { @@ -214,7 +214,7 @@ impl<'a> TiledPaneGrid<'a> { } fn can_reduce_pane_and_surroundings_up(&self, pane_id: &PaneId, reduce_by: f64) -> bool { let ids_below = self.pane_ids_directly_below(pane_id); - let flexible_below = self.ids_are_flexible(Direction::Vertical, ids_below); + let flexible_below = self.ids_are_flexible(SplitDirection::Vertical, ids_below); if flexible_below { self.can_reduce_pane_height(pane_id, reduce_by) } else { @@ -926,15 +926,15 @@ impl<'a> TiledPaneGrid<'a> { let pane_ids: Vec = result_panes.iter().map(|t| t.pid()).collect(); (right_resize_border, pane_ids) } - fn ids_are_flexible(&self, direction: Direction, pane_ids: Option>) -> bool { + fn ids_are_flexible(&self, direction: SplitDirection, pane_ids: Option>) -> bool { let panes = self.panes.borrow(); pane_ids.is_some() && pane_ids.unwrap().iter().all(|id| { let pane_to_check = panes.get(id).unwrap(); let geom = pane_to_check.current_geom(); let dimension = match direction { - Direction::Vertical => geom.rows, - Direction::Horizontal => geom.cols, + SplitDirection::Vertical => geom.rows, + SplitDirection::Horizontal => geom.cols, }; !dimension.is_fixed() }) @@ -967,7 +967,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_increase_pane_and_surroundings_right(pane_id, reduce_by) { self.increase_pane_and_surroundings_right(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols); + let _ = pane_resizer.layout(SplitDirection::Horizontal, self.display_area.cols); return true; } false @@ -980,7 +980,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_increase_pane_and_surroundings_left(pane_id, reduce_by) { self.increase_pane_and_surroundings_left(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols); + let _ = pane_resizer.layout(SplitDirection::Horizontal, self.display_area.cols); return true; } false @@ -989,7 +989,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_increase_pane_and_surroundings_up(pane_id, reduce_by) { self.increase_pane_and_surroundings_up(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows); + let _ = pane_resizer.layout(SplitDirection::Vertical, self.display_area.rows); return true; } false @@ -1002,7 +1002,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_increase_pane_and_surroundings_down(pane_id, reduce_by) { self.increase_pane_and_surroundings_down(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows); + let _ = pane_resizer.layout(SplitDirection::Vertical, self.display_area.rows); return true; } false @@ -1245,7 +1245,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_reduce_pane_and_surroundings_right(pane_id, reduce_by) { self.reduce_pane_and_surroundings_right(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols); + let _ = pane_resizer.layout(SplitDirection::Horizontal, self.display_area.cols); return true; } false @@ -1254,7 +1254,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_reduce_pane_and_surroundings_left(pane_id, reduce_by) { self.reduce_pane_and_surroundings_left(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Horizontal, self.display_area.cols); + let _ = pane_resizer.layout(SplitDirection::Horizontal, self.display_area.cols); return true; } false @@ -1263,7 +1263,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_reduce_pane_and_surroundings_up(pane_id, reduce_by) { self.reduce_pane_and_surroundings_up(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows); + let _ = pane_resizer.layout(SplitDirection::Vertical, self.display_area.rows); return true; } false @@ -1272,7 +1272,7 @@ impl<'a> TiledPaneGrid<'a> { if self.can_reduce_pane_and_surroundings_down(pane_id, reduce_by) { self.reduce_pane_and_surroundings_down(pane_id, reduce_by); let mut pane_resizer = PaneResizer::new(self.panes.clone()); - let _ = pane_resizer.layout(Direction::Vertical, self.display_area.rows); + let _ = pane_resizer.layout(SplitDirection::Vertical, self.display_area.rows); return true; } false @@ -1551,31 +1551,36 @@ impl<'a> TiledPaneGrid<'a> { } None } - fn find_panes_to_grow(&self, id: PaneId) -> Option<(Vec, Direction)> { + fn find_panes_to_grow(&self, id: PaneId) -> Option<(Vec, SplitDirection)> { if let Some(panes) = self .panes_to_the_left_between_aligning_borders(id) .or_else(|| self.panes_to_the_right_between_aligning_borders(id)) { - return Some((panes, Direction::Horizontal)); + return Some((panes, SplitDirection::Horizontal)); } if let Some(panes) = self .panes_above_between_aligning_borders(id) .or_else(|| self.panes_below_between_aligning_borders(id)) { - return Some((panes, Direction::Vertical)); + return Some((panes, SplitDirection::Vertical)); } None } - fn grow_panes(&mut self, panes: &[PaneId], direction: Direction, (width, height): (f64, f64)) { + fn grow_panes( + &mut self, + panes: &[PaneId], + direction: SplitDirection, + (width, height): (f64, f64), + ) { match direction { - Direction::Horizontal => { + SplitDirection::Horizontal => { for pane_id in panes { self.increase_pane_width(pane_id, width); } }, - Direction::Vertical => { + SplitDirection::Vertical => { for pane_id in panes { self.increase_pane_height(pane_id, height); } @@ -1597,8 +1602,8 @@ impl<'a> TiledPaneGrid<'a> { if let Some((panes_to_grow, direction)) = self.find_panes_to_grow(id) { self.grow_panes(&panes_to_grow, direction, (freed_width, freed_height)); let side_length = match direction { - Direction::Vertical => self.display_area.rows, - Direction::Horizontal => self.display_area.cols, + SplitDirection::Vertical => self.display_area.rows, + SplitDirection::Horizontal => self.display_area.cols, }; { let mut panes = self.panes.borrow_mut(); @@ -1614,7 +1619,7 @@ impl<'a> TiledPaneGrid<'a> { pub fn find_room_for_new_pane( &self, cursor_height_width_ratio: Option, - ) -> Option<(PaneId, Direction)> { + ) -> Option<(PaneId, SplitDirection)> { let panes = self.panes.borrow(); let pane_sequence: Vec<(&PaneId, &&mut Box)> = panes.iter().filter(|(_, p)| p.selectable()).collect(); @@ -1643,9 +1648,9 @@ impl<'a> TiledPaneGrid<'a> { > pane_to_split.cols() && pane_to_split.rows() > pane_to_split.min_height() * 2 { - Some(Direction::Horizontal) + Some(SplitDirection::Horizontal) } else if pane_to_split.cols() > pane_to_split.min_width() * 2 { - Some(Direction::Vertical) + Some(SplitDirection::Vertical) } else { None }; @@ -1655,29 +1660,29 @@ impl<'a> TiledPaneGrid<'a> { } } -pub fn split(direction: Direction, rect: &PaneGeom) -> Option<(PaneGeom, PaneGeom)> { +pub fn split(direction: SplitDirection, rect: &PaneGeom) -> Option<(PaneGeom, PaneGeom)> { let space = match direction { - Direction::Vertical => rect.cols, - Direction::Horizontal => rect.rows, + SplitDirection::Vertical => rect.cols, + SplitDirection::Horizontal => rect.rows, }; if let Some(p) = space.as_percent() { let first_rect = match direction { - Direction::Vertical => PaneGeom { + SplitDirection::Vertical => PaneGeom { cols: Dimension::percent(p / 2.0), ..*rect }, - Direction::Horizontal => PaneGeom { + SplitDirection::Horizontal => PaneGeom { rows: Dimension::percent(p / 2.0), ..*rect }, }; let second_rect = match direction { - Direction::Vertical => PaneGeom { + SplitDirection::Vertical => PaneGeom { x: first_rect.x + 1, cols: first_rect.cols, ..*rect }, - Direction::Horizontal => PaneGeom { + SplitDirection::Horizontal => PaneGeom { y: first_rect.y + 1, rows: first_rect.rows, ..*rect diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index f1489ea6..df4d270a 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -11,7 +11,7 @@ use zellij_utils::{ errors::{ContextType, PtyContext}, input::{ command::{RunCommand, TerminalAction}, - layout::{Layout, LayoutFromYaml, Run, TabLayout}, + layout::{Layout, PaneLayout, Run}, }, }; @@ -33,7 +33,12 @@ pub(crate) enum PtyInstruction { SpawnTerminalHorizontally(Option, ClientId), UpdateActivePane(Option, ClientId), GoToTab(TabIndex, ClientId), - NewTab(Option, Option, ClientId), + NewTab( + Option, + Option, + Option, + ClientId, + ), // the String is the tab name ClosePane(PaneId), CloseTab(Vec), Exit, @@ -65,9 +70,7 @@ pub(crate) struct Pty { default_editor: Option, } -use std::convert::TryFrom; - -pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) { +pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) { loop { let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Pty((&event).into())); @@ -136,20 +139,12 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) { .send_to_screen(ScreenInstruction::GoToTab(tab_index, Some(client_id))) .unwrap(); }, - PtyInstruction::NewTab(terminal_action, tab_layout, client_id) => { - let tab_name = tab_layout.as_ref().and_then(|layout| { - if layout.name.is_empty() { - None - } else { - Some(layout.name.clone()) - } - }); - - let merged_layout = layout.template.clone().insert_tab_layout(tab_layout); - let layout: Layout = - Layout::try_from(merged_layout).unwrap_or_else(|err| panic!("{}", err)); - - pty.spawn_terminals_for_layout(layout, terminal_action.clone(), client_id); + PtyInstruction::NewTab(terminal_action, tab_layout, tab_name, client_id) => { + pty.spawn_terminals_for_layout( + tab_layout.unwrap_or_else(|| layout.new_tab()), + terminal_action.clone(), + client_id, + ); if let Some(tab_name) = tab_name { // clear current name at first @@ -271,7 +266,7 @@ impl Pty { } pub fn spawn_terminals_for_layout( &mut self, - layout: Layout, + layout: PaneLayout, default_shell: Option, client_id: ClientId, ) { diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index d82ec42e..75230488 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -20,7 +20,7 @@ use zellij_utils::{ use crate::ClientId; -fn route_action( +pub(crate) fn route_action( action: Action, session: &SessionMetaData, _os_input: &dyn ServerOsApi, @@ -142,7 +142,8 @@ fn route_action( let screen_instr = match direction { Direction::Left => ScreenInstruction::MoveFocusLeftOrPreviousTab(client_id), Direction::Right => ScreenInstruction::MoveFocusRightOrNextTab(client_id), - _ => unreachable!(), + Direction::Up => ScreenInstruction::SwitchTabNext(client_id), + Direction::Down => ScreenInstruction::SwitchTabPrev(client_id), }; session.senders.send_to_screen(screen_instr).unwrap(); }, @@ -248,6 +249,108 @@ fn route_action( }; session.senders.send_to_pty(pty_instr).unwrap(); }, + Action::EditFile(path_to_file, line_number, split_direction, should_float) => { + match should_float { + Some(true) => { + session + .senders + .send_to_screen(ScreenInstruction::ShowFloatingPanes(client_id)) + .unwrap(); + }, + Some(false) => { + session + .senders + .send_to_screen(ScreenInstruction::HideFloatingPanes(client_id)) + .unwrap(); + }, + None => {}, + }; + + let open_file = TerminalAction::OpenFile(path_to_file, line_number); + let pty_instr = match (split_direction, should_float.unwrap_or(false)) { + (Some(Direction::Left), false) => { + PtyInstruction::SpawnTerminalVertically(Some(open_file), client_id) + }, + (Some(Direction::Right), false) => { + PtyInstruction::SpawnTerminalVertically(Some(open_file), client_id) + }, + (Some(Direction::Up), false) => { + PtyInstruction::SpawnTerminalHorizontally(Some(open_file), client_id) + }, + (Some(Direction::Down), false) => { + PtyInstruction::SpawnTerminalHorizontally(Some(open_file), client_id) + }, + // No direction specified or should float - defer placement to screen + (None, _) | (_, true) => PtyInstruction::SpawnTerminal( + Some(open_file), + ClientOrTabIndex::ClientId(client_id), + ), + }; + session.senders.send_to_pty(pty_instr).unwrap(); + }, + Action::SwitchModeForAllClients(input_mode) => { + let attrs = &session.client_attributes; + session + .senders + .send_to_plugin(PluginInstruction::Update( + None, + None, + Event::ModeUpdate(get_mode_info(input_mode, attrs, session.capabilities)), + )) + .unwrap(); + session + .senders + .send_to_screen(ScreenInstruction::ChangeModeForAllClients(get_mode_info( + input_mode, + attrs, + session.capabilities, + ))) + .unwrap(); + }, + Action::NewFloatingPane(run_command) => { + session + .senders + .send_to_screen(ScreenInstruction::ShowFloatingPanes(client_id)) + .unwrap(); + let run_cmd = run_command + .map(|cmd| TerminalAction::RunCommand(cmd.into())) + .or_else(|| session.default_shell.clone()); + session + .senders + .send_to_pty(PtyInstruction::SpawnTerminal( + run_cmd, + ClientOrTabIndex::ClientId(client_id), + )) + .unwrap(); + }, + Action::NewTiledPane(direction, run_command) => { + session + .senders + .send_to_screen(ScreenInstruction::HideFloatingPanes(client_id)) + .unwrap(); + let run_cmd = run_command + .map(|cmd| TerminalAction::RunCommand(cmd.into())) + .or_else(|| session.default_shell.clone()); + let pty_instr = match direction { + Some(Direction::Left) => { + PtyInstruction::SpawnTerminalVertically(run_cmd, client_id) + }, + Some(Direction::Right) => { + PtyInstruction::SpawnTerminalVertically(run_cmd, client_id) + }, + Some(Direction::Up) => { + PtyInstruction::SpawnTerminalHorizontally(run_cmd, client_id) + }, + Some(Direction::Down) => { + PtyInstruction::SpawnTerminalHorizontally(run_cmd, client_id) + }, + // No direction specified - try to put it in the biggest available spot + None => { + PtyInstruction::SpawnTerminal(run_cmd, ClientOrTabIndex::ClientId(client_id)) + }, + }; + session.senders.send_to_pty(pty_instr).unwrap(); + }, Action::TogglePaneEmbedOrFloating => { session .senders @@ -303,11 +406,13 @@ fn route_action( .send_to_screen(ScreenInstruction::CloseFocusedPane(client_id)) .unwrap(); }, - Action::NewTab(tab_layout) => { + Action::NewTab(tab_layout, tab_name) => { let shell = session.default_shell.clone(); session .senders - .send_to_pty(PtyInstruction::NewTab(shell, tab_layout, client_id)) + .send_to_pty(PtyInstruction::NewTab( + shell, tab_layout, tab_name, client_id, + )) .unwrap(); }, Action::GoToNextTab => { diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index ef4b4f60..012cc557 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -9,7 +9,7 @@ use std::str; use zellij_utils::errors::prelude::*; use zellij_utils::input::options::Clipboard; use zellij_utils::pane_size::{Size, SizeInPixels}; -use zellij_utils::{input::command::TerminalAction, input::layout::Layout, position::Position}; +use zellij_utils::{input::command::TerminalAction, input::layout::PaneLayout, position::Position}; use crate::panes::alacritty_functions::xparse_color; use crate::panes::terminal_character::AnsiCode; @@ -29,7 +29,7 @@ use zellij_utils::{ data::{Event, InputMode, ModeInfo, Palette, PaletteColor, PluginCapabilities, Style, TabInfo}, errors::{ContextType, ScreenContext}, input::{get_mode_info, options::Options}, - ipc::{ClientAttributes, PixelDimensions}, + ipc::{ClientAttributes, PixelDimensions, ServerToClientMsg}, }; /// Get the active tab and call a closure on it @@ -41,6 +41,7 @@ use zellij_utils::{ /// - screen: An instance of `Screen` to operate on /// - client_id: The client_id, usually taken from the `ScreenInstruction` that's being processed /// - closure: A closure satisfying `|tab: &mut Tab| -> ()` + macro_rules! active_tab { ($screen:ident, $client_id:ident, $closure:expr) => { if let Some(active_tab) = $screen.get_active_tab_mut($client_id) { @@ -54,6 +55,27 @@ macro_rules! active_tab { } }; } +macro_rules! active_tab_and_connected_client_id { + ($screen:ident, $client_id:ident, $closure:expr) => { + match $screen.get_active_tab_mut($client_id) { + Some(active_tab) => { + $closure(active_tab, $client_id); + }, + None => { + if let Some(client_id) = $screen.get_first_client_id() { + match $screen.get_active_tab_mut(client_id) { + Some(active_tab) => { + $closure(active_tab, client_id); + }, + None => { + log::error!("Active tab not found for client id: {:?}", $client_id); + }, + } + }; + }, + } + }; +} /// Instructions that can be sent to the [`Screen`]. #[derive(Debug, Clone)] @@ -64,6 +86,8 @@ pub enum ScreenInstruction { OpenInPlaceEditor(PaneId, ClientId), TogglePaneEmbedOrFloating(ClientId), ToggleFloatingPanes(ClientId, Option), + ShowFloatingPanes(ClientId), + HideFloatingPanes(ClientId), HorizontalSplit(PaneId, ClientId), VerticalSplit(PaneId, ClientId), WriteCharacter(Vec, ClientId), @@ -107,7 +131,7 @@ pub enum ScreenInstruction { ClosePane(PaneId, Option), UpdatePaneName(Vec, ClientId), UndoRenamePane(ClientId), - NewTab(Layout, Vec, ClientId), + NewTab(PaneLayout, Vec, ClientId), SwitchTabNext(ClientId), SwitchTabPrev(ClientId), ToggleActiveSyncTab(ClientId), @@ -122,6 +146,7 @@ pub enum ScreenInstruction { TerminalForegroundColor(String), TerminalColorRegisters(Vec<(usize, String)>), ChangeMode(ModeInfo, ClientId), + ChangeModeForAllClients(ModeInfo), LeftClick(Position, ClientId), RightClick(Position, ClientId), MiddleClick(Position, ClientId), @@ -157,6 +182,8 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenContext::TogglePaneEmbedOrFloating }, ScreenInstruction::ToggleFloatingPanes(..) => ScreenContext::ToggleFloatingPanes, + ScreenInstruction::ShowFloatingPanes(..) => ScreenContext::ShowFloatingPanes, + ScreenInstruction::HideFloatingPanes(..) => ScreenContext::HideFloatingPanes, ScreenInstruction::HorizontalSplit(..) => ScreenContext::HorizontalSplit, ScreenInstruction::VerticalSplit(..) => ScreenContext::VerticalSplit, ScreenInstruction::WriteCharacter(..) => ScreenContext::WriteCharacter, @@ -223,6 +250,9 @@ impl From<&ScreenInstruction> for ScreenContext { }, ScreenInstruction::TerminalColorRegisters(..) => ScreenContext::TerminalColorRegisters, ScreenInstruction::ChangeMode(..) => ScreenContext::ChangeMode, + ScreenInstruction::ChangeModeForAllClients(..) => { + ScreenContext::ChangeModeForAllClients + }, ScreenInstruction::ToggleActiveSyncTab(..) => ScreenContext::ToggleActiveSyncTab, ScreenInstruction::ScrollUpAt(..) => ScreenContext::ScrollUpAt, ScreenInstruction::ScrollDownAt(..) => ScreenContext::ScrollDownAt, @@ -485,35 +515,51 @@ impl Screen { /// Sets this [`Screen`]'s active [`Tab`] to the next tab. pub fn switch_tab_next(&mut self, client_id: ClientId) -> Result<()> { - if let Some(active_tab) = self.get_active_tab(client_id) { - let active_tab_pos = active_tab.position; - let new_tab_pos = (active_tab_pos + 1) % self.tabs.len(); - self.switch_active_tab(new_tab_pos, client_id) + let client_id = if self.get_active_tab(client_id).is_some() { + Some(client_id) } else { + self.get_first_client_id() + }; + if let Some(client_id) = client_id { + if let Some(active_tab) = self.get_active_tab(client_id) { + let active_tab_pos = active_tab.position; + let new_tab_pos = (active_tab_pos + 1) % self.tabs.len(); + return self.switch_active_tab(new_tab_pos, client_id); + } else { + log::error!("Active tab not found for client_id: {:?}", client_id); + } log::error!("Active tab not found for client id: {client_id:?}"); - Ok(()) } + Ok(()) } /// Sets this [`Screen`]'s active [`Tab`] to the previous tab. pub fn switch_tab_prev(&mut self, client_id: ClientId) -> Result<()> { - if let Some(active_tab) = self.get_active_tab(client_id) { - let active_tab_pos = active_tab.position; - let new_tab_pos = if active_tab_pos == 0 { - self.tabs.len() - 1 - } else { - active_tab_pos - 1 - }; - - self.switch_active_tab(new_tab_pos, client_id) + let client_id = if self.get_active_tab(client_id).is_some() { + Some(client_id) } else { + self.get_first_client_id() + }; + if let Some(client_id) = client_id { + if let Some(active_tab) = self.get_active_tab(client_id) { + let active_tab_pos = active_tab.position; + let new_tab_pos = if active_tab_pos == 0 { + self.tabs.len() - 1 + } else { + active_tab_pos - 1 + }; + + return self.switch_active_tab(new_tab_pos, client_id); + } else { + log::error!("Active tab not found for client_id: {:?}", client_id); + } log::error!("Active tab not found for client id: {client_id:?}"); - Ok(()) } + Ok(()) } pub fn go_to_tab(&mut self, tab_index: usize, client_id: ClientId) -> Result<()> { - self.switch_active_tab(tab_index - 1, client_id) + self.switch_active_tab(tab_index.saturating_sub(1), client_id) } fn close_tab_at_index(&mut self, tab_index: usize) -> Result<()> { @@ -555,13 +601,22 @@ impl Screen { // Closes the client_id's focused tab pub fn close_tab(&mut self, client_id: ClientId) -> Result<()> { let err_context = || format!("failed to close tab for client {client_id:?}"); - - let active_tab_index = *self - .active_tab_indices - .get(&client_id) - .with_context(err_context)?; - self.close_tab_at_index(active_tab_index) - .with_context(err_context) + let client_id = if self.get_active_tab(client_id).is_some() { + Some(client_id) + } else { + self.get_first_client_id() + }; + match client_id { + Some(client_id) => { + let active_tab_index = *self + .active_tab_indices + .get(&client_id) + .with_context(err_context)?; + self.close_tab_at_index(active_tab_index) + .with_context(err_context) + }, + None => Ok(()), + } } pub fn resize_to_screen(&mut self, new_screen_size: Size) -> Result<()> { @@ -656,6 +711,10 @@ impl Screen { } } + pub fn get_first_client_id(&self) -> Option { + self.active_tab_indices.keys().next().copied() + } + /// Returns an immutable reference to this [`Screen`]'s previous active [`Tab`]. /// Consumes the last entry in tab history. pub fn get_previous_tab(&mut self, client_id: ClientId) -> Result> { @@ -696,12 +755,18 @@ impl Screen { /// and switching to it. pub fn new_tab( &mut self, - layout: Layout, + layout: PaneLayout, new_pids: Vec, client_id: ClientId, ) -> Result<()> { + let client_id = if self.get_active_tab(client_id).is_some() { + client_id + } else if let Some(first_client_id) = self.get_first_client_id() { + first_client_id + } else { + client_id + }; let err_context = || format!("failed to create new tab for client {client_id:?}"); - let tab_index = self.get_new_tab_index(); let position = self.tabs.len(); let mut tab = Tab::new( @@ -854,44 +919,62 @@ impl Screen { } pub fn update_active_tab_name(&mut self, buf: Vec, client_id: ClientId) -> Result<()> { - let s = str::from_utf8(&buf) - .with_context(|| format!("failed to construct tab name from buf: {buf:?}"))?; - if let Some(active_tab) = self.get_active_tab_mut(client_id) { - match s { - "\0" => { - active_tab.name = String::new(); - }, - "\u{007F}" | "\u{0008}" => { - // delete and backspace keys - active_tab.name.pop(); - }, - c => { - // It only allows printable unicode - if buf.iter().all(|u| matches!(u, 0x20..=0x7E)) { - active_tab.name.push_str(c); - } - }, - } - self.update_tabs().with_context(|| { - format!("failed to update active tabs name for client id: {client_id:?}") - }) + let client_id = if self.get_active_tab(client_id).is_some() { + Some(client_id) } else { - log::error!("Active tab not found for client id: {client_id:?}"); - Ok(()) + self.get_first_client_id() + }; + match client_id { + Some(client_id) => { + let s = str::from_utf8(&buf) + .with_context(|| format!("failed to construct tab name from buf: {buf:?}"))?; + if let Some(active_tab) = self.get_active_tab_mut(client_id) { + match s { + "\0" => { + active_tab.name = String::new(); + }, + "\u{007F}" | "\u{0008}" => { + // delete and backspace keys + active_tab.name.pop(); + }, + c => { + // It only allows printable unicode + if buf.iter().all(|u| matches!(u, 0x20..=0x7E)) { + active_tab.name.push_str(c); + } + }, + } + self.update_tabs().with_context(|| { + format!("failed to update active tabs name for client id: {client_id:?}") + }) + } else { + log::error!("Active tab not found for client id: {client_id:?}"); + Ok(()) + } + }, + None => Ok(()), } } - pub fn undo_active_rename_tab(&mut self, client_id: ClientId) -> Result<()> { - if let Some(active_tab) = self.get_active_tab_mut(client_id) { - if active_tab.name != active_tab.prev_name { - active_tab.name = active_tab.prev_name.clone(); - self.update_tabs() - .context("failed to undo renaming of active tab")?; - } - Ok(()) + let client_id = if self.get_active_tab(client_id).is_some() { + Some(client_id) } else { - log::error!("Active tab not found for client id: {client_id:?}"); - Ok(()) + self.get_first_client_id() + }; + match client_id { + Some(client_id) => { + if let Some(active_tab) = self.get_active_tab_mut(client_id) { + if active_tab.name != active_tab.prev_name { + active_tab.name = active_tab.prev_name.clone(); + self.update_tabs() + .context("failed to undo renaming of active tab")?; + } + } else { + log::error!("Active tab not found for client id: {client_id:?}"); + } + Ok(()) + }, + None => Ok(()), } } @@ -941,26 +1024,49 @@ impl Screen { tab.mark_active_pane_for_rerender(client_id); } } - - pub fn move_focus_left_or_previous_tab(&mut self, client_id: ClientId) -> Result<()> { - if let Some(active_tab) = self.get_active_tab_mut(client_id) { - if !active_tab.move_focus_left(client_id) { - self.switch_tab_prev(client_id) - .context("failed to move focus left")?; + pub fn change_mode_for_all_clients(&mut self, mode_info: ModeInfo) { + let connected_client_ids: Vec = self.active_tab_indices.keys().copied().collect(); + for client_id in connected_client_ids { + self.change_mode(mode_info.clone(), client_id); + if let Some(os_input) = &mut self.bus.os_input { + let _ = os_input + .send_to_client(client_id, ServerToClientMsg::SwitchToMode(mode_info.mode)); } + } + } + pub fn move_focus_left_or_previous_tab(&mut self, client_id: ClientId) -> Result<()> { + let client_id = if self.get_active_tab(client_id).is_some() { + Some(client_id) } else { - log::error!("Active tab not found for client id: {:?}", client_id); + self.get_first_client_id() + }; + if let Some(client_id) = client_id { + if let Some(active_tab) = self.get_active_tab_mut(client_id) { + if !active_tab.move_focus_left(client_id) { + self.switch_tab_prev(client_id) + .context("failed to move focus left")?; + } + } else { + log::error!("Active tab not found for client id: {:?}", client_id); + } } Ok(()) } pub fn move_focus_right_or_next_tab(&mut self, client_id: ClientId) -> Result<()> { - if let Some(active_tab) = self.get_active_tab_mut(client_id) { - if !active_tab.move_focus_right(client_id) { - self.switch_tab_next(client_id) - .context("failed to move focus right")?; - } + let client_id = if self.get_active_tab(client_id).is_some() { + Some(client_id) } else { - log::error!("Active tab not found for client id: {:?}", client_id); + self.get_first_client_id() + }; + if let Some(client_id) = client_id { + if let Some(active_tab) = self.get_active_tab_mut(client_id) { + if !active_tab.move_focus_right(client_id) { + self.switch_tab_next(client_id) + .context("failed to move focus right")?; + } + } else { + log::error!("Active tab not found for client id: {:?}", client_id); + } } Ok(()) } @@ -996,7 +1102,6 @@ pub(crate) fn screen_thread_main( client_attributes: ClientAttributes, config_options: Box, ) -> Result<()> { - // let mut scrollbacks: HashMap = HashMap::new(); let capabilities = config_options.simplified_ui; let draw_pane_frames = config_options.pane_frames.unwrap_or(true); let session_is_mirrored = config_options.mirror_session.unwrap_or(false); @@ -1046,8 +1151,11 @@ pub(crate) fn screen_thread_main( ScreenInstruction::NewPane(pid, client_or_tab_index) => { match client_or_tab_index { ClientOrTabIndex::ClientId(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .new_pane(pid, Some(client_id))); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.new_pane(pid, Some(client_id)) + ); }, ClientOrTabIndex::TabIndex(tab_index) => { if let Some(active_tab) = screen.tabs.get_mut(&tab_index) { @@ -1071,89 +1179,168 @@ pub(crate) fn screen_thread_main( screen.render()?; }, ScreenInstruction::TogglePaneEmbedOrFloating(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .toggle_pane_embed_or_floating(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .toggle_pane_embed_or_floating(client_id) + ); screen.unblock_input()?; screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins screen.render()?; }, ScreenInstruction::ToggleFloatingPanes(client_id, default_shell) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .toggle_floating_panes(client_id, default_shell)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .toggle_floating_panes(client_id, default_shell) + ); + screen.unblock_input()?; + screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins + screen.render()?; + }, + ScreenInstruction::ShowFloatingPanes(client_id) => { + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, _client_id: ClientId| tab.show_floating_panes() + ); + screen.unblock_input()?; + screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins + screen.render()?; + }, + ScreenInstruction::HideFloatingPanes(client_id) => { + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, _client_id: ClientId| tab.hide_floating_panes() + ); screen.unblock_input()?; screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins screen.render()?; }, ScreenInstruction::HorizontalSplit(pid, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .horizontal_split(pid, client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.horizontal_split(pid, client_id) + ); screen.unblock_input()?; screen.update_tabs()?; screen.render()?; }, ScreenInstruction::VerticalSplit(pid, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .vertical_split(pid, client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.vertical_split(pid, client_id) + ); screen.unblock_input()?; screen.update_tabs()?; screen.render()?; }, ScreenInstruction::WriteCharacter(bytes, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| { - match tab.is_sync_panes_active() { - true => tab.write_to_terminals_on_current_tab(bytes), - false => tab.write_to_active_terminal(bytes, client_id), + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| { + match tab.is_sync_panes_active() { + true => tab.write_to_terminals_on_current_tab(bytes), + false => tab.write_to_active_terminal(bytes, client_id), + } } - }); + ); }, ScreenInstruction::ResizeLeft(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .resize_left(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.resize_left(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::ResizeRight(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .resize_right(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.resize_right(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::ResizeDown(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .resize_down(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.resize_down(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::ResizeUp(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab.resize_up(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.resize_up(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::ResizeIncrease(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .resize_increase(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.resize_increase(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::ResizeDecrease(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .resize_decrease(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.resize_decrease(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::SwitchFocus(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .focus_next_pane(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.focus_next_pane(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::FocusNextPane(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .focus_next_pane(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.focus_next_pane(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::FocusPreviousPane(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .focus_previous_pane(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.focus_previous_pane(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MoveFocusLeft(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_focus_left(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_focus_left(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MoveFocusLeftOrPreviousTab(client_id) => { screen.move_focus_left_or_previous_tab(client_id)?; @@ -1161,14 +1348,22 @@ pub(crate) fn screen_thread_main( screen.render()?; }, ScreenInstruction::MoveFocusDown(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_focus_down(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_focus_down(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MoveFocusRight(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_focus_right(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_focus_right(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MoveFocusRightOrNextTab(client_id) => { screen.move_focus_right_or_next_tab(client_id)?; @@ -1176,99 +1371,184 @@ pub(crate) fn screen_thread_main( screen.render()?; }, ScreenInstruction::MoveFocusUp(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_focus_up(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_focus_up(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::DumpScreen(file, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .dump_active_terminal_screen(Some(file.to_string()), client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .dump_active_terminal_screen(Some(file.to_string()), client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::EditScrollback(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .edit_scrollback(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.edit_scrollback(client_id) + ); screen.render()?; }, ScreenInstruction::ScrollUp(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .scroll_active_terminal_up(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.scroll_active_terminal_up(client_id) + ); + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::MovePane(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_active_pane(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_active_pane(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MovePaneDown(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_active_pane_down(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_active_pane_down(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MovePaneUp(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_active_pane_up(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_active_pane_up(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MovePaneRight(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_active_pane_right(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_active_pane_right(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MovePaneLeft(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .move_active_pane_left(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_active_pane_left(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::ScrollUpAt(point, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .handle_scrollwheel_up(&point, 3, client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .handle_scrollwheel_up(&point, 3, client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::ScrollDown(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .scroll_active_terminal_down(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.scroll_active_terminal_down(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::ScrollDownAt(point, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .handle_scrollwheel_down(&point, 3, client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .handle_scrollwheel_down(&point, 3, client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::ScrollToBottom(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .scroll_active_terminal_to_bottom(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .scroll_active_terminal_to_bottom(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::PageScrollUp(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .scroll_active_terminal_up_page(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .scroll_active_terminal_up_page(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::PageScrollDown(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .scroll_active_terminal_down_page(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .scroll_active_terminal_down_page(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::HalfPageScrollUp(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .scroll_active_terminal_up_half_page(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .scroll_active_terminal_up_half_page(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::HalfPageScrollDown(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .scroll_active_terminal_down_half_page(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .scroll_active_terminal_down_half_page(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::ClearScroll(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .clear_active_terminal_scroll(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .clear_active_terminal_scroll(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::CloseFocusedPane(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .close_focused_pane(client_id)); - screen.update_tabs()?; // update_tabs eventually calls render through the plugin thread + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.close_focused_pane(client_id) + ); + screen.update_tabs()?; + screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::SetSelectable(id, selectable, tab_index) => { screen.get_indexed_tab_mut(tab_index).map_or_else( @@ -1299,22 +1579,36 @@ pub(crate) fn screen_thread_main( }, } screen.update_tabs()?; + screen.unblock_input()?; }, ScreenInstruction::UpdatePaneName(c, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .update_active_pane_name(c, client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.update_active_pane_name(c, client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::UndoRenamePane(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .undo_active_rename_pane(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.undo_active_rename_pane(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::ToggleActiveTerminalFullscreen(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .toggle_active_pane_fullscreen(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .toggle_active_pane_fullscreen(client_id) + ); screen.update_tabs()?; screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::TogglePaneFrames => { screen.draw_pane_frames = !screen.draw_pane_frames; @@ -1322,6 +1616,7 @@ pub(crate) fn screen_thread_main( tab.set_pane_frames(screen.draw_pane_frames); } screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::SwitchTabNext(client_id) => { screen.switch_tab_next(client_id)?; @@ -1344,9 +1639,14 @@ pub(crate) fn screen_thread_main( screen.render()?; }, ScreenInstruction::GoToTab(tab_index, client_id) => { - if let Some(client_id) = - client_id.or_else(|| screen.active_tab_indices.keys().next().copied()) - { + let client_id = if client_id.is_none() { + None + } else if screen.active_tab_indices.contains_key(&client_id.unwrap()) { + client_id + } else { + screen.active_tab_indices.keys().next().copied() + }; + if let Some(client_id) = client_id { screen.go_to_tab(tab_index as usize, client_id)?; screen.unblock_input()?; screen.render()?; @@ -1354,10 +1654,12 @@ pub(crate) fn screen_thread_main( }, ScreenInstruction::UpdateTabName(c, client_id) => { screen.update_active_tab_name(c, client_id)?; + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::UndoRenameTab(client_id) => { screen.undo_active_rename_tab(client_id)?; + screen.unblock_input()?; screen.render()?; }, ScreenInstruction::TerminalResize(new_size) => { @@ -1379,35 +1681,49 @@ pub(crate) fn screen_thread_main( ScreenInstruction::ChangeMode(mode_info, client_id) => { screen.change_mode(mode_info, client_id); screen.render()?; + screen.unblock_input()?; + }, + ScreenInstruction::ChangeModeForAllClients(mode_info) => { + screen.change_mode_for_all_clients(mode_info); + screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::ToggleActiveSyncTab(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .toggle_sync_panes_is_active()); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, _client_id: ClientId| tab.toggle_sync_panes_is_active() + ); screen.update_tabs()?; screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::LeftClick(point, client_id) => { active_tab!(screen, client_id, |tab: &mut Tab| tab .handle_left_click(&point, client_id)); screen.update_tabs()?; screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::RightClick(point, client_id) => { active_tab!(screen, client_id, |tab: &mut Tab| tab .handle_right_click(&point, client_id)); screen.update_tabs()?; screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::MiddleClick(point, client_id) => { active_tab!(screen, client_id, |tab: &mut Tab| tab .handle_middle_click(&point, client_id)); screen.update_tabs()?; screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::LeftMouseRelease(point, client_id) => { active_tab!(screen, client_id, |tab: &mut Tab| tab .handle_left_mouse_release(&point, client_id)); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::RightMouseRelease(point, client_id) => { active_tab!(screen, client_id, |tab: &mut Tab| tab @@ -1488,39 +1804,63 @@ pub(crate) fn screen_thread_main( screen.unblock_input()?; }, ScreenInstruction::UpdateSearch(c, client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .update_search_term(c, client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.update_search_term(c, client_id) + ); screen.render()?; }, ScreenInstruction::SearchDown(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .search_down(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.search_down(client_id) + ); screen.render()?; }, ScreenInstruction::SearchUp(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab.search_up(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.search_up(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::SearchToggleCaseSensitivity(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .toggle_search_case_sensitivity(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab + .toggle_search_case_sensitivity(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::SearchToggleWrap(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .toggle_search_wrap(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.toggle_search_wrap(client_id) + ); screen.render()?; + screen.unblock_input()?; }, ScreenInstruction::SearchToggleWholeWord(client_id) => { - active_tab!(screen, client_id, |tab: &mut Tab| tab - .toggle_search_whole_words(client_id)); + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.toggle_search_whole_words(client_id) + ); screen.render()?; + screen.unblock_input()?; }, } } Ok(()) } -#[cfg(test)] #[path = "./unit/screen_tests.rs"] +#[cfg(test)] mod screen_tests; diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 31f3fa1c..883caf0d 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -40,7 +40,7 @@ use zellij_utils::{ data::{Event, InputMode, ModeInfo, Palette, PaletteColor, Style}, input::{ command::TerminalAction, - layout::{Layout, Run}, + layout::{PaneLayout, Run}, parse_keys, }, pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport}, @@ -454,7 +454,7 @@ impl Tab { pub fn apply_layout( &mut self, - layout: Layout, + layout: PaneLayout, new_pids: Vec, tab_index: usize, client_id: ClientId, @@ -478,7 +478,7 @@ impl Tab { let mut new_pids = new_pids.iter(); let mut focus_pane_id: Option = None; - let mut set_focus_pane_id = |layout: &Layout, pane_id: PaneId| { + let mut set_focus_pane_id = |layout: &PaneLayout, pane_id: PaneId| { if layout.focus.unwrap_or(false) && focus_pane_id.is_none() { focus_pane_id = Some(pane_id); } @@ -498,7 +498,7 @@ impl Tab { *position_and_size, self.senders.to_plugin.as_ref().unwrap().clone(), pane_title, - layout.pane_name.clone().unwrap_or_default(), + layout.name.clone().unwrap_or_default(), ); new_plugin.set_borderless(layout.borderless); self.tiled_panes @@ -513,7 +513,7 @@ impl Tab { *position_and_size, self.style, next_terminal_position, - layout.pane_name.clone().unwrap_or_default(), + layout.name.clone().unwrap_or_default(), self.link_handler.clone(), self.character_cell_size.clone(), self.sixel_image_store.clone(), @@ -734,6 +734,14 @@ impl Tab { } self.set_force_render(); } + pub fn show_floating_panes(&mut self) { + self.floating_panes.toggle_show_panes(true); + self.set_force_render(); + } + pub fn hide_floating_panes(&mut self) { + self.floating_panes.toggle_show_panes(false); + self.set_force_render(); + } pub fn new_pane(&mut self, pid: PaneId, client_id: Option) { self.close_down_to_max_terminals(); if self.floating_panes.panes_are_visible() { @@ -2036,7 +2044,6 @@ impl Tab { position_on_screen: &Position, client_id: ClientId, ) -> bool { - println!("mouse hold middle"); // return value indicates whether we should trigger a render // determine if event is repeated to enable smooth scrolling let is_repeated = if let Some(last_position) = self.last_mouse_hold_position { @@ -2044,13 +2051,11 @@ impl Tab { } else { false }; - println!("is repeated: {:?}", is_repeated); self.last_mouse_hold_position = Some(*position_on_screen); let active_pane = self.get_active_pane_or_floating_pane_mut(client_id); if let Some(active_pane) = active_pane { - println!("can have active pane"); let mut relative_position = active_pane.relative_position(position_on_screen); if !is_repeated { relative_position.change_column( @@ -2066,7 +2071,6 @@ impl Tab { ); if let Some(mouse_event) = active_pane.mouse_middle_click(&relative_position, true) { - log::info!("can have mouse event: {:?}", mouse_event); self.write_to_active_terminal(mouse_event.into_bytes(), client_id); return true; // we need to re-render in this case so the selection disappears } diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_basic_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_basic_layout.snap new file mode 100644 index 00000000..2a3dc369 --- /dev/null +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_basic_layout.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 2130 +expression: snapshot +--- +00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): │ │└──────────────────────────────────────────────────────────┘ +10 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐ +11 (C): │ ││ │ +12 (C): │ ││ │ +13 (C): │ ││ │ +14 (C): │ ││ │ +15 (C): │ ││ │ +16 (C): │ ││ │ +17 (C): │ ││ │ +18 (C): │ ││ │ +19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_layout.snap new file mode 100644 index 00000000..2d185efe --- /dev/null +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_layout.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 2170 +expression: snapshot +--- +00 (C): ┌ Pane #1 ──────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ Pane #6 ─────────────────────────────┐ +01 (C): │ ││ ││ │ +02 (C): │ ││ ││ │ +03 (C): │ ││ ││ │ +04 (C): │ ││ ││ │ +05 (C): │ ││ ││ │ +06 (C): │ ││ ││ │ +07 (C): │ ││ ││ │ +08 (C): │ ││ ││ │ +09 (C): │ │└──────────────────────────────────────┘│ │ +10 (C): │ │┌ Pane #3 ───┐┌ Pane #4 ──┐┌ Pane #5 ──┐│ │ +11 (C): │ ││ ││ ││ ││ │ +12 (C): │ ││ ││ ││ ││ │ +13 (C): │ ││ ││ ││ ││ │ +14 (C): │ ││ ││ ││ ││ │ +15 (C): │ ││ ││ ││ ││ │ +16 (C): │ ││ ││ ││ ││ │ +17 (C): │ ││ ││ ││ ││ │ +18 (C): │ ││ ││ ││ ││ │ +19 (C): └───────────────────────────────────────┘└────────────┘└───────────┘└───────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_uneven_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_uneven_layout.snap new file mode 100644 index 00000000..6ac556ba --- /dev/null +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_uneven_layout.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 2204 +expression: snapshot +--- +00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ │└──────────────────────────────────────────────────────────┘ +05 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ +10 (C): ┌ Pane #4 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +11 (C): │ │ +12 (C): │ │ +13 (C): │ │ +14 (C): │ │ +15 (C): │ │ +16 (C): │ │ +17 (C): │ │ +18 (C): │ │ +19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index 14a9c9e1..3b26bc26 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -9,12 +9,11 @@ use crate::{ thread_bus::ThreadSenders, ClientId, }; -use std::convert::TryInto; use std::path::PathBuf; use zellij_utils::channels::Receiver; use zellij_utils::envs::set_session_name; use zellij_utils::errors::ErrorContext; -use zellij_utils::input::layout::LayoutTemplate; +use zellij_utils::input::layout::{Layout, PaneLayout}; use zellij_utils::ipc::IpcReceiverWithContext; use zellij_utils::pane_size::{Size, SizeInPixels}; use zellij_utils::position::Position; @@ -213,12 +212,62 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab { terminal_emulator_colors, terminal_emulator_color_codes, ); - tab.apply_layout( - LayoutTemplate::default().try_into().unwrap(), - vec![1], + tab.apply_layout(PaneLayout::default(), vec![1], index, client_id); + tab +} + +fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str) -> Tab { + set_session_name("test".into()); + let index = 0; + let position = 0; + let name = String::new(); + let os_api = Box::new(FakeInputOutput { + file_dumps: Arc::new(Mutex::new(HashMap::new())), + }); + let senders = ThreadSenders::default().silently_fail_on_send(); + let max_panes = None; + let mode_info = default_mode; + let style = Style::default(); + let draw_pane_frames = true; + let client_id = 1; + let session_is_mirrored = true; + let mut connected_clients = HashSet::new(); + connected_clients.insert(client_id); + let connected_clients = Rc::new(RefCell::new(connected_clients)); + let character_cell_info = Rc::new(RefCell::new(None)); + let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default())); + let copy_options = CopyOptions::default(); + let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); + let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); + let layout = Layout::from_str(layout, "layout_file_name".into()).unwrap(); + let tab_layout = layout.new_tab(); + let mut tab = Tab::new( index, + position, + name, + size, + character_cell_info, + sixel_image_store, + os_api, + senders, + max_panes, + style, + mode_info, + draw_pane_frames, + connected_clients, + session_is_mirrored, client_id, + copy_options, + terminal_emulator_colors, + terminal_emulator_color_codes, ); + let pane_ids = tab_layout + .extract_run_instructions() + .iter() + .enumerate() + .map(|(i, _)| i as i32) + .collect(); + tab.apply_layout(tab_layout, pane_ids, index, client_id); tab } @@ -271,7 +320,8 @@ fn create_new_tab_with_mock_pty_writer( terminal_emulator_color_codes, ); tab.apply_layout( - LayoutTemplate::default().try_into().unwrap(), + // LayoutTemplate::default().try_into().unwrap(), + PaneLayout::default(), vec![1], index, client_id, @@ -329,12 +379,7 @@ fn create_new_tab_with_sixel_support( terminal_emulator_colors, terminal_emulator_color_codes, ); - tab.apply_layout( - LayoutTemplate::default().try_into().unwrap(), - vec![1], - index, - client_id, - ); + tab.apply_layout(PaneLayout::default(), vec![1], index, client_id); tab } @@ -2050,6 +2095,110 @@ fn pane_in_utf8_normal_event_tracking_mouse_mode() { ); } +#[test] +fn tab_with_basic_layout() { + let layout = r#" + layout { + pane split_direction="Vertical" { + pane + pane split_direction="Horizontal" { + pane + pane + } + } + } + "#; + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 1; + let mut tab = create_new_tab_with_layout(size, ModeInfo::default(), layout); + let mut output = Output::default(); + tab.render(&mut output, None); + let snapshot = take_snapshot( + output.serialize().get(&client_id).unwrap(), + size.rows, + size.cols, + Palette::default(), + ); + assert_snapshot!(snapshot); +} + +#[test] +fn tab_with_nested_layout() { + let layout = r#" + layout { + pane_template name="top-and-vertical-sandwich" { + pane + vertical-sandwich { + pane + } + } + pane_template name="vertical-sandwich" split_direction="vertical" { + pane + children + pane + } + pane_template name="nested-vertical-sandwich" split_direction="vertical" { + pane + top-and-vertical-sandwich + pane + } + nested-vertical-sandwich + } + "#; + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 1; + let mut tab = create_new_tab_with_layout(size, ModeInfo::default(), layout); + let mut output = Output::default(); + tab.render(&mut output, None); + let snapshot = take_snapshot( + output.serialize().get(&client_id).unwrap(), + size.rows, + size.cols, + Palette::default(), + ); + assert_snapshot!(snapshot); +} + +#[test] +fn tab_with_nested_uneven_layout() { + let layout = r#" + layout { + pane_template name="horizontal-with-vertical-top" { + pane split_direction="Vertical" { + pane + children + } + pane + } + horizontal-with-vertical-top name="my tab" { + pane + pane + } + } + "#; + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 1; + let mut tab = create_new_tab_with_layout(size, ModeInfo::default(), layout); + let mut output = Output::default(); + tab.render(&mut output, None); + let snapshot = take_snapshot( + output.serialize().get(&client_id).unwrap(), + size.rows, + size.cols, + Palette::default(), + ); + assert_snapshot!(snapshot); +} + #[test] fn pane_bracketed_paste_ignored_when_not_in_bracketed_paste_mode() { // regression test for: https://github.com/zellij-org/zellij/issues/1687 diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index 8a307250..60604b00 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -7,9 +7,8 @@ use crate::{ thread_bus::ThreadSenders, ClientId, }; -use std::convert::TryInto; use std::path::PathBuf; -use zellij_utils::input::layout::LayoutTemplate; +use zellij_utils::input::layout::PaneLayout; use zellij_utils::ipc::IpcReceiverWithContext; use zellij_utils::pane_size::{Size, SizeInPixels}; @@ -132,12 +131,7 @@ fn create_new_tab(size: Size) -> Tab { terminal_emulator_colors, terminal_emulator_color_codes, ); - tab.apply_layout( - LayoutTemplate::default().try_into().unwrap(), - vec![1], - index, - client_id, - ); + tab.apply_layout(PaneLayout::default(), vec![1], index, client_id); tab } @@ -183,12 +177,7 @@ fn create_new_tab_with_cell_size( terminal_emulator_colors, terminal_emulator_color_codes, ); - tab.apply_layout( - LayoutTemplate::default().try_into().unwrap(), - vec![1], - index, - client_id, - ); + tab.apply_layout(PaneLayout::default(), vec![1], index, client_id); tab } diff --git a/zellij-server/src/thread_bus.rs b/zellij-server/src/thread_bus.rs index 1bb00c09..21ddecfe 100644 --- a/zellij-server/src/thread_bus.rs +++ b/zellij-server/src/thread_bus.rs @@ -147,6 +147,12 @@ impl Bus { } } #[allow(unused)] + pub fn should_silently_fail(mut self) -> Self { + // this is mostly used for the tests + self.senders.should_silently_fail = true; + self + } + #[allow(unused)] pub fn empty() -> Self { // this is mostly used for the tests Bus { diff --git a/zellij-server/src/unit/fixtures/layout-with-three-panes.kdl b/zellij-server/src/unit/fixtures/layout-with-three-panes.kdl new file mode 100644 index 00000000..ea1f01e7 --- /dev/null +++ b/zellij-server/src/unit/fixtures/layout-with-three-panes.kdl @@ -0,0 +1,5 @@ +layout { + pane + pane + pane +} diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 28aec39c..16b962f1 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -1,30 +1,129 @@ -use super::{CopyOptions, Screen, ScreenInstruction}; +use super::{screen_thread_main, CopyOptions, Screen, ScreenInstruction}; use crate::panes::PaneId; use crate::{ + channels::SenderWithContext, os_input_output::{AsyncReader, Pid, ServerOsApi}, + route::route_action, thread_bus::Bus, - ClientId, + ClientId, ServerInstruction, SessionMetaData, ThreadSenders, }; -use std::convert::TryInto; +use insta::assert_snapshot; use std::path::PathBuf; +use zellij_utils::cli::CliAction; +use zellij_utils::errors::ErrorContext; +use zellij_utils::input::actions::{Action, Direction, ResizeDirection}; use zellij_utils::input::command::TerminalAction; -use zellij_utils::input::layout::LayoutTemplate; +use zellij_utils::input::layout::{PaneLayout, SplitDirection}; +use zellij_utils::input::options::Options; use zellij_utils::ipc::IpcReceiverWithContext; use zellij_utils::pane_size::{Size, SizeInPixels}; +use crate::pty_writer::PtyWriteInstruction; +use std::env::set_var; use std::os::unix::io::RawFd; +use std::sync::{Arc, Mutex}; -use zellij_utils::ipc::{ClientAttributes, PixelDimensions}; +use crate::{pty::PtyInstruction, wasm_vm::PluginInstruction}; +use zellij_utils::ipc::PixelDimensions; use zellij_utils::nix; - use zellij_utils::{ - data::{ModeInfo, Palette}, + channels::{self, ChannelWithContext, Receiver}, + data::{InputMode, ModeInfo, Palette, PluginCapabilities}, interprocess::local_socket::LocalSocketStream, - ipc::{ClientToServerMsg, ServerToClientMsg}, + ipc::{ClientAttributes, ClientToServerMsg, ServerToClientMsg}, }; -#[derive(Clone)] -struct FakeInputOutput {} +use crate::panes::grid::Grid; +use crate::panes::link_handler::LinkHandler; +use crate::panes::sixel::SixelImageStore; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; +use zellij_utils::vte; + +// TODO: deduplicate with identical function in tab_integration_tests +fn take_snapshot_and_cursor_coordinates( + ansi_instructions: &str, + rows: usize, + columns: usize, + palette: Palette, +) -> (Option<(usize, usize)>, String) { + let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); + let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); + let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels { + width: 8, + height: 21, + }))); + let mut grid = Grid::new( + rows, + columns, + Rc::new(RefCell::new(palette)), + terminal_emulator_color_codes, + Rc::new(RefCell::new(LinkHandler::new())), + character_cell_size, + sixel_image_store, + ); + let mut vte_parser = vte::Parser::new(); + for &byte in ansi_instructions.as_bytes() { + vte_parser.advance(&mut grid, byte); + } + (grid.cursor_coordinates(), format!("{:?}", grid)) +} + +fn take_snapshots_and_cursor_coordinates_from_render_events<'a>( + all_events: impl Iterator, + screen_size: Size, +) -> Vec<(Option<(usize, usize)>, String)> { + let snapshots: Vec<(Option<(usize, usize)>, String)> = all_events + .filter_map(|server_instruction| { + match server_instruction { + ServerInstruction::Render(output) => { + if let Some(output) = output { + // note this only takes a snapshot of the first client! + let raw_snapshot = output.get(&1).unwrap(); + let snapshot = take_snapshot_and_cursor_coordinates( + raw_snapshot, + screen_size.rows, + screen_size.cols, + Palette::default(), + ); + Some(snapshot) + } else { + None + } + }, + _ => None, + } + }) + .collect(); + snapshots +} + +fn send_cli_action_to_server( + session_metadata: &SessionMetaData, + cli_action: CliAction, + mock_screen: &mut MockScreen, + client_id: ClientId, +) { + let os_input = Box::new(mock_screen.os_input.clone()); + let to_server = mock_screen.to_server.clone(); + let actions = Action::actions_from_cli(cli_action).unwrap(); + for action in actions { + route_action( + action, + &session_metadata, + &*os_input, + &to_server.clone(), + client_id, + ); + } +} + +#[derive(Clone, Default)] +struct FakeInputOutput { + fake_filesystem: Arc>>, + server_to_client_messages: Arc>>>, +} impl ServerOsApi for FakeInputOutput { fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) { @@ -61,10 +160,16 @@ impl ServerOsApi for FakeInputOutput { } fn send_to_client( &self, - _client_id: ClientId, - _msg: ServerToClientMsg, + client_id: ClientId, + msg: ServerToClientMsg, ) -> Result<(), &'static str> { - unimplemented!() + self.server_to_client_messages + .lock() + .unwrap() + .entry(client_id) + .or_insert_with(Vec::new) + .push(msg); + Ok(()) } fn new_client( &mut self, @@ -82,21 +187,27 @@ impl ServerOsApi for FakeInputOutput { fn get_cwd(&self, _pid: Pid) -> Option { unimplemented!() } - fn write_to_file(&mut self, _: String, _: Option) { - unimplemented!() + fn write_to_file(&mut self, contents: String, filename: Option) { + if let Some(filename) = filename { + self.fake_filesystem + .lock() + .unwrap() + .insert(filename, contents); + } } } fn create_new_screen(size: Size) -> Screen { let mut bus: Bus = Bus::empty(); - let fake_os_input = FakeInputOutput {}; + let fake_os_input = FakeInputOutput::default(); bus.os_input = Some(Box::new(fake_os_input)); let client_attributes = ClientAttributes { size, ..Default::default() }; let max_panes = None; - let mode_info = ModeInfo::default(); + let mut mode_info = ModeInfo::default(); + mode_info.session_name = Some("zellij-test".into()); let draw_pane_frames = false; let session_is_mirrored = true; let copy_options = CopyOptions::default(); @@ -112,14 +223,199 @@ fn create_new_screen(size: Size) -> Screen { ) } +struct MockScreen { + pub main_client_id: u16, + pub pty_receiver: Option>, + pub pty_writer_receiver: Option>, + pub screen_receiver: Option>, + pub server_receiver: Option>, + pub plugin_receiver: Option>, + pub to_screen: SenderWithContext, + pub to_pty: SenderWithContext, + pub to_plugin: SenderWithContext, + pub to_server: SenderWithContext, + pub to_pty_writer: SenderWithContext, + pub os_input: FakeInputOutput, + pub client_attributes: ClientAttributes, + pub config_options: Options, + pub session_metadata: SessionMetaData, +} + +impl MockScreen { + pub fn run(&mut self, initial_layout: Option) -> std::thread::JoinHandle<()> { + let config_options = self.config_options.clone(); + let client_attributes = self.client_attributes.clone(); + let screen_bus = Bus::new( + vec![self.screen_receiver.take().unwrap()], + None, + Some(&self.to_pty.clone()), + Some(&self.to_plugin.clone()), + Some(&self.to_server.clone()), + Some(&self.to_pty_writer.clone()), + Some(Box::new(self.os_input.clone())), + ) + .should_silently_fail(); + let screen_thread = std::thread::Builder::new() + .name("screen_thread".to_string()) + .spawn(move || { + set_var("ZELLIJ_SESSION_NAME", "zellij-test"); + screen_thread_main( + screen_bus, + None, + client_attributes, + Box::new(config_options), + ) + .expect("TEST") + }) + .unwrap(); + let pane_layout = initial_layout.unwrap_or_default(); + let pane_count = pane_layout.extract_run_instructions().len(); + let mut pane_ids = vec![]; + for i in 0..pane_count { + pane_ids.push(i as i32); + } + let _ = self.to_screen.send(ScreenInstruction::NewTab( + pane_layout, + pane_ids, + self.main_client_id, + )); + screen_thread + } + pub fn new_tab(&mut self, tab_layout: PaneLayout) { + let pane_count = tab_layout.extract_run_instructions().len(); + let mut pane_ids = vec![]; + for i in 0..pane_count { + pane_ids.push(i as i32); + } + let _ = self.to_screen.send(ScreenInstruction::NewTab( + tab_layout, + pane_ids, + self.main_client_id, + )); + } + pub fn teardown(&mut self, threads: Vec>) { + let _ = self.to_pty.send(PtyInstruction::Exit); + let _ = self.to_pty_writer.send(PtyWriteInstruction::Exit); + let _ = self.to_screen.send(ScreenInstruction::Exit); + let _ = self.to_server.send(ServerInstruction::KillSession); + let _ = self.to_plugin.send(PluginInstruction::Exit); + for thread in threads { + let _ = thread.join(); + } + } + pub fn clone_session_metadata(&self) -> SessionMetaData { + // hack that only clones the clonable parts of SessionMetaData + SessionMetaData { + senders: self.session_metadata.senders.clone(), + capabilities: self.session_metadata.capabilities.clone(), + client_attributes: self.session_metadata.client_attributes.clone(), + default_shell: self.session_metadata.default_shell.clone(), + screen_thread: None, + pty_thread: None, + wasm_thread: None, + pty_writer_thread: None, + } + } +} + +impl MockScreen { + pub fn new(size: Size) -> Self { + let (to_server, server_receiver): ChannelWithContext = + channels::bounded(50); + let to_server = SenderWithContext::new(to_server); + + let (to_screen, screen_receiver): ChannelWithContext = + channels::unbounded(); + let to_screen = SenderWithContext::new(to_screen); + + let (to_plugin, plugin_receiver): ChannelWithContext = + channels::unbounded(); + let to_plugin = SenderWithContext::new(to_plugin); + let (to_pty, pty_receiver): ChannelWithContext = channels::unbounded(); + let to_pty = SenderWithContext::new(to_pty); + + let (to_pty_writer, pty_writer_receiver): ChannelWithContext = + channels::unbounded(); + let to_pty_writer = SenderWithContext::new(to_pty_writer); + + let client_attributes = ClientAttributes { + size, + ..Default::default() + }; + let capabilities = PluginCapabilities { + arrow_fonts: Default::default(), + }; + + let session_metadata = SessionMetaData { + senders: ThreadSenders { + to_screen: Some(to_screen.clone()), + to_pty: Some(to_pty.clone()), + to_plugin: Some(to_plugin.clone()), + to_pty_writer: Some(to_pty_writer.clone()), + to_server: Some(to_server.clone()), + should_silently_fail: true, + }, + capabilities, + default_shell: None, + client_attributes: client_attributes.clone(), + screen_thread: None, + pty_thread: None, + wasm_thread: None, + pty_writer_thread: None, + }; + + let os_input = FakeInputOutput::default(); + let config_options = Options::default(); + let main_client_id = 1; + MockScreen { + main_client_id, + pty_receiver: Some(pty_receiver), + pty_writer_receiver: Some(pty_writer_receiver), + screen_receiver: Some(screen_receiver), + server_receiver: Some(server_receiver), + plugin_receiver: Some(plugin_receiver), + to_screen, + to_pty, + to_plugin, + to_server, + to_pty_writer, + os_input, + client_attributes, + config_options, + session_metadata, + } + } +} + +macro_rules! log_actions_in_thread { + ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr ) => { + std::thread::Builder::new() + .name("pty_writer_thread".to_string()) + .spawn({ + let log = $arc_mutex_log.clone(); + move || loop { + let (event, _err_ctx) = $receiver + .recv() + .expect("failed to receive event on channel"); + match event { + $exit_event => { + log.lock().unwrap().push(event); + break; + }, + _ => { + log.lock().unwrap().push(event); + }, + } + } + }) + .unwrap() + }; +} + fn new_tab(screen: &mut Screen, pid: i32) { let client_id = 1; screen - .new_tab( - LayoutTemplate::default().try_into().unwrap(), - vec![pid], - client_id, - ) + .new_tab(PaneLayout::default(), vec![pid], client_id) .expect("TEST"); } @@ -572,3 +868,1616 @@ fn attach_after_first_tab_closed() { screen.remove_client(1).expect("TEST"); screen.add_client(1).expect("TEST"); } + +// Following are tests for sending CLI actions +// these tests are only partially relevant to Screen +// and are included here for two reasons: +// 1. The best way to "integration test" these is combining the "screen_thread_main" and +// "route_action" functions and mocking everything around them +// 2. These inadvertently also test many parts of Screen that are not tested elsewhere + +#[test] +pub fn send_cli_write_chars_action_to_screen() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_writer_receiver = mock_screen.pty_writer_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(None); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_writer_thread = log_actions_in_thread!( + received_pty_instructions, + PtyWriteInstruction::Exit, + pty_writer_receiver + ); + let cli_action = CliAction::WriteChars { + chars: "input from the cli".into(), + }; + send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_writer_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_write_action_to_screen() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_writer_receiver = mock_screen.pty_writer_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(None); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_writer_thread = log_actions_in_thread!( + received_pty_instructions, + PtyWriteInstruction::Exit, + pty_writer_receiver + ); + let cli_action = CliAction::Write { + bytes: vec![102, 111, 111], + }; + send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_writer_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_resize_action_to_screen() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let pty_writer_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let resize_cli_action = CliAction::Resize { + resize_direction: ResizeDirection::Left, + }; + send_cli_action_to_server( + &session_metadata, + resize_cli_action, + &mut mock_screen, + client_id, + ); + mock_screen.teardown(vec![pty_writer_thread, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_focus_next_pane_action() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let focus_next_pane_action = CliAction::FocusNextPane; + send_cli_action_to_server( + &session_metadata, + focus_next_pane_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (cursor_coordinates, _snapshot) in snapshots { + // here we assert he cursor_coordinates to let us know if we switched the pane focus + assert_snapshot!(format!("{:?}", cursor_coordinates)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_focus_previous_pane_action() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let focus_next_pane_action = CliAction::FocusPreviousPane; + send_cli_action_to_server( + &session_metadata, + focus_next_pane_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (cursor_coordinates, _snapshot) in snapshots { + // here we assert he cursor_coordinates to let us know if we switched the pane focus + assert_snapshot!(format!("{:?}", cursor_coordinates)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_move_focus_pane_action() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let move_focus_action = CliAction::MoveFocus { + direction: Direction::Right, + }; + send_cli_action_to_server( + &session_metadata, + move_focus_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (cursor_coordinates, _snapshot) in snapshots { + // here we assert he cursor_coordinates to let us know if we switched the pane focus + assert_snapshot!(format!("{:?}", cursor_coordinates)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_move_focus_or_tab_pane_action() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let move_focus_action = CliAction::MoveFocusOrTab { + direction: Direction::Right, + }; + send_cli_action_to_server( + &session_metadata, + move_focus_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (cursor_coordinates, _snapshot) in snapshots { + // here we assert he cursor_coordinates to let us know if we switched the pane focus + assert_snapshot!(format!("{:?}", cursor_coordinates)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_move_pane_action() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let cli_action = CliAction::MovePane { + direction: Direction::Right, + }; + send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_dump_screen_action() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let cli_action = CliAction::DumpScreen { + path: PathBuf::from("/tmp/foo"), + }; + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + "fill pane up with something".as_bytes().to_vec(), + )); + send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_thread, screen_thread]); + assert_snapshot!(format!( + "{:?}", + *mock_screen.os_input.fake_filesystem.lock().unwrap() + )); +} + +#[test] +pub fn send_cli_edit_scrollback_action() { + let size = Size { cols: 80, rows: 20 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let cli_action = CliAction::EditScrollback; + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + "fill pane up with something".as_bytes().to_vec(), + )); + send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![pty_thread, screen_thread]); + let dumped_file_name = mock_screen + .os_input + .fake_filesystem + .lock() + .unwrap() + .keys() + .next() + .unwrap() + .clone(); + let mut found_instruction = false; + for instruction in received_pty_instructions.lock().unwrap().iter() { + if let PtyInstruction::OpenInPlaceEditor(scrollback_contents_file, terminal_id, client_id) = + instruction + { + assert_eq!(scrollback_contents_file, &PathBuf::from(&dumped_file_name)); + assert_eq!(terminal_id, &Some(1)); + assert_eq!(client_id, &1); + found_instruction = true; + } + } + assert!(found_instruction); +} + +#[test] +pub fn send_cli_scroll_up_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let cli_action = CliAction::ScrollUp; + let mut pane_contents = String::new(); + for i in 0..20 { + pane_contents.push_str(&format!("fill pane up with something {}\n\r", i)); + } + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + pane_contents.as_bytes().to_vec(), + )); + std::thread::sleep(std::time::Duration::from_millis(100)); + // we send two actions here because only the last line in the pane is empty, so one action + // won't show in a render + send_cli_action_to_server( + &session_metadata, + cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + cli_action.clone(), + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_scroll_down_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let scroll_up_cli_action = CliAction::ScrollUp; + let scroll_down_cli_action = CliAction::ScrollDown; + let mut pane_contents = String::new(); + for i in 0..20 { + pane_contents.push_str(&format!("fill pane up with something {}\n\r", i)); + } + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + pane_contents.as_bytes().to_vec(), + )); + std::thread::sleep(std::time::Duration::from_millis(100)); + // scroll up some + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + + // scroll down some + send_cli_action_to_server( + &session_metadata, + scroll_down_cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + scroll_down_cli_action.clone(), + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_scroll_to_bottom_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let scroll_up_cli_action = CliAction::ScrollUp; + let scroll_to_bottom_action = CliAction::ScrollToBottom; + let mut pane_contents = String::new(); + for i in 0..20 { + pane_contents.push_str(&format!("fill pane up with something {}\n\r", i)); + } + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + pane_contents.as_bytes().to_vec(), + )); + std::thread::sleep(std::time::Duration::from_millis(100)); + // scroll up some + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + scroll_up_cli_action.clone(), + &mut mock_screen, + client_id, + ); + + // scroll to bottom + send_cli_action_to_server( + &session_metadata, + scroll_to_bottom_action.clone(), + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_page_scroll_up_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let page_scroll_up_action = CliAction::PageScrollUp; + let mut pane_contents = String::new(); + for i in 0..20 { + pane_contents.push_str(&format!("fill pane up with something {}\n\r", i)); + } + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + pane_contents.as_bytes().to_vec(), + )); + std::thread::sleep(std::time::Duration::from_millis(100)); + send_cli_action_to_server( + &session_metadata, + page_scroll_up_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_page_scroll_down_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let page_scroll_up_action = CliAction::PageScrollUp; + let page_scroll_down_action = CliAction::PageScrollDown; + let mut pane_contents = String::new(); + for i in 0..20 { + pane_contents.push_str(&format!("fill pane up with something {}\n\r", i)); + } + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + pane_contents.as_bytes().to_vec(), + )); + std::thread::sleep(std::time::Duration::from_millis(100)); + + // scroll up some + send_cli_action_to_server( + &session_metadata, + page_scroll_up_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + page_scroll_up_action.clone(), + &mut mock_screen, + client_id, + ); + + // scroll down + send_cli_action_to_server( + &session_metadata, + page_scroll_down_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_half_page_scroll_up_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let half_page_scroll_up_action = CliAction::HalfPageScrollUp; + let mut pane_contents = String::new(); + for i in 0..20 { + pane_contents.push_str(&format!("fill pane up with something {}\n\r", i)); + } + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + pane_contents.as_bytes().to_vec(), + )); + std::thread::sleep(std::time::Duration::from_millis(100)); + send_cli_action_to_server( + &session_metadata, + half_page_scroll_up_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_half_page_scroll_down_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let half_page_scroll_up_action = CliAction::HalfPageScrollUp; + let half_page_scroll_down_action = CliAction::HalfPageScrollDown; + let mut pane_contents = String::new(); + for i in 0..20 { + pane_contents.push_str(&format!("fill pane up with something {}\n\r", i)); + } + let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes( + 0, + pane_contents.as_bytes().to_vec(), + )); + std::thread::sleep(std::time::Duration::from_millis(100)); + + // scroll up some + send_cli_action_to_server( + &session_metadata, + half_page_scroll_up_action.clone(), + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + half_page_scroll_up_action.clone(), + &mut mock_screen, + client_id, + ); + + // scroll down + send_cli_action_to_server( + &session_metadata, + half_page_scroll_down_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_toggle_full_screen_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let toggle_full_screen_action = CliAction::ToggleFullscreen; + send_cli_action_to_server( + &session_metadata, + toggle_full_screen_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_toggle_pane_frames_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let toggle_pane_frames_action = CliAction::TogglePaneFrames; + send_cli_action_to_server( + &session_metadata, + toggle_pane_frames_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_toggle_active_tab_sync_action() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_writer_receiver = mock_screen.pty_writer_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_writer_thread = log_actions_in_thread!( + received_pty_instructions, + PtyWriteInstruction::Exit, + pty_writer_receiver + ); + let cli_toggle_active_tab_sync_action = CliAction::ToggleActiveSyncTab; + let cli_write_action = CliAction::Write { + bytes: vec![102, 111, 111], + }; + send_cli_action_to_server( + &session_metadata, + cli_toggle_active_tab_sync_action, + &mut mock_screen, + client_id, + ); + send_cli_action_to_server( + &session_metadata, + cli_write_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_writer_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_new_pane_action_with_default_parameters() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let cli_new_pane_action = CliAction::NewPane { + direction: None, + command: None, + cwd: None, + floating: None, + }; + send_cli_action_to_server( + &session_metadata, + cli_new_pane_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_new_pane_action_with_split_direction() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let cli_new_pane_action = CliAction::NewPane { + direction: Some(Direction::Right), + command: None, + cwd: None, + floating: None, + }; + send_cli_action_to_server( + &session_metadata, + cli_new_pane_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_new_pane_action_with_command_and_cwd() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let cli_new_pane_action = CliAction::NewPane { + direction: Some(Direction::Right), + command: Some("htop".into()), + cwd: Some("/some/folder".into()), + floating: None, + }; + send_cli_action_to_server( + &session_metadata, + cli_new_pane_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_edit_action_with_default_parameters() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let cli_edit_action = CliAction::Edit { + file: PathBuf::from("/file/to/edit"), + direction: None, + line_number: None, + floating: None, + }; + send_cli_action_to_server( + &session_metadata, + cli_edit_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_edit_action_with_line_number() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let cli_edit_action = CliAction::Edit { + file: PathBuf::from("/file/to/edit"), + direction: None, + line_number: Some(100), + floating: None, + }; + send_cli_action_to_server( + &session_metadata, + cli_edit_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_edit_action_with_split_direction() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let cli_edit_action = CliAction::Edit { + file: PathBuf::from("/file/to/edit"), + direction: Some(Direction::Down), + line_number: None, + floating: None, + }; + send_cli_action_to_server( + &session_metadata, + cli_edit_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![pty_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_switch_mode_action() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let screen_thread = mock_screen.run(Some(initial_layout)); + let cli_switch_mode = CliAction::SwitchMode { + input_mode: InputMode::Locked, + }; + send_cli_action_to_server( + &session_metadata, + cli_switch_mode, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![screen_thread]); + assert_snapshot!(format!( + "{:?}", + *mock_screen + .os_input + .server_to_client_messages + .lock() + .unwrap() + )); +} + +#[test] +pub fn send_cli_toggle_pane_embed_or_float() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating; + // first time to float + send_cli_action_to_server( + &session_metadata, + toggle_pane_embed_or_floating.clone(), + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + // second time to embed + send_cli_action_to_server( + &session_metadata, + toggle_pane_embed_or_floating.clone(), + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_toggle_floating_panes() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating; + let toggle_floating_panes = CliAction::ToggleFloatingPanes; + // float the focused pane + send_cli_action_to_server( + &session_metadata, + toggle_pane_embed_or_floating, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + // toggle floating panes (will hide the floated pane from the previous action) + send_cli_action_to_server( + &session_metadata, + toggle_floating_panes.clone(), + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + // toggle floating panes (will show the floated pane) + send_cli_action_to_server( + &session_metadata, + toggle_floating_panes.clone(), + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_close_pane_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let close_pane_action = CliAction::ClosePane; + send_cli_action_to_server( + &session_metadata, + close_pane_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_new_tab_action_default_params() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let new_tab_action = CliAction::NewTab { + name: None, + layout: None, + }; + send_cli_action_to_server( + &session_metadata, + new_tab_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![pty_thread, screen_thread]); + assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); +} + +#[test] +pub fn send_cli_new_tab_action_with_name_and_layout() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_pty_instructions = Arc::new(Mutex::new(vec![])); + let pty_receiver = mock_screen.pty_receiver.take().unwrap(); + let pty_thread = log_actions_in_thread!( + received_pty_instructions, + PtyInstruction::Exit, + pty_receiver + ); + let new_tab_action = CliAction::NewTab { + name: Some("my-awesome-tab-name".into()), + layout: Some(PathBuf::from(format!( + "{}/src/unit/fixtures/layout-with-three-panes.kdl", + env!("CARGO_MANIFEST_DIR") + ))), + }; + send_cli_action_to_server( + &session_metadata, + new_tab_action, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![pty_thread, screen_thread]); + let new_tab_instruction = received_pty_instructions + .lock() + .unwrap() + .iter() + .find(|i| { + if let PtyInstruction::NewTab(..) = i { + return true; + } else { + return false; + } + }) + .unwrap() + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_instruction)); +} + +#[test] +pub fn send_cli_next_tab_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut second_tab_layout = PaneLayout::default(); + second_tab_layout.children_split_direction = SplitDirection::Horizontal; + second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + mock_screen.new_tab(second_tab_layout); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let goto_next_tab = CliAction::GoToNextTab; + send_cli_action_to_server( + &session_metadata, + goto_next_tab, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_thread, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_previous_tab_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut second_tab_layout = PaneLayout::default(); + second_tab_layout.children_split_direction = SplitDirection::Horizontal; + second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + mock_screen.new_tab(second_tab_layout); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let goto_previous_tab = CliAction::GoToPreviousTab; + send_cli_action_to_server( + &session_metadata, + goto_previous_tab, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_thread, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_goto_tab_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut second_tab_layout = PaneLayout::default(); + second_tab_layout.children_split_direction = SplitDirection::Horizontal; + second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + mock_screen.new_tab(second_tab_layout); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let goto_tab = CliAction::GoToTab { index: 1 }; + send_cli_action_to_server(&session_metadata, goto_tab, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_thread, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_close_tab_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut second_tab_layout = PaneLayout::default(); + second_tab_layout.children_split_direction = SplitDirection::Horizontal; + second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + mock_screen.new_tab(second_tab_layout); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let close_tab = CliAction::CloseTab; + send_cli_action_to_server(&session_metadata, close_tab, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_thread, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} + +#[test] +pub fn send_cli_rename_tab() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut second_tab_layout = PaneLayout::default(); + second_tab_layout.children_split_direction = SplitDirection::Horizontal; + second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + mock_screen.new_tab(second_tab_layout); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_plugin_instructions = Arc::new(Mutex::new(vec![])); + let plugin_receiver = mock_screen.plugin_receiver.take().unwrap(); + let plugin_thread = log_actions_in_thread!( + received_plugin_instructions, + PluginInstruction::Exit, + plugin_receiver + ); + let rename_tab = CliAction::RenameTab { + name: "new-tab-name".into(), + }; + send_cli_action_to_server(&session_metadata, rename_tab, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![plugin_thread, screen_thread]); + assert_snapshot!(format!( + "{:#?}", + *received_plugin_instructions.lock().unwrap() + )) +} + +#[test] +pub fn send_cli_undo_rename_tab() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = PaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut second_tab_layout = PaneLayout::default(); + second_tab_layout.children_split_direction = SplitDirection::Horizontal; + second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + mock_screen.new_tab(second_tab_layout); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout)); + let received_plugin_instructions = Arc::new(Mutex::new(vec![])); + let plugin_receiver = mock_screen.plugin_receiver.take().unwrap(); + let plugin_thread = log_actions_in_thread!( + received_plugin_instructions, + PluginInstruction::Exit, + plugin_receiver + ); + let rename_tab = CliAction::RenameTab { + name: "new-tab-name".into(), + }; + let undo_rename_tab = CliAction::UndoRenameTab; + // first rename the tab + send_cli_action_to_server(&session_metadata, rename_tab, &mut mock_screen, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + // then undo the tab rename to go back to the default name + send_cli_action_to_server( + &session_metadata, + undo_rename_tab, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![plugin_thread, screen_thread]); + assert_snapshot!(format!( + "{:#?}", + *received_plugin_instructions.lock().unwrap() + )) +} diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-2.snap new file mode 100644 index 00000000..2df4565e --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1805 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-3.snap new file mode 100644 index 00000000..c8e5e9a9 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1805 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): │ │ +05 (C): │ │ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-4.snap new file mode 100644 index 00000000..163f7b35 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1850 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action.snap new file mode 100644 index 00000000..6c5fd6ab --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_pane_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1805 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-2.snap new file mode 100644 index 00000000..eea7656b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2118 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-3.snap new file mode 100644 index 00000000..b4240eb0 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2118 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-4.snap new file mode 100644 index 00000000..eea7656b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2118 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-5.snap new file mode 100644 index 00000000..d4fce111 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2118 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-6.snap new file mode 100644 index 00000000..eea7656b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-6.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2118 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-7.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-7.snap new file mode 100644 index 00000000..f6af649c --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action-7.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2120 +expression: "format!(\"{}\", snapshot_count)" +--- +6 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action.snap new file mode 100644 index 00000000..d4fce111 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_close_tab_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2118 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_dump_screen_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_dump_screen_action.snap new file mode 100644 index 00000000..6eb6814d --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_dump_screen_action.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1074 +expression: "format!(\"{:?}\", * mock_screen.os_input.fake_filesystem.lock().unwrap())" +--- +{"/tmp/foo": "fill pane up with something"} diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap new file mode 100644 index 00000000..776d37ff --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1618 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[SpawnTerminal(Some(OpenFile("/file/to/edit", None)), ClientId(10)), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap new file mode 100644 index 00000000..9d4ecb19 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1650 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[SpawnTerminal(Some(OpenFile("/file/to/edit", Some(100))), ClientId(10)), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap new file mode 100644 index 00000000..1d793cf6 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1682 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[SpawnTerminalHorizontally(Some(OpenFile("/file/to/edit", None)), 10), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-2.snap new file mode 100644 index 00000000..74460796 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-2.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 939 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-3.snap new file mode 100644 index 00000000..f0d453eb --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-3.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 939 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((41, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-4.snap new file mode 100644 index 00000000..ae95b51b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 937 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action.snap new file mode 100644 index 00000000..74460796 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_next_pane_action.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 939 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-2.snap new file mode 100644 index 00000000..c8861240 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-2.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 968 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-3.snap new file mode 100644 index 00000000..89f17aa7 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-3.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 968 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((41, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-4.snap new file mode 100644 index 00000000..1189125a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 970 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action.snap new file mode 100644 index 00000000..c8861240 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_focus_previous_pane_action.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 968 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_go_to_next_and_previous_search_occurrence.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_go_to_next_and_previous_search_occurrence.snap new file mode 100644 index 00000000..53beab4a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_go_to_next_and_previous_search_occurrence.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2674 +expression: "format!(\"{:?}\", * received_server_instructions.lock().unwrap())" +--- +[Render(Some({1: "\u{1b}[?25l\u{1b}[2J\u{1b}[1;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐\u{1b}[2;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[2;80H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;80H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;80H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────────────────────────────────────────────┘\u{1b}[2;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[3;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[4;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[6;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐\u{1b}[7;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[10;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────────────────────────────────────────────┘\u{1b}[7;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[8;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[9;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[6;1H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), UnblockInputThread, Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), Render(Some({1: "\u{1b}[?25l\u{1b}[2J\u{1b}[1;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #1 ─────────────────────────────┐\u{1b}[2;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[2;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[10;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────┘\u{1b}[2;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[3;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[4;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[5;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[6;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[7;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[8;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[9;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[1;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #2 ─────────────────────────────┐\u{1b}[2;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[2;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[10;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────┘\u{1b}[2;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[3;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[4;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[5;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[6;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[7;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[8;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[9;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[1;41H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), UnblockInputThread, Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), UnblockInputThread, Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), KillSession] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-2.snap new file mode 100644 index 00000000..6eb10760 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2037 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-3.snap new file mode 100644 index 00000000..a2f36767 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2037 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-4.snap new file mode 100644 index 00000000..6eb10760 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2037 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-5.snap new file mode 100644 index 00000000..1688290e --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2037 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-6.snap new file mode 100644 index 00000000..6eb10760 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-6.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2037 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-7.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-7.snap new file mode 100644 index 00000000..e8b27b15 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action-7.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2040 +expression: "format!(\"{}\", snapshot_count)" +--- +6 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action.snap new file mode 100644 index 00000000..1688290e --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_goto_tab_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2037 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-2.snap new file mode 100644 index 00000000..0f0a9e25 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1397 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-3.snap new file mode 100644 index 00000000..884173f4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1397 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 4/13 ┐ +01 (C): │fill pane up with something 9 │ +02 (C): │fill pane up with something 10 │ +03 (C): │fill pane up with something 11 │ +04 (C): │fill pane up with something 12 │ +05 (C): │fill pane up with something 13 │ +06 (C): │fill pane up with something 14 │ +07 (C): │fill pane up with something 15 │ +08 (C): │fill pane up with something 16 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-4.snap new file mode 100644 index 00000000..8118d806 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1397 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 8/13 ┐ +01 (C): │fill pane up with something 5 │ +02 (C): │fill pane up with something 6 │ +03 (C): │fill pane up with something 7 │ +04 (C): │fill pane up with something 8 │ +05 (C): │fill pane up with something 9 │ +06 (C): │fill pane up with something 10 │ +07 (C): │fill pane up with something 11 │ +08 (C): │fill pane up with something 12 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-5.snap new file mode 100644 index 00000000..884173f4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1397 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 4/13 ┐ +01 (C): │fill pane up with something 9 │ +02 (C): │fill pane up with something 10 │ +03 (C): │fill pane up with something 11 │ +04 (C): │fill pane up with something 12 │ +05 (C): │fill pane up with something 13 │ +06 (C): │fill pane up with something 14 │ +07 (C): │fill pane up with something 15 │ +08 (C): │fill pane up with something 16 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-6.snap new file mode 100644 index 00000000..63ab9f8d --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action-6.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1434 +expression: "format!(\"{}\", snapshot_count)" +--- +5 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action.snap new file mode 100644 index 00000000..d03e1da4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_down_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1397 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-2.snap new file mode 100644 index 00000000..4fdd411b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1354 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-3.snap new file mode 100644 index 00000000..f0b88e27 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1354 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 4/13 ┐ +01 (C): │fill pane up with something 9 │ +02 (C): │fill pane up with something 10 │ +03 (C): │fill pane up with something 11 │ +04 (C): │fill pane up with something 12 │ +05 (C): │fill pane up with something 13 │ +06 (C): │fill pane up with something 14 │ +07 (C): │fill pane up with something 15 │ +08 (C): │fill pane up with something 16 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-4.snap new file mode 100644 index 00000000..8bc6c44b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1389 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action.snap new file mode 100644 index 00000000..d38454b4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_half_page_scroll_up_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1354 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-2.snap new file mode 100644 index 00000000..7a6fd48a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-2.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1030 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-3.snap new file mode 100644 index 00000000..400b84d7 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-3.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1030 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((41, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-4.snap new file mode 100644 index 00000000..97cb88db --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1036 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action.snap new file mode 100644 index 00000000..7a6fd48a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_or_tab_pane_action.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1030 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-2.snap new file mode 100644 index 00000000..208d683f --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-2.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 999 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-3.snap new file mode 100644 index 00000000..407ab4bb --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-3.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 999 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((41, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-4.snap new file mode 100644 index 00000000..eacdaba2 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1003 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action.snap new file mode 100644 index 00000000..208d683f --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_focus_pane_action.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 999 +expression: "format!(\"{:?}\", cursor_coordinates)" +--- +Some((1, 1)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-2.snap new file mode 100644 index 00000000..14158fbd --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-2.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1060 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): +10 (C): +11 (C): +12 (C): +13 (C): +14 (C): +15 (C): +16 (C): +17 (C): +18 (C): +19 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-3.snap new file mode 100644 index 00000000..d4fc90dd --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-3.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1060 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #2 ─────────────────────────────┐┌ Pane #1 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): │ ││ │ +10 (C): │ ││ │ +11 (C): │ ││ │ +12 (C): │ ││ │ +13 (C): │ ││ │ +14 (C): │ ││ │ +15 (C): │ ││ │ +16 (C): │ ││ │ +17 (C): │ ││ │ +18 (C): │ ││ │ +19 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-4.snap new file mode 100644 index 00000000..4c454d89 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1068 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action.snap new file mode 100644 index 00000000..1c054e3a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_move_pane_action.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1061 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): │ ││ │ +10 (C): │ ││ │ +11 (C): │ ││ │ +12 (C): │ ││ │ +13 (C): │ ││ │ +14 (C): │ ││ │ +15 (C): │ ││ │ +16 (C): │ ││ │ +17 (C): │ ││ │ +18 (C): │ ││ │ +19 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap new file mode 100644 index 00000000..38b18ce7 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1889 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[SpawnTerminalVertically(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder") })), 10), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_cwd_and_args.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_cwd_and_args.snap new file mode 100644 index 00000000..29b09a8b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_cwd_and_args.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1632 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[SpawnTerminalVertically(Some(RunCommand(RunCommand { command: "htop", args: ["-h", "--something", "arg"], cwd: Some("/some/folder") })), 10), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap new file mode 100644 index 00000000..eedc6c50 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1566 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[SpawnTerminal(None, ClientId(10)), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap new file mode 100644 index 00000000..de7a2465 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1599 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[SpawnTerminalVertically(None, 10), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap new file mode 100644 index 00000000..53a02426 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1898 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[NewTab(None, None, None, 10), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap new file mode 100644 index 00000000..5f676ab7 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap @@ -0,0 +1,55 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1989 +expression: "format!(\"{:#?}\", new_tab_instruction)" +--- +NewTab( + None, + Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + Some( + "my-awesome-tab-name", + ), + 10, +) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-2.snap new file mode 100644 index 00000000..f44abd51 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1969 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-3.snap new file mode 100644 index 00000000..6c8d7629 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1969 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-4.snap new file mode 100644 index 00000000..f44abd51 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1969 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-5.snap new file mode 100644 index 00000000..fdac85da --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1969 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-6.snap new file mode 100644 index 00000000..f44abd51 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-6.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1969 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-7.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-7.snap new file mode 100644 index 00000000..8e7e4eae --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action-7.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2012 +expression: "format!(\"{}\", snapshot_count)" +--- +6 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action.snap new file mode 100644 index 00000000..fdac85da --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_next_tab_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1969 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-2.snap new file mode 100644 index 00000000..dd4795d3 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1318 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-3.snap new file mode 100644 index 00000000..38ae6619 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1318 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 9/13 ┐ +01 (C): │fill pane up with something 4 │ +02 (C): │fill pane up with something 5 │ +03 (C): │fill pane up with something 6 │ +04 (C): │fill pane up with something 7 │ +05 (C): │fill pane up with something 8 │ +06 (C): │fill pane up with something 9 │ +07 (C): │fill pane up with something 10 │ +08 (C): │fill pane up with something 11 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-4.snap new file mode 100644 index 00000000..73c58989 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1318 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ───────────── SCROLL: 13/13 ┐ +01 (C): │fill pane up with something 0 │ +02 (C): │fill pane up with something 1 │ +03 (C): │fill pane up with something 2 │ +04 (C): │fill pane up with something 3 │ +05 (C): │fill pane up with something 4 │ +06 (C): │fill pane up with something 5 │ +07 (C): │fill pane up with something 6 │ +08 (C): │fill pane up with something 7 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-5.snap new file mode 100644 index 00000000..5de916b8 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1318 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 5/13 ┐ +01 (C): │fill pane up with something 8 │ +02 (C): │fill pane up with something 9 │ +03 (C): │fill pane up with something 10 │ +04 (C): │fill pane up with something 11 │ +05 (C): │fill pane up with something 12 │ +06 (C): │fill pane up with something 13 │ +07 (C): │fill pane up with something 14 │ +08 (C): │fill pane up with something 15 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-6.snap new file mode 100644 index 00000000..fc4136a6 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action-6.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1351 +expression: "format!(\"{}\", snapshot_count)" +--- +5 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action.snap new file mode 100644 index 00000000..19f6d030 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_down_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1318 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-2.snap new file mode 100644 index 00000000..15f71daf --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1275 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-3.snap new file mode 100644 index 00000000..481e5b23 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1275 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 9/13 ┐ +01 (C): │fill pane up with something 4 │ +02 (C): │fill pane up with something 5 │ +03 (C): │fill pane up with something 6 │ +04 (C): │fill pane up with something 7 │ +05 (C): │fill pane up with something 8 │ +06 (C): │fill pane up with something 9 │ +07 (C): │fill pane up with something 10 │ +08 (C): │fill pane up with something 11 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-4.snap new file mode 100644 index 00000000..328d4b3a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1306 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action.snap new file mode 100644 index 00000000..a59f6869 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_page_scroll_up_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1275 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-2.snap new file mode 100644 index 00000000..412016df --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2003 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-3.snap new file mode 100644 index 00000000..e2ff3ec6 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2003 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-4.snap new file mode 100644 index 00000000..412016df --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2003 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-5.snap new file mode 100644 index 00000000..b0d42634 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2003 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-6.snap new file mode 100644 index 00000000..412016df --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-6.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2003 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-7.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-7.snap new file mode 100644 index 00000000..648f833d --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action-7.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2048 +expression: "format!(\"{}\", snapshot_count)" +--- +6 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action.snap new file mode 100644 index 00000000..b0d42634 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_previous_tab_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2003 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): └──────────────────────────────────────────────────────────────────────────────┘ +05 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-2.snap new file mode 100644 index 00000000..91d02a51 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1835 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-3.snap new file mode 100644 index 00000000..da90407d --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1835 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ my_new_pane_title ───────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): │ │ +05 (C): │ │ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-4.snap new file mode 100644 index 00000000..42794790 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1882 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action.snap new file mode 100644 index 00000000..24b8735a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_pane_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1835 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap new file mode 100644 index 00000000..40b651ae --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap @@ -0,0 +1,436 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2528 +expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())" +--- +[ + Update( + None, + Some( + 10, + ), + InputReceived, + ), + Update( + None, + Some( + 10, + ), + InputReceived, + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: false, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + TabInfo { + position: 1, + name: "Tab #2", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: false, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + TabInfo { + position: 1, + name: "", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: false, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + TabInfo { + position: 1, + name: "new-tab-name", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Exit, +] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen-2.snap new file mode 100644 index 00000000..da2e2a7b --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen-2.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 924 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): +10 (C): +11 (C): +12 (C): +13 (C): +14 (C): +15 (C): +16 (C): +17 (C): +18 (C): +19 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen-3.snap new file mode 100644 index 00000000..4325fbb4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen-3.snap @@ -0,0 +1,26 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 924 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────┐┌ Pane #2 ─────────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): │ ││ │ +10 (C): │ ││ │ +11 (C): │ ││ │ +12 (C): │ ││ │ +13 (C): │ ││ │ +14 (C): │ ││ │ +15 (C): │ ││ │ +16 (C): │ ││ │ +17 (C): │ ││ │ +18 (C): │ ││ │ +19 (C): └──────────────────────────────────┘└──────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen.snap new file mode 100644 index 00000000..3b34c47d --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_resize_action_to_screen.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 904 +expression: "format!(\"{}\", snapshot_count)" +--- +0 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-2.snap new file mode 100644 index 00000000..4d0118e1 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-3.snap new file mode 100644 index 00000000..ce17e618 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 1/13 ┐ +01 (C): │fill pane up with something 12 │ +02 (C): │fill pane up with something 13 │ +03 (C): │fill pane up with something 14 │ +04 (C): │fill pane up with something 15 │ +05 (C): │fill pane up with something 16 │ +06 (C): │fill pane up with something 17 │ +07 (C): │fill pane up with something 18 │ +08 (C): │fill pane up with something 19 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-4.snap new file mode 100644 index 00000000..eea8c7f4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 2/13 ┐ +01 (C): │fill pane up with something 11 │ +02 (C): │fill pane up with something 12 │ +03 (C): │fill pane up with something 13 │ +04 (C): │fill pane up with something 14 │ +05 (C): │fill pane up with something 15 │ +06 (C): │fill pane up with something 16 │ +07 (C): │fill pane up with something 17 │ +08 (C): │fill pane up with something 18 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-5.snap new file mode 100644 index 00000000..e2c021ed --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 3/13 ┐ +01 (C): │fill pane up with something 10 │ +02 (C): │fill pane up with something 11 │ +03 (C): │fill pane up with something 12 │ +04 (C): │fill pane up with something 13 │ +05 (C): │fill pane up with something 14 │ +06 (C): │fill pane up with something 15 │ +07 (C): │fill pane up with something 16 │ +08 (C): │fill pane up with something 17 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-6.snap new file mode 100644 index 00000000..9765846d --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-6.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 4/13 ┐ +01 (C): │fill pane up with something 9 │ +02 (C): │fill pane up with something 10 │ +03 (C): │fill pane up with something 11 │ +04 (C): │fill pane up with something 12 │ +05 (C): │fill pane up with something 13 │ +06 (C): │fill pane up with something 14 │ +07 (C): │fill pane up with something 15 │ +08 (C): │fill pane up with something 16 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-7.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-7.snap new file mode 100644 index 00000000..e2c021ed --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-7.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 3/13 ┐ +01 (C): │fill pane up with something 10 │ +02 (C): │fill pane up with something 11 │ +03 (C): │fill pane up with something 12 │ +04 (C): │fill pane up with something 13 │ +05 (C): │fill pane up with something 14 │ +06 (C): │fill pane up with something 15 │ +07 (C): │fill pane up with something 16 │ +08 (C): │fill pane up with something 17 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-8.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-8.snap new file mode 100644 index 00000000..eea8c7f4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-8.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 2/13 ┐ +01 (C): │fill pane up with something 11 │ +02 (C): │fill pane up with something 12 │ +03 (C): │fill pane up with something 13 │ +04 (C): │fill pane up with something 14 │ +05 (C): │fill pane up with something 15 │ +06 (C): │fill pane up with something 16 │ +07 (C): │fill pane up with something 17 │ +08 (C): │fill pane up with something 18 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-9.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-9.snap new file mode 100644 index 00000000..47fdf2d7 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action-9.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1222 +expression: "format!(\"{}\", snapshot_count)" +--- +8 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action.snap new file mode 100644 index 00000000..798b4720 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_down_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1193 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-2.snap new file mode 100644 index 00000000..fd5c4f89 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1239 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-3.snap new file mode 100644 index 00000000..7a2e2371 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1239 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 1/13 ┐ +01 (C): │fill pane up with something 12 │ +02 (C): │fill pane up with something 13 │ +03 (C): │fill pane up with something 14 │ +04 (C): │fill pane up with something 15 │ +05 (C): │fill pane up with something 16 │ +06 (C): │fill pane up with something 17 │ +07 (C): │fill pane up with something 18 │ +08 (C): │fill pane up with something 19 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-4.snap new file mode 100644 index 00000000..8e073396 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1239 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 2/13 ┐ +01 (C): │fill pane up with something 11 │ +02 (C): │fill pane up with something 12 │ +03 (C): │fill pane up with something 13 │ +04 (C): │fill pane up with something 14 │ +05 (C): │fill pane up with something 15 │ +06 (C): │fill pane up with something 16 │ +07 (C): │fill pane up with something 17 │ +08 (C): │fill pane up with something 18 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-5.snap new file mode 100644 index 00000000..657ed3e8 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1239 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 3/13 ┐ +01 (C): │fill pane up with something 10 │ +02 (C): │fill pane up with something 11 │ +03 (C): │fill pane up with something 12 │ +04 (C): │fill pane up with something 13 │ +05 (C): │fill pane up with something 14 │ +06 (C): │fill pane up with something 15 │ +07 (C): │fill pane up with something 16 │ +08 (C): │fill pane up with something 17 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-6.snap new file mode 100644 index 00000000..60f03824 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-6.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1239 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 4/13 ┐ +01 (C): │fill pane up with something 9 │ +02 (C): │fill pane up with something 10 │ +03 (C): │fill pane up with something 11 │ +04 (C): │fill pane up with something 12 │ +05 (C): │fill pane up with something 13 │ +06 (C): │fill pane up with something 14 │ +07 (C): │fill pane up with something 15 │ +08 (C): │fill pane up with something 16 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-7.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-7.snap new file mode 100644 index 00000000..92ac7a86 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-7.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1239 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 0/13 ┐ +01 (C): │fill pane up with something 13 │ +02 (C): │fill pane up with something 14 │ +03 (C): │fill pane up with something 15 │ +04 (C): │fill pane up with something 16 │ +05 (C): │fill pane up with something 17 │ +06 (C): │fill pane up with something 18 │ +07 (C): │fill pane up with something 19 │ +08 (C): │ │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-8.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-8.snap new file mode 100644 index 00000000..92163142 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action-8.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1268 +expression: "format!(\"{}\", snapshot_count)" +--- +7 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action.snap new file mode 100644 index 00000000..98e19e67 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_to_bottom_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1239 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-2.snap new file mode 100644 index 00000000..cd8a3061 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1147 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-3.snap new file mode 100644 index 00000000..d61adfbc --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1147 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 1/13 ┐ +01 (C): │fill pane up with something 12 │ +02 (C): │fill pane up with something 13 │ +03 (C): │fill pane up with something 14 │ +04 (C): │fill pane up with something 15 │ +05 (C): │fill pane up with something 16 │ +06 (C): │fill pane up with something 17 │ +07 (C): │fill pane up with something 18 │ +08 (C): │fill pane up with something 19 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-4.snap new file mode 100644 index 00000000..a2ef5fa2 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1149 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ────────────── SCROLL: 2/13 ┐ +01 (C): │fill pane up with something 11 │ +02 (C): │fill pane up with something 12 │ +03 (C): │fill pane up with something 13 │ +04 (C): │fill pane up with something 14 │ +05 (C): │fill pane up with something 15 │ +06 (C): │fill pane up with something 16 │ +07 (C): │fill pane up with something 17 │ +08 (C): │fill pane up with something 18 │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-5.snap new file mode 100644 index 00000000..9c7f4cf7 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action-5.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1175 +expression: "format!(\"{}\", snapshot_count)" +--- +4 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action.snap new file mode 100644 index 00000000..94eef91e --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_scroll_up_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1147 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_switch_mode_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_switch_mode_action.snap new file mode 100644 index 00000000..49e3d8fb --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_switch_mode_action.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1711 +expression: "format!(\"{:?}\", *\n mock_screen.os_input.server_to_client_messages.lock().unwrap())" +--- +{1: [SwitchToMode(Locked)]} diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_active_tab_sync_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_active_tab_sync_action.snap new file mode 100644 index 00000000..8597c630 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_active_tab_sync_action.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1487 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[Write([102, 111, 111], 0), Write([102, 111, 111], 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-2.snap new file mode 100644 index 00000000..e20094c2 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1775 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-3.snap new file mode 100644 index 00000000..105baa7f --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1775 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ ┌ Pane #1 ─────────────────────────────┐ │ +04 (C): │ │ │ │ +05 (C): │ │ │ │ +06 (C): │ │ │ │ +07 (C): │ └──────────────────────────────────────┘ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-4.snap new file mode 100644 index 00000000..84f72323 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1775 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): │ │ +05 (C): │ │ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-5.snap new file mode 100644 index 00000000..105baa7f --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-5.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1775 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ ┌ Pane #1 ─────────────────────────────┐ │ +04 (C): │ │ │ │ +05 (C): │ │ │ │ +06 (C): │ │ │ │ +07 (C): │ └──────────────────────────────────────┘ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-6.snap new file mode 100644 index 00000000..2b28bb3a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-6.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1818 +expression: "format!(\"{}\", snapshot_count)" +--- +5 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes.snap new file mode 100644 index 00000000..b7d2d258 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1775 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-2.snap new file mode 100644 index 00000000..d7a84628 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1427 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-3.snap new file mode 100644 index 00000000..25e1f8df --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1427 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): │ │ +05 (C): │ │ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-4.snap new file mode 100644 index 00000000..8ee7c1cb --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1466 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action.snap new file mode 100644 index 00000000..a18e57fb --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_full_screen_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1427 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-2.snap new file mode 100644 index 00000000..0cffa2c9 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1737 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-3.snap new file mode 100644 index 00000000..81d9b259 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1737 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ ┌ Pane #1 ─────────────────────────────┐ │ +04 (C): │ │ │ │ +05 (C): │ │ │ │ +06 (C): │ │ │ │ +07 (C): │ └──────────────────────────────────────┘ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────────────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-4.snap new file mode 100644 index 00000000..3ee6542f --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1737 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #2 ─────────────────────────────┐┌ Pane #1 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-5.snap new file mode 100644 index 00000000..0f07af8a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-5.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1778 +expression: "format!(\"{}\", snapshot_count)" +--- +4 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float.snap new file mode 100644 index 00000000..626bca74 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1737 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-2.snap new file mode 100644 index 00000000..2e0fc915 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1457 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-3.snap new file mode 100644 index 00000000..395ce350 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1457 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): │ +01 (C): │ +02 (C): │ +03 (C): │ +04 (C): │ +05 (C): │ +06 (C): │ +07 (C): │ +08 (C): │ +09 (C): │ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-4.snap new file mode 100644 index 00000000..2ca593dd --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action-4.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1498 +expression: "format!(\"{}\", snapshot_count)" +--- +3 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action.snap new file mode 100644 index 00000000..e8307ea9 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_frames_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1457 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-2.snap new file mode 100644 index 00000000..f8d04616 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1870 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): +01 (C): +02 (C): +03 (C): +04 (C): +05 (C): +06 (C): +07 (C): +08 (C): +09 (C): + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-3.snap new file mode 100644 index 00000000..37c5f371 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-3.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1870 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ my_new_pane_title ───────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): │ │ +05 (C): │ │ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-4.snap new file mode 100644 index 00000000..a65e528e --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-4.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1870 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐ +01 (C): │ │ +02 (C): │ │ +03 (C): │ │ +04 (C): │ │ +05 (C): │ │ +06 (C): │ │ +07 (C): │ │ +08 (C): │ │ +09 (C): └──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-5.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-5.snap new file mode 100644 index 00000000..f2b26455 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-5.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2264 +expression: "format!(\"{}\", snapshot_count)" +--- +4 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-6.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-6.snap new file mode 100644 index 00000000..edd72e56 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action-6.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2260 +expression: "format!(\"{}\", snapshot_count)" +--- +5 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action.snap new file mode 100644 index 00000000..3457c90d --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_pane_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 1870 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +01 (C): │ ││ │ +02 (C): │ ││ │ +03 (C): │ ││ │ +04 (C): │ ││ │ +05 (C): │ ││ │ +06 (C): │ ││ │ +07 (C): │ ││ │ +08 (C): │ ││ │ +09 (C): └──────────────────────────────────────┘└──────────────────────────────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap new file mode 100644 index 00000000..dbe2c85a --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap @@ -0,0 +1,473 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2571 +expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())" +--- +[ + Update( + None, + Some( + 10, + ), + InputReceived, + ), + Update( + None, + Some( + 10, + ), + InputReceived, + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + ModeUpdate( + ModeInfo { + mode: Normal, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: false, + }, + session_name: Some( + "zellij-test", + ), + }, + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: false, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + TabInfo { + position: 1, + name: "Tab #2", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: false, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + TabInfo { + position: 1, + name: "", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: false, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + TabInfo { + position: 1, + name: "new-tab-name", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Update( + None, + Some( + 10, + ), + InputReceived, + ), + Update( + None, + Some( + 1, + ), + TabUpdate( + [ + TabInfo { + position: 0, + name: "Tab #1", + active: false, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + TabInfo { + position: 1, + name: "Tab #2", + active: true, + panes_to_hide: 0, + is_fullscreen_active: false, + is_sync_panes_active: false, + are_floating_panes_visible: false, + other_focused_clients: [], + }, + ], + ), + ), + Exit, +] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_update_search_term.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_update_search_term.snap new file mode 100644 index 00000000..9421b96e --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_update_search_term.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2614 +expression: "format!(\"{:?}\", * received_server_instructions.lock().unwrap())" +--- +[Render(Some({1: "\u{1b}[?25l\u{1b}[2J\u{1b}[1;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐\u{1b}[2;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[2;80H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;80H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;80H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────────────────────────────────────────────┘\u{1b}[2;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[3;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[4;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[6;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐\u{1b}[7;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[10;1H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────────────────────────────────────────────┘\u{1b}[7;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[8;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[9;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[6;1H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), UnblockInputThread, Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), Render(Some({1: "\u{1b}[?25l\u{1b}[2J\u{1b}[1;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #1 ─────────────────────────────┐\u{1b}[2;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[2;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;40H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[10;1H\u{1b}[m\u{1b}[38;5;0m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────┘\u{1b}[2;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[3;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[4;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[5;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[6;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[7;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[8;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[9;2H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[1;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m┌ Pane #2 ─────────────────────────────┐\u{1b}[2;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[2;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[3;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[4;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[5;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[6;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[7;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[8;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[9;80H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m│\u{1b}[10;41H\u{1b}[m\u{1b}[39m\u{1b}[49m\u{1b}[29m\u{1b}[28m\u{1b}[27m\u{1b}[25m\u{1b}[25m\u{1b}[1m\u{1b}[24m\u{1b}[23m└──────────────────────────────────────┘\u{1b}[2;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[3;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[4;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[5;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[6;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[7;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[8;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}[9;42H\u{1b}[m\u{1b}[m\u{1b}]8;;\u{1b}\\ \u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[1;41H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), UnblockInputThread, Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), Render(Some({1: "\u{1b}[?25l\u{1b}]0;Zellij (zellij-test) - Pane #1\u{7}\u{1b}[1;1H\u{1b}[m\u{1b}[?25h\u{1b}[2;2H\u{1b}[m\u{1b}[0 q"})), KillSession] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_write_action_to_screen.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_write_action_to_screen.snap new file mode 100644 index 00000000..32ae2a50 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_write_action_to_screen.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 879 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[Write([102, 111, 111], 0), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_write_chars_action_to_screen.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_write_chars_action_to_screen.snap new file mode 100644 index 00000000..90ade0ee --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_write_chars_action_to_screen.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 846 +expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +--- +[Write([105, 110, 112, 117, 116, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 99, 108, 105], 0), Exit] diff --git a/zellij-utils/Cargo.toml b/zellij-utils/Cargo.toml index 4bbd0897..02fad102 100644 --- a/zellij-utils/Cargo.toml +++ b/zellij-utils/Cargo.toml @@ -23,7 +23,6 @@ libc = "0.2" nix = "0.23.1" once_cell = "1.8.0" serde = { version = "1.0", features = ["derive"] } -serde_yaml = "0.8" serde_json = "1.0" strip-ansi-escapes = "0.1.0" strum = "0.20.0" @@ -36,6 +35,7 @@ unicode-width = "0.1.8" miette = { version = "3.3.0", features = ["fancy"] } regex = "1.5.5" tempfile = "3.2.0" +kdl = { version = "4.5.0", features = ["span"] } #[cfg(not(target_family = "wasm"))] [target.'cfg(not(target_family = "wasm"))'.dependencies] @@ -46,6 +46,8 @@ interprocess = "1.1.1" async-std = { version = "1.3.0", features = ["unstable"] } [dev-dependencies] +insta = { version = "1.6.0", features = ["backtrace"] } + [features] disable_automatic_asset_installation = [] diff --git a/zellij-utils/assets/config/default.kdl b/zellij-utils/assets/config/default.kdl new file mode 100644 index 00000000..227dea43 --- /dev/null +++ b/zellij-utils/assets/config/default.kdl @@ -0,0 +1,294 @@ +keybinds { + normal { + // uncomment this and adjust key if using copy_on_select=false + // bind "Alt c" { Copy; } + } + locked { + bind "Ctrl g" { SwitchToMode "Normal"; } + } + resize { + bind "Ctrl n" { SwitchToMode "Normal"; } + bind "h" "Left" { Resize "Left"; } + bind "j" "Down" { Resize "Down"; } + bind "k" "Up" { Resize "Up"; } + bind "l" "Right" { Resize "Right"; } + bind "=" "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + } + pane { + bind "Ctrl p" { SwitchToMode "Normal"; } + bind "h" "Left" { MoveFocus "Left"; } + bind "l" "Right" { MoveFocus "Right"; } + bind "j" "Down" { MoveFocus "Down"; } + bind "k" "Up" { MoveFocus "Up"; } + bind "p" { SwitchFocus; } + bind "n" { NewPane; SwitchToMode "Normal"; } + bind "d" { NewPane "Down"; SwitchToMode "Normal"; } + bind "r" { NewPane "Right"; SwitchToMode "Normal"; } + bind "x" { CloseFocus; SwitchToMode "Normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "Normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "Normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "Normal"; } + bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0;} + } + move { + bind "Ctrl h" { SwitchToMode "Normal"; } + bind "n" "Tab" { MovePane; } + bind "h" "Left" { MovePane "Left"; } + bind "j" "Down" { MovePane "Down"; } + bind "k" "Up" { MovePane "Up"; } + bind "l" "Right" { MovePane "Right"; } + } + tab { + bind "Ctrl t" { SwitchToMode "Normal"; } + bind "r" { SwitchToMode "RenameTab"; TabNameInput 0; } + bind "h" "Left" "Up" "k" { GoToPreviousTab; } + bind "l" "Right" "Down" "j" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "Normal"; } + bind "x" { CloseTab; SwitchToMode "Normal"; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "Normal"; } + bind "1" { GoToTab 1; SwitchToMode "Normal"; } + bind "2" { GoToTab 2; SwitchToMode "Normal"; } + bind "3" { GoToTab 3; SwitchToMode "Normal"; } + bind "4" { GoToTab 4; SwitchToMode "Normal"; } + bind "5" { GoToTab 5; SwitchToMode "Normal"; } + bind "6" { GoToTab 6; SwitchToMode "Normal"; } + bind "7" { GoToTab 7; SwitchToMode "Normal"; } + bind "8" { GoToTab 8; SwitchToMode "Normal"; } + bind "9" { GoToTab 9; SwitchToMode "Normal"; } + bind "Tab" { ToggleTab; } + } + scroll { + bind "Ctrl s" { SwitchToMode "Normal"; } + bind "e" { EditScrollback; SwitchToMode "Normal"; } + bind "s" { SwitchToMode "EnterSearch"; SearchInput 0; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "Normal"; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + // uncomment this and adjust key if using copy_on_select=false + // bind "Alt c" { Copy; } + } + search { + bind "Ctrl s" { SwitchToMode "Normal"; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "Normal"; } + bind "j" "Down" { ScrollDown; } + bind "k" "Up" { ScrollUp; } + bind "Ctrl f" "PageDown" "Right" "l" { PageScrollDown; } + bind "Ctrl b" "PageUp" "Left" "h" { PageScrollUp; } + bind "d" { HalfPageScrollDown; } + bind "u" { HalfPageScrollUp; } + bind "n" { Search "down"; } + bind "p" { Search "up"; } + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "w" { SearchToggleOption "Wrap"; } + bind "o" { SearchToggleOption "WholeWord"; } + } + entersearch { + bind "Ctrl c" "Esc" { SwitchToMode "Scroll"; } + bind "Enter" { SwitchToMode "Search"; } + } + renametab { + bind "Ctrl c" { SwitchToMode "Normal"; } + bind "Esc" { UndoRenameTab; SwitchToMode "Tab"; } + } + renamepane { + bind "Ctrl c" { SwitchToMode "Normal"; } + bind "Esc" { UndoRenamePane; SwitchToMode "Pane"; } + } + session { + bind "Ctrl o" { SwitchToMode "Normal"; } + bind "Ctrl s" { SwitchToMode "Scroll"; } + bind "d" { Detach; } + } + tmux { + bind "[" { SwitchToMode "Scroll"; } + bind "Ctrl b" { Write 2; SwitchToMode "Normal"; } + bind "\"" { NewPane "Down"; SwitchToMode "Normal"; } + bind "%" { NewPane "Right"; SwitchToMode "Normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "Normal"; } + bind "c" { NewTab; SwitchToMode "Normal"; } + bind "," { SwitchToMode "RenameTab"; } + bind "p" { GoToPreviousTab; SwitchToMode "Normal"; } + bind "n" { GoToNextTab; SwitchToMode "Normal"; } + bind "Left" { MoveFocus "Left"; SwitchToMode "Normal"; } + bind "Right" { MoveFocus "Right"; SwitchToMode "Normal"; } + bind "Down" { MoveFocus "Down"; SwitchToMode "Normal"; } + bind "Up" { MoveFocus "Up"; SwitchToMode "Normal"; } + bind "h" { MoveFocus "Left"; SwitchToMode "Normal"; } + bind "l" { MoveFocus "Right"; SwitchToMode "Normal"; } + bind "j" { MoveFocus "Down"; SwitchToMode "Normal"; } + bind "k" { MoveFocus "Up"; SwitchToMode "Normal"; } + bind "o" { FocusNextPane; } + bind "d" { Detach; } + } + shared_except "locked" { + bind "Ctrl g" { SwitchToMode "Locked"; } + bind "Ctrl q" { Quit; } + bind "Alt n" { NewPane; } + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + bind "Alt l" "Alt Right" { MoveFocusOrTab "Right"; } + bind "Alt j" "Alt Down" { MoveFocus "Down"; } + bind "Alt k" "Alt Up" { MoveFocus "Up"; } + bind "Alt =" "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + } + shared_except "normal" "locked" { + bind "Enter" "Space" "Esc" { SwitchToMode "Normal"; } + } + shared_except "pane" "locked" { + bind "Ctrl p" { SwitchToMode "Pane"; } + } + shared_except "resize" "locked" { + bind "Ctrl n" { SwitchToMode "Resize"; } + } + shared_except "scroll" "locked" { + bind "Ctrl s" { SwitchToMode "Scroll"; } + } + shared_except "session" "locked" { + bind "Ctrl o" { SwitchToMode "Session"; } + } + shared_except "tab" "locked" { + bind "Ctrl t" { SwitchToMode "Tab"; } + } + shared_except "move" "locked" { + bind "Ctrl h" { SwitchToMode "Move"; } + } + shared_except "tmux" "locked" { + bind "Ctrl b" { SwitchToMode "Tmux"; } + } +} + +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} + +// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP +// eg. when terminal window with an active zellij session is closed +// Options: +// - detach (Default) +// - quit +// +// on_force_close "quit" + +// Send a request for a simplified ui (without arrow fonts) to plugins +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Toggle between having pane frames around the panes +// Options: +// - true (default) +// - false +// +// pane_frames true + +// Define color themes for Zellij +// For more examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes +// Once these themes are defined, one of them should to be selected in the "theme" section of this file +// +// themes { +// dracula { +// fg 248 248 242 +// bg 40 42 54 +// red 255 85 85 +// green 80 250 123 +// yellow 241 250 140 +// blue 98 114 164 +// magenta 255 121 198 +// orange 255 184 108 +// cyan 139 233 253 +// black 0 0 0 +// white 255 255 255 +// } +// } + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "default" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// Choose the mode that zellij uses when starting up. +// Default: normal +// +// default_mode "locked" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Configure the scroll back buffer size +// This is the number of lines zellij stores for each pane in the scroll back +// buffer. Excess number of lines are discarded in a FIFO fashion. +// Valid values: positive integers +// Default value: 10000 +// +// scroll_buffer_size 10000 + +// Provide a command to execute when copying text. The text will be piped to +// the stdin of the program to perform the copy. This can be used with +// terminal emulators which do not support the OSC 52 ANSI control sequence +// that will be used by default if this option is not set. +// Examples: +// +// copy_command "xclip -selection clipboard" // x11 +// copy_command "wl-copy" // wayland +// copy_command "pbcopy" // osx + +// Choose the destination for copied text +// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. +// Does not apply when using copy_command. +// Options: +// - system (default) +// - primary +// +// copy_clipboard "primary" + +// Enable or disable automatic copy (and clear) of selection when releasing mouse +// Default: true +// +// copy_on_select false + +// Path to the default editor to use to edit pane scrollbuffer +// Default: $EDITOR or $VISUAL +// +// scrollback_editor "/usr/bin/vim" + +// When attaching to an existing session with other users, +// should the session be mirrored (true) +// or should each user have their own cursor (false) +// Default: false +// +// mirror_session true + +// The folder in which Zellij will look for layouts +// +// layout_dir "/path/to/my/layout_dir" + +// The folder in which Zellij will look for themes +// +// theme_dir "/path/to/my/theme_dir" diff --git a/zellij-utils/assets/layouts/compact.kdl b/zellij-utils/assets/layouts/compact.kdl new file mode 100644 index 00000000..7871ad40 --- /dev/null +++ b/zellij-utils/assets/layouts/compact.kdl @@ -0,0 +1,6 @@ +layout { + pane + pane size=1 borderless=true { + plugin location="zellij:compact-bar" + } +} diff --git a/zellij-utils/assets/layouts/compact.yaml b/zellij-utils/assets/layouts/compact.yaml deleted file mode 100644 index d20ff08a..00000000 --- a/zellij-utils/assets/layouts/compact.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -template: - direction: Horizontal - parts: - - direction: Vertical - body: true - - direction: Vertical - borderless: true - split_size: - Fixed: 1 - run: - plugin: - location: "zellij:compact-bar" diff --git a/zellij-utils/assets/layouts/default.kdl b/zellij-utils/assets/layouts/default.kdl new file mode 100644 index 00000000..4434b29b --- /dev/null +++ b/zellij-utils/assets/layouts/default.kdl @@ -0,0 +1,9 @@ +layout { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } +} diff --git a/zellij-utils/assets/layouts/disable-status-bar.kdl b/zellij-utils/assets/layouts/disable-status-bar.kdl new file mode 100644 index 00000000..5eca5b0c --- /dev/null +++ b/zellij-utils/assets/layouts/disable-status-bar.kdl @@ -0,0 +1,6 @@ +layout { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + pane +} diff --git a/zellij-utils/assets/layouts/disable-status-bar.yaml b/zellij-utils/assets/layouts/disable-status-bar.yaml deleted file mode 100644 index 10779398..00000000 --- a/zellij-utils/assets/layouts/disable-status-bar.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -template: - direction: Horizontal - parts: - - direction: Vertical - borderless: true - split_size: - Fixed: 1 - run: - plugin: - location: "zellij:tab-bar" - - direction: Vertical - body: true diff --git a/zellij-utils/assets/layouts/no-plugins.kdl b/zellij-utils/assets/layouts/no-plugins.kdl new file mode 100644 index 00000000..45535924 --- /dev/null +++ b/zellij-utils/assets/layouts/no-plugins.kdl @@ -0,0 +1 @@ +layout diff --git a/zellij-utils/assets/layouts/no-plugins.yaml b/zellij-utils/assets/layouts/no-plugins.yaml deleted file mode 100644 index 808d6860..00000000 --- a/zellij-utils/assets/layouts/no-plugins.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -template: - direction: Horizontal - parts: - - direction: Vertical - body: true -tabs: - - direction: Vertical diff --git a/zellij-utils/assets/layouts/strider.kdl b/zellij-utils/assets/layouts/strider.kdl new file mode 100644 index 00000000..dbe8d077 --- /dev/null +++ b/zellij-utils/assets/layouts/strider.kdl @@ -0,0 +1,19 @@ +layout { + default_tab_template { + pane size=1 borderless=true { + plugin location="zellij:tab-bar" + } + children + pane size=2 borderless=true { + plugin location="zellij:status-bar" + } + } + tab { + pane split_direction="Vertical" { + pane size="20%" { + plugin location="zellij:strider" + } + pane + } + } +} diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index a947f943..24616bd1 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -1,6 +1,8 @@ +use crate::data::InputMode; use crate::setup::Setup; use crate::{ consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}, + input::actions::{Direction, ResizeDirection}, input::options::CliOptions, }; use clap::{Parser, Subcommand}; @@ -46,6 +48,15 @@ pub struct CliArgs { pub debug: bool, } +impl CliArgs { + pub fn should_clean_config(&self) -> bool { + match &self.command { + Some(Command::Setup(ref setup)) => setup.clean, + _ => false, + } + } +} + #[derive(Debug, Subcommand, Clone, Serialize, Deserialize)] pub enum Command { /// Change the behaviour of zellij @@ -110,6 +121,137 @@ pub enum Sessions { yes: bool, }, /// Send actions to a specific session - #[cfg(feature = "unstable")] - Action { action: Option }, + #[clap(visible_alias = "ac")] + #[clap(subcommand)] + Action(CliAction), + /// Send actions to a specific session + #[clap(visible_alias = "c")] + Command { + command: Option, + #[clap(short, long, value_parser, conflicts_with("floating"))] + direction: Option, + #[clap(long, value_parser)] + cwd: Option, + #[clap(short, long, value_parser, default_missing_value("true"))] + floating: Option, + }, + /// Edit file with default $EDITOR / $VISUAL in a specific session + #[clap(visible_alias = "e")] + Edit { + file: PathBuf, + #[clap(short, long, value_parser)] + line_number: Option, + #[clap(short, long, value_parser, conflicts_with("floating"))] + direction: Option, + #[clap(short, long, value_parser, default_missing_value("true"))] + floating: Option, + }, + ConvertConfig { + old_config_file: PathBuf, + }, + ConvertLayout { + old_layout_file: PathBuf, + }, + ConvertTheme { + old_theme_file: PathBuf, + }, +} + +#[derive(Debug, Subcommand, Clone, Serialize, Deserialize)] +pub enum CliAction { + /// Write bytes to the terminal. + Write { bytes: Vec }, + /// Write characters to the terminal. + WriteChars { chars: String }, + /// Resize the focused pane in the specified direction. [right|left|up|down|+|-] + Resize { resize_direction: ResizeDirection }, + /// Change focus to the next pane + FocusNextPane, + /// Change focus to the previous pane + FocusPreviousPane, + /// Move the focused pane in the specified direction. [right|left|up|down] + MoveFocus { direction: Direction }, + /// Move focus to the pane or tab (if on screen edge) in the specified direction + /// [right|left|up|down] + MoveFocusOrTab { direction: Direction }, + /// Change the location of the focused pane in the specified direction + /// [right|left|up|down] + MovePane { direction: Direction }, + /// Dumps the pane scrollback to a file + DumpScreen { path: PathBuf }, + /// Open the pane scrollback in your default editor + EditScrollback, + /// Scroll up in the focused pane + ScrollUp, + /// Scroll down in focus pane. + ScrollDown, + /// Scroll down to bottom in focus pane. + ScrollToBottom, + /// Scroll up one page in focus pane. + PageScrollUp, + /// Scroll down one page in focus pane. + PageScrollDown, + /// Scroll up half page in focus pane. + HalfPageScrollUp, + /// Scroll down half page in focus pane. + HalfPageScrollDown, + /// Toggle between fullscreen focus pane and normal layout. + ToggleFullscreen, + /// Toggle frames around panes in the UI + TogglePaneFrames, + /// Toggle between sending text commands to all panes on the current tab and normal mode. + ToggleActiveSyncTab, + /// Open a new pane in the specified direction [right|left|up|down] + /// If no direction is specified, will try to use the biggest available space. + NewPane { + #[clap(short, long, value_parser, conflicts_with("floating"))] + direction: Option, + #[clap(short, long, value_parser)] + command: Option, + #[clap(long, value_parser)] + cwd: Option, + #[clap(short, long, value_parser, default_missing_value("true"))] + floating: Option, + }, + /// Open the specified file in a new zellij pane with your default EDITOR + Edit { + file: PathBuf, + #[clap(short, long, value_parser, conflicts_with("floating"))] + direction: Option, + #[clap(short, long, value_parser)] + line_number: Option, + #[clap(short, long, value_parser, default_missing_value("true"))] + floating: Option, + }, + /// Switch input mode of all connected clients [locked|pane|tab|resize|move|search|session] + SwitchMode { input_mode: InputMode }, + /// Embed focused pane if floating or float focused pane if embedded + TogglePaneEmbedOrFloating, + /// Toggle the visibility of all fdirectionloating panes in the current Tab, open one if none exist + ToggleFloatingPanes, + /// Close the focused pane. + ClosePane, + /// Renames the focused pane + RenamePane { name: String }, + /// Remove a previously set pane name + UndoRenamePane, + /// Go to the next tab. + GoToNextTab, + /// Go to the previous tab. + GoToPreviousTab, + /// Close the current tab. + CloseTab, + /// Go to tab with index [index] + GoToTab { index: u32 }, + /// Renames the focused pane + RenameTab { name: String }, + /// Remove a previously set tab name + UndoRenameTab, + /// Create a new tab, optionally with a specified tab layout and name + NewTab { + #[clap(short, long, value_parser)] + layout: Option, + #[clap(short, long, value_parser)] + name: Option, + }, } diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs index b2897292..605cf898 100644 --- a/zellij-utils/src/data.rs +++ b/zellij-utils/src/data.rs @@ -1,4 +1,5 @@ use crate::input::actions::Action; +use crate::input::config::ConversionError; use clap::ArgEnum; use serde::{Deserialize, Serialize}; use std::fmt; @@ -58,6 +59,95 @@ pub enum Key { Esc, } +impl FromStr for Key { + type Err = Box; + fn from_str(key_str: &str) -> Result { + let mut modifier: Option<&str> = None; + let mut main_key: Option<&str> = None; + for (index, part) in key_str.split_ascii_whitespace().enumerate() { + if index == 0 && (part == "Ctrl" || part == "Alt") { + modifier = Some(part); + } else if main_key.is_none() { + main_key = Some(part) + } + } + match (modifier, main_key) { + (Some("Ctrl"), Some(main_key)) => { + let mut key_chars = main_key.chars(); + let key_count = main_key.chars().count(); + if key_count == 1 { + let key_char = key_chars.next().unwrap(); + Ok(Key::Ctrl(key_char)) + } else { + Err(format!("Failed to parse key: {}", key_str).into()) + } + }, + (Some("Alt"), Some(main_key)) => { + match main_key { + // why crate::data::Direction and not just Direction? + // Because it's a different type that we export in this wasm mandated soup - we + // don't like it either! This will be solved as we chip away at our tech-debt + "Left" => Ok(Key::Alt(CharOrArrow::Direction(Direction::Left))), + "Right" => Ok(Key::Alt(CharOrArrow::Direction(Direction::Right))), + "Up" => Ok(Key::Alt(CharOrArrow::Direction(Direction::Up))), + "Down" => Ok(Key::Alt(CharOrArrow::Direction(Direction::Down))), + _ => { + let mut key_chars = main_key.chars(); + let key_count = main_key.chars().count(); + if key_count == 1 { + let key_char = key_chars.next().unwrap(); + Ok(Key::Alt(CharOrArrow::Char(key_char))) + } else { + Err(format!("Failed to parse key: {}", key_str).into()) + } + }, + } + }, + (None, Some(main_key)) => match main_key { + "Backspace" => Ok(Key::Backspace), + "Left" => Ok(Key::Left), + "Right" => Ok(Key::Right), + "Up" => Ok(Key::Up), + "Down" => Ok(Key::Down), + "Home" => Ok(Key::Home), + "End" => Ok(Key::End), + "PageUp" => Ok(Key::PageUp), + "PageDown" => Ok(Key::PageDown), + "Tab" => Ok(Key::BackTab), + "Delete" => Ok(Key::Delete), + "Insert" => Ok(Key::Insert), + "Space" => Ok(Key::Char(' ')), + "Enter" => Ok(Key::Char('\n')), + "Esc" => Ok(Key::Esc), + _ => { + let mut key_chars = main_key.chars(); + let key_count = main_key.chars().count(); + if key_count == 1 { + let key_char = key_chars.next().unwrap(); + Ok(Key::Char(key_char)) + } else if key_count > 1 { + if let Some(first_char) = key_chars.next() { + if first_char == 'F' { + let f_index: String = key_chars.collect(); + let f_index: u8 = f_index + .parse() + .map_err(|e| format!("Failed to parse F index: {}", e))?; + if f_index >= 1 && f_index <= 12 { + return Ok(Key::F(f_index)); + } + } + } + Err(format!("Failed to parse key: {}", key_str).into()) + } else { + Err(format!("Failed to parse key: {}", key_str).into()) + } + }, + }, + _ => Err(format!("Failed to parse key: {}", key_str).into()), + } + } +} + impl fmt::Display for Key { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -154,7 +244,20 @@ pub enum Event { } /// Describes the different input modes, which change the way that keystrokes will be interpreted. -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, EnumIter, Serialize, Deserialize, ArgEnum)] +#[derive( + Debug, + PartialEq, + Eq, + Hash, + Copy, + Clone, + EnumIter, + Serialize, + Deserialize, + ArgEnum, + PartialOrd, + Ord, +)] pub enum InputMode { /// In `Normal` mode, input is always written to the terminal, except for the shortcuts leading /// to other modes @@ -202,6 +305,27 @@ pub enum InputMode { Tmux, } +// impl TryFrom<&str> for InputMode { +// type Error = String; +// fn try_from(mode: &str) -> Result { +// match mode { +// "normal" | "Normal" => Ok(InputMode::Normal), +// "locked" | "Locked" => Ok(InputMode::Locked), +// "resize" | "Resize" => Ok(InputMode::Resize), +// "pane" | "Pane" => Ok(InputMode::Pane), +// "tab" | "Tab" => Ok(InputMode::Tab), +// "search" | "Search" => Ok(InputMode::Search), +// "renametab" | "RenameTab" => Ok(InputMode::RenameTab), +// "renamepane" | "RenamePane" => Ok(InputMode::RenamePane), +// "session" | "Session" => Ok(InputMode::Session), +// "move" | "Move" => Ok(InputMode::Move), +// "prompt" | "Prompt" => Ok(InputMode::Prompt), +// "tmux" | "Tmux" => Ok(InputMode::Tmux), +// _ => Err(format!("Unrecognized mode: {}", mode)), +// } +// } +// } + impl Default for InputMode { fn default() -> InputMode { InputMode::Normal @@ -231,25 +355,25 @@ impl Default for PaletteColor { } impl FromStr for InputMode { - type Err = Box; + type Err = ConversionError; - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { match s { - "normal" => Ok(InputMode::Normal), - "resize" => Ok(InputMode::Resize), - "locked" => Ok(InputMode::Locked), - "pane" => Ok(InputMode::Pane), - "tab" => Ok(InputMode::Tab), - "scroll" => Ok(InputMode::Scroll), - "search" => Ok(InputMode::Search), - "entersearch" => Ok(InputMode::EnterSearch), - "renametab" => Ok(InputMode::RenameTab), - "session" => Ok(InputMode::Session), - "move" => Ok(InputMode::Move), - "tmux" => Ok(InputMode::Tmux), - "prompt" => Ok(InputMode::Prompt), - "renamepane" => Ok(InputMode::RenamePane), - e => Err(e.to_string().into()), + "normal" | "Normal" => Ok(InputMode::Normal), + "locked" | "Locked" => Ok(InputMode::Locked), + "resize" | "Resize" => Ok(InputMode::Resize), + "pane" | "Pane" => Ok(InputMode::Pane), + "tab" | "Tab" => Ok(InputMode::Tab), + "search" | "Search" => Ok(InputMode::Search), + "scroll" | "Scroll" => Ok(InputMode::Scroll), + "renametab" | "RenameTab" => Ok(InputMode::RenameTab), + "renamepane" | "RenamePane" => Ok(InputMode::RenamePane), + "session" | "Session" => Ok(InputMode::Session), + "move" | "Move" => Ok(InputMode::Move), + "prompt" | "Prompt" => Ok(InputMode::Prompt), + "tmux" | "Tmux" => Ok(InputMode::Tmux), + "entersearch" | "Entersearch" | "EnterSearch" => Ok(InputMode::EnterSearch), + e => Err(ConversionError::UnknownInputMode(e.into())), } } } @@ -343,7 +467,7 @@ pub struct PluginIds { } /// Tag used to identify the plugin in layout and config yaml files -#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, PartialOrd, Ord)] pub struct PluginTag(String); impl PluginTag { diff --git a/zellij-utils/src/envs.rs b/zellij-utils/src/envs.rs index 9e457b03..3596e94e 100644 --- a/zellij-utils/src/envs.rs +++ b/zellij-utils/src/envs.rs @@ -2,10 +2,12 @@ use anyhow::Result; use serde::{Deserialize, Serialize}; use std::{ - collections::HashMap, + collections::{BTreeMap, HashMap}, env::{set_var, var}, }; +use std::fmt; + pub const ZELLIJ_ENV_KEY: &str = "ZELLIJ"; pub fn get_zellij() -> Result { Ok(var(ZELLIJ_ENV_KEY)?) @@ -34,19 +36,31 @@ pub fn get_socket_dir() -> Result { } /// Manage ENVIRONMENT VARIABLES from the configuration and the layout files -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] -pub struct EnvironmentVariablesFromYaml { +#[derive(Default, Clone, PartialEq, Serialize, Deserialize)] +pub struct EnvironmentVariables { env: HashMap, } -impl EnvironmentVariablesFromYaml { +impl fmt::Debug for EnvironmentVariables { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut stable_sorted = BTreeMap::new(); + for (env_var_name, env_var_value) in self.env.iter() { + stable_sorted.insert(env_var_name, env_var_value); + } + write!(f, "{:#?}", stable_sorted) + } +} + +impl EnvironmentVariables { /// Merges two structs, keys from `other` supersede keys from `self` pub fn merge(&self, other: Self) -> Self { let mut env = self.clone(); env.env.extend(other.env); env } - + pub fn from_data(data: HashMap) -> Self { + EnvironmentVariables { env: data } + } /// Set all the ENVIRONMENT VARIABLES, that are configured /// in the configuration and layout files pub fn set_vars(&self) { diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index dac249fc..ec9d4de3 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -214,6 +214,8 @@ pub enum ScreenContext { NewPane, OpenInPlaceEditor, ToggleFloatingPanes, + ShowFloatingPanes, + HideFloatingPanes, TogglePaneEmbedOrFloating, HorizontalSplit, VerticalSplit, @@ -276,6 +278,7 @@ pub enum ScreenContext { TerminalForegroundColor, TerminalColorRegisters, ChangeMode, + ChangeModeForAllClients, LeftClick, RightClick, MiddleClick, @@ -339,6 +342,7 @@ pub enum ClientContext { SwitchToMode, Connected, ActiveClients, + OwnClientId, } /// Stack call representations corresponding to the different types of [`ServerInstruction`]s. diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 754151a1..8dacdc65 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -1,21 +1,42 @@ //! Definition of the actions that can be bound to keys. use super::command::RunCommandAction; -use super::layout::TabLayout; +use super::layout::{Layout, PaneLayout}; +use crate::cli::CliAction; use crate::data::InputMode; +use crate::input::config::{ConfigError, KdlError}; use crate::input::options::OnForceClose; +use miette::{NamedSource, Report}; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use std::str::FromStr; + use crate::position::Position; /// The four directions (left, right, up, down). -#[derive(Eq, Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Eq, Clone, Copy, Debug, PartialEq, Deserialize, Serialize)] pub enum Direction { Left, Right, Up, Down, } +impl FromStr for Direction { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "Left" | "left" => Ok(Direction::Left), + "Right" | "right" => Ok(Direction::Right), + "Up" | "up" => Ok(Direction::Up), + "Down" | "down" => Ok(Direction::Down), + _ => Err(format!( + "Failed to parse Direction. Unknown Direction: {}", + s + )), + } + } +} #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum ResizeDirection { @@ -26,6 +47,23 @@ pub enum ResizeDirection { Increase, Decrease, } +impl FromStr for ResizeDirection { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "Left" | "left" => Ok(ResizeDirection::Left), + "Right" | "right" => Ok(ResizeDirection::Right), + "Up" | "up" => Ok(ResizeDirection::Up), + "Down" | "down" => Ok(ResizeDirection::Down), + "Increase" | "increase" | "+" => Ok(ResizeDirection::Increase), + "Decrease" | "decrease" | "-" => Ok(ResizeDirection::Decrease), + _ => Err(format!( + "Failed to parse ResizeDirection. Unknown ResizeDirection: {}", + s + )), + } + } +} #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum SearchDirection { @@ -33,6 +71,20 @@ pub enum SearchDirection { Up, } +impl FromStr for SearchDirection { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "Down" | "down" => Ok(SearchDirection::Down), + "Up" | "up" => Ok(SearchDirection::Up), + _ => Err(format!( + "Failed to parse SearchDirection. Unknown SearchDirection: {}", + s + )), + } + } +} + #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum SearchOption { CaseSensitivity, @@ -40,6 +92,54 @@ pub enum SearchOption { Wrap, } +impl FromStr for SearchOption { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "CaseSensitivity" | "casesensitivity" | "Casesensitivity" => { + Ok(SearchOption::CaseSensitivity) + }, + "WholeWord" | "wholeword" | "Wholeword" => Ok(SearchOption::WholeWord), + "Wrap" | "wrap" => Ok(SearchOption::Wrap), + _ => Err(format!( + "Failed to parse SearchOption. Unknown SearchOption: {}", + s + )), + } + } +} + +fn split_escaped_whitespace(s: &str) -> Vec { + s.split_ascii_whitespace() + .map(|s| String::from(s)) + .fold(vec![], |mut acc, part| { + if let Some(previous_part) = acc.last_mut() { + if previous_part.ends_with('\\') { + previous_part.push(' '); + previous_part.push_str(&part); + return acc; + } + } + acc.push(part); + acc + }) +} + +fn split_command_and_args(command: String) -> (PathBuf, Vec) { + let mut full_command = split_escaped_whitespace(&command); + let mut command = None; + let mut command_args = vec![]; + for part in full_command.drain(..) { + if command.is_none() { + command = Some(part); + } else { + command_args.push(part); + } + } + let command = PathBuf::from(command.unwrap()); + (command, command_args) +} + // As these actions are bound to the default config, please // do take care when refactoring - or renaming. // They might need to be adjusted in the default config @@ -55,6 +155,8 @@ pub enum Action { WriteChars(String), /// Switch to the specified input mode. SwitchToMode(InputMode), + /// Switch all connected clients to the specified input mode. + SwitchModeForAllClients(InputMode), /// Resize focus pane in specified direction. Resize(ResizeDirection), /// Switch focus to next pane in specified direction. @@ -97,6 +199,12 @@ pub enum Action { /// Open a new pane in the specified direction (relative to focus). /// If no direction is specified, will try to use the biggest available space. NewPane(Option), + /// Open the file in a new pane using the default editor + EditFile(PathBuf, Option, Option, Option), // usize is an optional line number, bool is floating true/false + /// Open a new floating pane + NewFloatingPane(Option), + /// Open a new tiled (embedded, non-floating) pane + NewTiledPane(Option, Option), /// Embed focused pane in tab if floating or float focused pane if embedded TogglePaneEmbedOrFloating, /// Toggle the visibility of all floating panes (if any) in the current Tab @@ -106,7 +214,7 @@ pub enum Action { PaneNameInput(Vec), UndoRenamePane, /// Create a new tab, optionally with a specified tab layout. - NewTab(Option), + NewTab(Option, Option), // the String is the tab name /// Do nothing. NoOp, /// Go to the next tab. @@ -147,6 +255,144 @@ pub enum Action { SearchToggleOption(SearchOption), } +impl Action { + pub fn actions_from_cli(cli_action: CliAction) -> Result, String> { + match cli_action { + CliAction::Write { bytes } => Ok(vec![Action::Write(bytes)]), + CliAction::WriteChars { chars } => Ok(vec![Action::WriteChars(chars)]), + CliAction::Resize { resize_direction } => Ok(vec![Action::Resize(resize_direction)]), + CliAction::FocusNextPane => Ok(vec![Action::FocusNextPane]), + CliAction::FocusPreviousPane => Ok(vec![Action::FocusPreviousPane]), + CliAction::MoveFocus { direction } => Ok(vec![Action::MoveFocus(direction)]), + CliAction::MoveFocusOrTab { direction } => Ok(vec![Action::MoveFocusOrTab(direction)]), + CliAction::MovePane { direction } => Ok(vec![Action::MovePane(Some(direction))]), + CliAction::DumpScreen { path } => Ok(vec![Action::DumpScreen( + path.as_os_str().to_string_lossy().into(), + )]), + CliAction::EditScrollback => Ok(vec![Action::EditScrollback]), + CliAction::ScrollUp => Ok(vec![Action::ScrollUp]), + CliAction::ScrollDown => Ok(vec![Action::ScrollDown]), + CliAction::ScrollToBottom => Ok(vec![Action::ScrollToBottom]), + CliAction::PageScrollUp => Ok(vec![Action::PageScrollUp]), + CliAction::PageScrollDown => Ok(vec![Action::PageScrollDown]), + CliAction::HalfPageScrollUp => Ok(vec![Action::HalfPageScrollUp]), + CliAction::HalfPageScrollDown => Ok(vec![Action::HalfPageScrollDown]), + CliAction::ToggleFullscreen => Ok(vec![Action::ToggleFocusFullscreen]), + CliAction::TogglePaneFrames => Ok(vec![Action::TogglePaneFrames]), + CliAction::ToggleActiveSyncTab => Ok(vec![Action::ToggleActiveSyncTab]), + CliAction::NewPane { + direction, + command, + cwd, + floating, + } => match command { + Some(command) => { + let (command, args) = split_command_and_args(command); + let run_command_action = RunCommandAction { + command, + args, + cwd, + direction, + }; + match floating { + Some(true) => Ok(vec![Action::NewFloatingPane(Some(run_command_action))]), + _ => Ok(vec![Action::NewTiledPane( + direction, + Some(run_command_action), + )]), + } + }, + None => match floating { + Some(true) => Ok(vec![Action::NewFloatingPane(None)]), + _ => Ok(vec![Action::NewTiledPane(direction, None)]), + }, + }, + CliAction::Edit { + direction, + file, + line_number, + floating, + } => Ok(vec![Action::EditFile( + file, + line_number, + direction, + floating, + )]), + CliAction::SwitchMode { input_mode } => { + Ok(vec![Action::SwitchModeForAllClients(input_mode)]) + }, + CliAction::TogglePaneEmbedOrFloating => Ok(vec![Action::TogglePaneEmbedOrFloating]), + CliAction::ToggleFloatingPanes => Ok(vec![Action::ToggleFloatingPanes]), + CliAction::ClosePane => Ok(vec![Action::CloseFocus]), + CliAction::RenamePane { name } => Ok(vec![ + Action::UndoRenamePane, + Action::PaneNameInput(name.as_bytes().to_vec()), + ]), + CliAction::UndoRenamePane => Ok(vec![Action::UndoRenamePane]), + CliAction::GoToNextTab => Ok(vec![Action::GoToNextTab]), + CliAction::GoToPreviousTab => Ok(vec![Action::GoToPreviousTab]), + CliAction::CloseTab => Ok(vec![Action::CloseTab]), + CliAction::GoToTab { index } => Ok(vec![Action::GoToTab(index)]), + CliAction::RenameTab { name } => Ok(vec![ + Action::TabNameInput(vec![0]), + Action::TabNameInput(name.as_bytes().to_vec()), + ]), + CliAction::UndoRenameTab => Ok(vec![Action::UndoRenameTab]), + CliAction::NewTab { name, layout } => { + if let Some(layout_path) = layout { + let (path_to_raw_layout, raw_layout) = + Layout::stringified_from_path_or_default(Some(&layout_path), None) + .map_err(|e| format!("Failed to load layout: {}", e))?; + let layout = Layout::from_str(&raw_layout, path_to_raw_layout).map_err(|e| { + let stringified_error = match e { + ConfigError::KdlError(kdl_error) => { + let error = kdl_error.add_src(layout_path.as_path().as_os_str().to_string_lossy().to_string(), String::from(raw_layout)); + let report: Report = error.into(); + format!("{:?}", report) + } + ConfigError::KdlDeserializationError(kdl_error) => { + let error_message = match kdl_error.kind { + kdl::KdlErrorKind::Context("valid node terminator") => { + format!("Failed to deserialize KDL node. \nPossible reasons:\n{}\n{}\n{}\n{}", + "- Missing `;` after a node name, eg. { node; another_node; }", + "- Missing quotations (\") around an argument node eg. { first_node \"argument_node\"; }", + "- Missing an equal sign (=) between node arguments on a title line. eg. argument=\"value\"", + "- Found an extraneous equal sign (=) between node child arguments and their values. eg. { argument=\"value\" }") + }, + _ => String::from(kdl_error.help.unwrap_or("Kdl Deserialization Error")), + }; + let kdl_error = KdlError { + error_message, + src: Some(NamedSource::new(layout_path.as_path().as_os_str().to_string_lossy().to_string(), String::from(raw_layout))), + offset: Some(kdl_error.span.offset()), + len: Some(kdl_error.span.len()), + }; + let report: Report = kdl_error.into(); + format!("{:?}", report) + }, + e => format!("{}", e) + }; + stringified_error + })?; + let mut tabs = layout.tabs(); + if tabs.len() > 1 { + return Err(format!("Tab layout cannot itself have tabs")); + } else if !tabs.is_empty() { + let (tab_name, layout) = tabs.drain(..).next().unwrap(); + let name = tab_name.or(name); + Ok(vec![Action::NewTab(Some(layout), name)]) + } else { + let layout = layout.new_tab(); + Ok(vec![Action::NewTab(Some(layout), name)]) + } + } else { + Ok(vec![Action::NewTab(None, name)]) + } + }, + } + } +} + impl From for Action { fn from(ofc: OnForceClose) -> Action { match ofc { @@ -155,13 +401,3 @@ impl From for Action { } } } - -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct ActionsFromYaml(Vec); - -impl ActionsFromYaml { - /// Get a reference to the actions from yaml's actions. - pub fn actions(&self) -> &[Action] { - self.0.as_ref() - } -} diff --git a/zellij-utils/src/input/config.rs b/zellij-utils/src/input/config.rs index 6d394636..ca161c94 100644 --- a/zellij-utils/src/input/config.rs +++ b/zellij-utils/src/input/config.rs @@ -1,98 +1,135 @@ -//! Deserializes configuration options. -use std::fmt; +use crate::data::Palette; +use miette::{Diagnostic, LabeledSpan, NamedSource, SourceCode}; use std::fs::File; use std::io::{self, Read}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use thiserror::Error; -use serde::{Deserialize, Serialize}; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryFrom; -use super::keybinds::{Keybinds, KeybindsFromYaml}; +use super::keybinds::Keybinds; use super::options::Options; -use super::plugins::{PluginsConfig, PluginsConfigError, PluginsConfigFromYaml}; -use super::theme::{ThemesFromYamlIntermediate, UiConfigFromYaml}; +use super::plugins::{PluginsConfig, PluginsConfigError}; +use super::theme::{Themes, UiConfig}; use crate::cli::{CliArgs, Command}; -use crate::envs::EnvironmentVariablesFromYaml; +use crate::envs::EnvironmentVariables; use crate::setup; -const DEFAULT_CONFIG_FILE_NAME: &str = "config.yaml"; +const DEFAULT_CONFIG_FILE_NAME: &str = "config.kdl"; type ConfigResult = Result; -/// Intermediate deserialization config struct -#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq)] -pub struct ConfigFromYaml { - #[serde(flatten)] - pub options: Option, - pub keybinds: Option, - pub themes: Option, - #[serde(flatten)] - pub env: Option, - #[serde(default)] - pub plugins: PluginsConfigFromYaml, - pub ui: Option, -} - /// Main configuration. -#[derive(Debug, Clone, PartialEq, Deserialize)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct Config { pub keybinds: Keybinds, pub options: Options, - pub themes: Option, + pub themes: Themes, pub plugins: PluginsConfig, - pub ui: Option, - pub env: EnvironmentVariablesFromYaml, + pub ui: UiConfig, + pub env: EnvironmentVariables, } #[derive(Error, Debug)] +pub struct KdlError { + pub error_message: String, + pub src: Option, + pub offset: Option, + pub len: Option, +} + +impl KdlError { + pub fn new_with_location(error_message: String, offset: usize, len: usize) -> Self { + KdlError { + error_message, + src: None, + offset: Some(offset), + len: Some(len), + } + } + pub fn add_src(mut self, src_name: String, src_input: String) -> Self { + self.src = Some(NamedSource::new(src_name, src_input)); + self + } +} + +impl std::fmt::Display for KdlError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "Failed to parse Zellij configuration") + } +} +use std::fmt::Display; + +impl Diagnostic for KdlError { + fn source_code(&self) -> Option<&dyn SourceCode> { + match self.src.as_ref() { + Some(src) => Some(src), + None => None, + } + } + fn help<'a>(&'a self) -> Option> { + // TODO: link to specific relevant sections + Some(Box::new(format!("For more information, please see our configuration guide: https://zellij.dev/documentation/configuration.html"))) + } + fn labels(&self) -> Option + '_>> { + if let (Some(offset), Some(len)) = (self.offset, self.len) { + let label = LabeledSpan::new(Some(self.error_message.clone()), offset, len); + Some(Box::new(std::iter::once(label))) + } else { + None + } + } +} + +#[derive(Error, Debug, Diagnostic)] pub enum ConfigError { // Deserialization error #[error("Deserialization error: {0}")] - Serde(#[from] serde_yaml::Error), + KdlDeserializationError(#[from] kdl::KdlError), + #[error("KdlDeserialization error: {0}")] + KdlError(KdlError), // TODO: consolidate these // Io error #[error("IoError: {0}")] Io(#[from] io::Error), + #[error("Config error: {0}")] + Std(#[from] Box), // Io error with path context #[error("IoError: {0}, File: {1}")] IoPath(io::Error, PathBuf), // Internal Deserialization Error #[error("FromUtf8Error: {0}")] FromUtf8(#[from] std::string::FromUtf8Error), - // Naming a part in a tab is unsupported - #[error("There was an error in the layout file, {0}")] - LayoutNameInTab(#[from] LayoutNameInTabError), // Plugins have a semantic error, usually trying to parse two of the same tag #[error("PluginsError: {0}")] PluginsError(#[from] PluginsConfigError), + #[error("{0}")] + ConversionError(#[from] ConversionError), } -impl Default for Config { - fn default() -> Self { - let keybinds = Keybinds::default(); - let options = Options::default(); - let themes = None; - let env = EnvironmentVariablesFromYaml::default(); - let plugins = PluginsConfig::default(); - let ui = None; - - Config { - keybinds, - options, - themes, - plugins, - env, - ui, - } +impl ConfigError { + pub fn new_kdl_error(error_message: String, offset: usize, len: usize) -> Self { + ConfigError::KdlError(KdlError { + error_message, + src: None, + offset: Some(offset), + len: Some(len), + }) } } +#[derive(Debug, Error)] +pub enum ConversionError { + #[error("{0}")] + UnknownInputMode(String), +} + impl TryFrom<&CliArgs> for Config { type Error = ConfigError; fn try_from(opts: &CliArgs) -> ConfigResult { if let Some(ref path) = opts.config { - return Config::new(path); + let default_config = Config::from_default_assets()?; + return Config::from_path(path, Some(default_config)); } if let Some(Command::Setup(ref setup)) = opts.command { @@ -109,7 +146,8 @@ impl TryFrom<&CliArgs> for Config { if let Some(ref config) = config_dir { let path = config.join(DEFAULT_CONFIG_FILE_NAME); if path.exists() { - Config::new(&path) + let default_config = Config::from_default_assets()?; + Config::from_path(&path, Some(default_config)) } else { Config::from_default_assets() } @@ -120,126 +158,84 @@ impl TryFrom<&CliArgs> for Config { } impl Config { - /// Uses defaults, but lets config override them. - pub fn from_yaml(yaml_config: &str) -> ConfigResult { - let maybe_config_from_yaml: Option = match serde_yaml::from_str(yaml_config) - { - Err(e) => { - // needs direct check, as `[ErrorImpl]` is private - // https://github.com/dtolnay/serde-yaml/issues/121 - if yaml_config.is_empty() { - return Ok(Config::default()); - } - return Err(ConfigError::Serde(e)); - }, - Ok(config) => config, - }; - - match maybe_config_from_yaml { - None => Ok(Config::default()), - Some(config) => config.try_into(), + pub fn theme_config(&self, opts: &Options) -> Option { + match &opts.theme { + Some(theme_name) => self.themes.get_theme(theme_name).map(|theme| theme.palette), + None => self.themes.get_theme("default").map(|theme| theme.palette), } } - - /// Deserializes from given path. - pub fn new(path: &Path) -> ConfigResult { + /// Gets default configuration from assets + pub fn from_default_assets() -> ConfigResult { + let cfg = String::from_utf8(setup::DEFAULT_CONFIG.to_vec())?; + match Self::from_kdl(&cfg, None) { + Ok(config) => Ok(config), + Err(ConfigError::KdlError(kdl_error)) => Err(ConfigError::KdlError( + kdl_error.add_src("Default built-in-configuration".into(), cfg), + )), + Err(e) => Err(e), + } + } + pub fn from_path(path: &PathBuf, default_config: Option) -> ConfigResult { match File::open(path) { Ok(mut file) => { - let mut yaml_config = String::new(); - file.read_to_string(&mut yaml_config) + let mut kdl_config = String::new(); + file.read_to_string(&mut kdl_config) .map_err(|e| ConfigError::IoPath(e, path.to_path_buf()))?; - Ok(Config::from_yaml(&yaml_config)?) + match Config::from_kdl(&kdl_config, default_config) { + Ok(config) => Ok(config), + Err(ConfigError::KdlDeserializationError(kdl_error)) => { + let error_message = match kdl_error.kind { + kdl::KdlErrorKind::Context("valid node terminator") => { + format!("Failed to deserialize KDL node. \nPossible reasons:\n{}\n{}\n{}\n{}", + "- Missing `;` after a node name, eg. { node; another_node; }", + "- Missing quotations (\") around an argument node eg. { first_node \"argument_node\"; }", + "- Missing an equal sign (=) between node arguments on a title line. eg. argument=\"value\"", + "- Found an extraneous equal sign (=) between node child arguments and their values. eg. { argument=\"value\" }") + }, + _ => { + String::from(kdl_error.help.unwrap_or("Kdl Deserialization Error")) + }, + }; + let kdl_error = KdlError { + error_message, + src: Some(NamedSource::new( + path.as_path().as_os_str().to_string_lossy(), + kdl_config, + )), + offset: Some(kdl_error.span.offset()), + len: Some(kdl_error.span.len()), + }; + Err(ConfigError::KdlError(kdl_error)) + }, + Err(ConfigError::KdlError(kdl_error)) => { + Err(ConfigError::KdlError(kdl_error.add_src( + path.as_path().as_os_str().to_string_lossy().to_string(), + kdl_config, + ))) + }, + Err(e) => Err(e), + } }, Err(e) => Err(ConfigError::IoPath(e, path.into())), } } - - /// Gets default configuration from assets - // TODO Deserialize the Config from bytes &[u8], - // once serde-yaml supports zero-copy - pub fn from_default_assets() -> ConfigResult { - let cfg = String::from_utf8(setup::DEFAULT_CONFIG.to_vec())?; - Self::from_yaml(&cfg) - } - - /// Merges two Config structs into one Config struct - /// `other` overrides `self`. - pub fn merge(&self, other: Self) -> Self { - Self { - // TODO: merge keybinds in a way that preserves "unbind" attribute - keybinds: self.keybinds.clone(), - options: self.options.merge(other.options), - themes: self.themes.clone(), // TODO - env: self.env.merge(other.env), - plugins: self.plugins.merge(other.plugins), - ui: self.ui, // TODO - } - } } -impl TryFrom for Config { - type Error = ConfigError; - - fn try_from(config_from_yaml: ConfigFromYaml) -> ConfigResult { - let keybinds = Keybinds::get_default_keybinds_with_config(config_from_yaml.keybinds); - let options = Options::from_yaml(config_from_yaml.options); - let themes = config_from_yaml.themes; - let env = config_from_yaml.env.unwrap_or_default(); - let plugins = PluginsConfig::get_plugins_with_default(config_from_yaml.plugins.try_into()?); - let ui = config_from_yaml.ui; - Ok(Self { - keybinds, - options, - plugins, - themes, - env, - ui, - }) - } -} - -// TODO: Split errors up into separate modules -#[derive(Debug, Clone)] -pub struct LayoutNameInTabError; - -impl fmt::Display for LayoutNameInTabError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "LayoutNameInTabError: -The `parts` inside the `tabs` can't be named. For example: ---- -tabs: - - direction: Vertical - name: main - parts: - - direction: Vertical - name: section # <== The part section can't be named. - - direction: Vertical - - direction: Vertical - name: test -" - ) - } -} - -impl std::error::Error for LayoutNameInTabError { - fn description(&self) -> &str { - "The `parts` inside the `tabs` can't be named." - } -} - -// The unit test location. #[cfg(test)] mod config_test { - use std::io::Write; - - use tempfile::tempdir; - use super::*; + use crate::data::{InputMode, Palette, PaletteColor, PluginTag}; + use crate::input::layout::RunPluginLocation; + use crate::input::options::{Clipboard, OnForceClose}; + use crate::input::plugins::{PluginConfig, PluginType, PluginsConfig}; + use crate::input::theme::{FrameConfig, Theme, Themes, UiConfig}; + use std::collections::HashMap; + use std::io::Write; + use tempfile::tempdir; #[test] fn try_from_cli_args_with_config() { + // makes sure loading a config file with --config tries to load the config let arbitrary_config = PathBuf::from("nonexistent.yaml"); let opts = CliArgs { config: Some(arbitrary_config), @@ -252,6 +248,7 @@ mod config_test { #[test] fn try_from_cli_args_with_option_clean() { + // makes sure --clean works... TODO: how can this actually fail now? use crate::setup::Setup; let opts = CliArgs { command: Some(Command::Setup(Setup { @@ -283,13 +280,387 @@ mod config_test { let tmp = tempdir().unwrap(); opts.config_dir = Some(tmp.path().to_path_buf()); let result = Config::try_from(&opts); - assert_eq!(result.unwrap(), Config::default()); + assert_eq!(result.unwrap(), Config::from_default_assets().unwrap()); } #[test] fn try_from_cli_args_default() { let opts = CliArgs::default(); let result = Config::try_from(&opts); - assert_eq!(result.unwrap(), Config::default()); + assert_eq!(result.unwrap(), Config::from_default_assets().unwrap()); + } + + #[test] + fn can_define_options_in_configfile() { + let config_contents = r#" + simplified_ui true + theme "my cool theme" + default_mode "locked" + default_shell "/path/to/my/shell" + default_layout "/path/to/my/layout.kdl" + layout_dir "/path/to/my/layout-dir" + theme_dir "/path/to/my/theme-dir" + mouse_mode false + pane_frames false + mirror_session true + on_force_close "quit" + scroll_buffer_size 100000 + copy_command "/path/to/my/copy-command" + copy_clipboard "primary" + copy_on_select false + scrollback_editor "/path/to/my/scrollback-editor" + session_name "my awesome session" + attach_to_session true + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + assert_eq!( + config.options.simplified_ui, + Some(true), + "Option set in config" + ); + assert_eq!( + config.options.theme, + Some(String::from("my cool theme")), + "Option set in config" + ); + assert_eq!( + config.options.default_mode, + Some(InputMode::Locked), + "Option set in config" + ); + assert_eq!( + config.options.default_shell, + Some(PathBuf::from("/path/to/my/shell")), + "Option set in config" + ); + assert_eq!( + config.options.default_layout, + Some(PathBuf::from("/path/to/my/layout.kdl")), + "Option set in config" + ); + assert_eq!( + config.options.layout_dir, + Some(PathBuf::from("/path/to/my/layout-dir")), + "Option set in config" + ); + assert_eq!( + config.options.theme_dir, + Some(PathBuf::from("/path/to/my/theme-dir")), + "Option set in config" + ); + assert_eq!( + config.options.mouse_mode, + Some(false), + "Option set in config" + ); + assert_eq!( + config.options.pane_frames, + Some(false), + "Option set in config" + ); + assert_eq!( + config.options.mirror_session, + Some(true), + "Option set in config" + ); + assert_eq!( + config.options.on_force_close, + Some(OnForceClose::Quit), + "Option set in config" + ); + assert_eq!( + config.options.scroll_buffer_size, + Some(100000), + "Option set in config" + ); + assert_eq!( + config.options.copy_command, + Some(String::from("/path/to/my/copy-command")), + "Option set in config" + ); + assert_eq!( + config.options.copy_clipboard, + Some(Clipboard::Primary), + "Option set in config" + ); + assert_eq!( + config.options.copy_on_select, + Some(false), + "Option set in config" + ); + assert_eq!( + config.options.scrollback_editor, + Some(PathBuf::from("/path/to/my/scrollback-editor")), + "Option set in config" + ); + assert_eq!( + config.options.session_name, + Some(String::from("my awesome session")), + "Option set in config" + ); + assert_eq!( + config.options.attach_to_session, + Some(true), + "Option set in config" + ); + } + + #[test] + fn can_define_themes_in_configfile() { + let config_contents = r#" + themes { + dracula { + fg 248 248 242 + bg 40 42 54 + red 255 85 85 + green 80 250 123 + yellow 241 250 140 + blue 98 114 164 + magenta 255 121 198 + orange 255 184 108 + cyan 139 233 253 + black 0 0 0 + white 255 255 255 + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let mut expected_themes = HashMap::new(); + expected_themes.insert( + "dracula".into(), + Theme { + palette: Palette { + fg: PaletteColor::Rgb((248, 248, 242)), + bg: PaletteColor::Rgb((40, 42, 54)), + red: PaletteColor::Rgb((255, 85, 85)), + green: PaletteColor::Rgb((80, 250, 123)), + yellow: PaletteColor::Rgb((241, 250, 140)), + blue: PaletteColor::Rgb((98, 114, 164)), + magenta: PaletteColor::Rgb((255, 121, 198)), + orange: PaletteColor::Rgb((255, 184, 108)), + cyan: PaletteColor::Rgb((139, 233, 253)), + black: PaletteColor::Rgb((0, 0, 0)), + white: PaletteColor::Rgb((255, 255, 255)), + ..Default::default() + }, + }, + ); + let expected_themes = Themes::from_data(expected_themes); + assert_eq!(config.themes, expected_themes, "Theme defined in config"); + } + + #[test] + fn can_define_multiple_themes_including_hex_themes_in_configfile() { + let config_contents = r##" + themes { + dracula { + fg 248 248 242 + bg 40 42 54 + red 255 85 85 + green 80 250 123 + yellow 241 250 140 + blue 98 114 164 + magenta 255 121 198 + orange 255 184 108 + cyan 139 233 253 + black 0 0 0 + white 255 255 255 + } + nord { + fg "#D8DEE9" + bg "#2E3440" + black "#3B4252" + red "#BF616A" + green "#A3BE8C" + yellow "#EBCB8B" + blue "#81A1C1" + magenta "#B48EAD" + cyan "#88C0D0" + white "#E5E9F0" + orange "#D08770" + } + } + "##; + let config = Config::from_kdl(config_contents, None).unwrap(); + let mut expected_themes = HashMap::new(); + expected_themes.insert( + "dracula".into(), + Theme { + palette: Palette { + fg: PaletteColor::Rgb((248, 248, 242)), + bg: PaletteColor::Rgb((40, 42, 54)), + red: PaletteColor::Rgb((255, 85, 85)), + green: PaletteColor::Rgb((80, 250, 123)), + yellow: PaletteColor::Rgb((241, 250, 140)), + blue: PaletteColor::Rgb((98, 114, 164)), + magenta: PaletteColor::Rgb((255, 121, 198)), + orange: PaletteColor::Rgb((255, 184, 108)), + cyan: PaletteColor::Rgb((139, 233, 253)), + black: PaletteColor::Rgb((0, 0, 0)), + white: PaletteColor::Rgb((255, 255, 255)), + ..Default::default() + }, + }, + ); + expected_themes.insert( + "nord".into(), + Theme { + palette: Palette { + fg: PaletteColor::Rgb((216, 222, 233)), + bg: PaletteColor::Rgb((46, 52, 64)), + black: PaletteColor::Rgb((59, 66, 82)), + red: PaletteColor::Rgb((191, 97, 106)), + green: PaletteColor::Rgb((163, 190, 140)), + yellow: PaletteColor::Rgb((235, 203, 139)), + blue: PaletteColor::Rgb((129, 161, 193)), + magenta: PaletteColor::Rgb((180, 142, 173)), + cyan: PaletteColor::Rgb((136, 192, 208)), + white: PaletteColor::Rgb((229, 233, 240)), + orange: PaletteColor::Rgb((208, 135, 112)), + ..Default::default() + }, + }, + ); + let expected_themes = Themes::from_data(expected_themes); + assert_eq!(config.themes, expected_themes, "Theme defined in config"); + } + + #[test] + fn can_define_eight_bit_themes() { + let config_contents = r#" + themes { + eight_bit_theme { + fg 248 + bg 40 + red 255 + green 80 + yellow 241 + blue 98 + magenta 255 + orange 255 + cyan 139 + black 1 + white 255 + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let mut expected_themes = HashMap::new(); + expected_themes.insert( + "eight_bit_theme".into(), + Theme { + palette: Palette { + fg: PaletteColor::EightBit(248), + bg: PaletteColor::EightBit(40), + red: PaletteColor::EightBit(255), + green: PaletteColor::EightBit(80), + yellow: PaletteColor::EightBit(241), + blue: PaletteColor::EightBit(98), + magenta: PaletteColor::EightBit(255), + orange: PaletteColor::EightBit(255), + cyan: PaletteColor::EightBit(139), + black: PaletteColor::EightBit(1), + white: PaletteColor::EightBit(255), + ..Default::default() + }, + }, + ); + let expected_themes = Themes::from_data(expected_themes); + assert_eq!(config.themes, expected_themes, "Theme defined in config"); + } + + #[test] + fn can_define_plugin_configuration_in_configfile() { + let config_contents = r#" + plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { + path "strider" + _allow_exec_host_cmd true + } + compact-bar { path "compact-bar"; } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let mut expected_plugin_configuration = HashMap::new(); + expected_plugin_configuration.insert( + PluginTag::new("tab-bar"), + PluginConfig { + path: PathBuf::from("tab-bar"), + run: PluginType::Pane(None), + location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), + _allow_exec_host_cmd: false, + }, + ); + expected_plugin_configuration.insert( + PluginTag::new("status-bar"), + PluginConfig { + path: PathBuf::from("status-bar"), + run: PluginType::Pane(None), + location: RunPluginLocation::Zellij(PluginTag::new("status-bar")), + _allow_exec_host_cmd: false, + }, + ); + expected_plugin_configuration.insert( + PluginTag::new("strider"), + PluginConfig { + path: PathBuf::from("strider"), + run: PluginType::Pane(None), + location: RunPluginLocation::Zellij(PluginTag::new("strider")), + _allow_exec_host_cmd: true, + }, + ); + expected_plugin_configuration.insert( + PluginTag::new("compact-bar"), + PluginConfig { + path: PathBuf::from("compact-bar"), + run: PluginType::Pane(None), + location: RunPluginLocation::Zellij(PluginTag::new("compact-bar")), + _allow_exec_host_cmd: false, + }, + ); + assert_eq!( + config.plugins, + PluginsConfig::from_data(expected_plugin_configuration), + "Plugins defined in config" + ); + } + + #[test] + fn can_define_ui_configuration_in_configfile() { + let config_contents = r#" + ui { + pane_frames { + rounded_corners true + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let expected_ui_config = UiConfig { + pane_frames: FrameConfig { + rounded_corners: true, + }, + }; + assert_eq!(config.ui, expected_ui_config, "Ui config defined in config"); + } + + #[test] + fn can_define_env_variables_in_config_file() { + let config_contents = r#" + env { + RUST_BACKTRACE 1 + SOME_OTHER_VAR "foo" + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let mut expected_env_config = HashMap::new(); + expected_env_config.insert("RUST_BACKTRACE".into(), "1".into()); + expected_env_config.insert("SOME_OTHER_VAR".into(), "foo".into()); + assert_eq!( + config.env, + EnvironmentVariables::from_data(expected_env_config), + "Env variables defined in config" + ); } } diff --git a/zellij-utils/src/input/keybinds.rs b/zellij-utils/src/input/keybinds.rs index 6e6f2ab9..eaed03fd 100644 --- a/zellij-utils/src/input/keybinds.rs +++ b/zellij-utils/src/input/keybinds.rs @@ -1,326 +1,70 @@ -//! Mapping of inputs to sequences of actions. use std::collections::{BTreeMap, HashMap}; use super::actions::Action; -use super::config; use crate::data::{InputMode, Key, KeybindsVec}; use serde::{Deserialize, Serialize}; -use strum::IntoEnumIterator; +use std::fmt; /// Used in the config struct -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct Keybinds(HashMap); -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct ModeKeybinds(BTreeMap>); +#[derive(Clone, PartialEq, Deserialize, Serialize, Default)] +pub struct Keybinds(pub HashMap>>); -/// Intermediate struct used for deserialisation -/// Used in the config file. -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct KeybindsFromYaml { - #[serde(flatten)] - keybinds: HashMap>, - #[serde(default)] - unbind: Unbind, -} - -/// Intermediate enum used for deserialisation -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -#[serde(untagged)] -enum KeyActionUnbind { - KeyAction(KeyActionFromYaml), - Unbind(UnbindFromYaml), -} - -/// Intermediate struct used for deserialisation -#[derive(Clone, Debug, PartialEq, Deserialize)] -struct KeyActionUnbindFromYaml { - keybinds: Vec, - unbind: Unbind, -} - -/// Intermediate struct used for deserialisation -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct KeyActionFromYaml { - action: Vec, - key: Vec, -} - -/// Intermediate struct used for deserialisation -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -struct UnbindFromYaml { - unbind: Unbind, -} - -/// List of keys, for which to disable their respective default actions -/// `All` is a catch all, and will disable the default actions for all keys. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] -#[serde(untagged)] -enum Unbind { - // This is the correct order, don't rearrange! - // Suspected Bug in the untagged macro. - // 1. Keys - Keys(Vec), - // 2. All - All(bool), -} - -impl Default for Keybinds { - // Use once per codepath - // TODO investigate why - fn default() -> Keybinds { - Self::from_default_assets() +impl fmt::Debug for Keybinds { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut stable_sorted = BTreeMap::new(); + for (mode, keybinds) in self.0.iter() { + let mut stable_sorted_mode_keybinds = BTreeMap::new(); + for (key, actions) in keybinds { + stable_sorted_mode_keybinds.insert(key, actions); + } + stable_sorted.insert(mode, stable_sorted_mode_keybinds); + } + write!(f, "{:#?}", stable_sorted) } } impl Keybinds { - pub fn new() -> Keybinds { - Keybinds(HashMap::::new()) + pub fn get_actions_for_key_in_mode(&self, mode: &InputMode, key: &Key) -> Option<&Vec> { + self.0 + .get(mode) + .and_then(|normal_mode_keybindings| normal_mode_keybindings.get(key)) } - - fn from_default_assets() -> Keybinds { - config::Config::from_default_assets() - .expect("Keybinds from default assets Error!") - .keybinds + pub fn get_actions_for_key_in_mode_or_default_action( + &self, + mode: &InputMode, + key: &Key, + raw_bytes: Vec, + ) -> Vec { + self.0 + .get(mode) + .and_then(|normal_mode_keybindings| normal_mode_keybindings.get(key)) + .cloned() + .unwrap_or_else(|| vec![self.default_action_for_mode(mode, raw_bytes)]) + } + pub fn get_input_mode_mut(&mut self, input_mode: &InputMode) -> &mut HashMap> { + self.0.entry(*input_mode).or_insert_with(HashMap::new) + } + pub fn default_action_for_mode(&self, mode: &InputMode, raw_bytes: Vec) -> Action { + match *mode { + InputMode::Normal | InputMode::Locked => Action::Write(raw_bytes), + InputMode::RenameTab => Action::TabNameInput(raw_bytes), + InputMode::RenamePane => Action::PaneNameInput(raw_bytes), + InputMode::EnterSearch => Action::SearchInput(raw_bytes), + _ => Action::NoOp, + } } - pub fn to_keybinds_vec(&self) -> KeybindsVec { let mut ret = vec![]; for (mode, mode_binds) in &self.0 { - ret.push((*mode, mode_binds.to_cloned_vec())); + let mut mode_binds_vec: Vec<(Key, Vec)> = vec![]; + for (key, actions) in mode_binds { + mode_binds_vec.push((key.clone(), actions.clone())); + } + ret.push((*mode, mode_binds_vec)) } ret } - - pub fn get_mode_keybinds(&self, mode: &InputMode) -> &ModeKeybinds { - self.0 - .get(mode) - .expect("Failed to get Keybinds for current mode") - } - - /// Entrypoint from the config module - pub fn get_default_keybinds_with_config(from_yaml: Option) -> Keybinds { - let default_keybinds = match from_yaml.clone() { - Some(keybinds) => match keybinds.unbind { - Unbind::All(true) => Keybinds::new(), - Unbind::All(false) | Unbind::Keys(_) => Keybinds::unbind(keybinds), - }, - None => Keybinds::default(), - }; - - if let Some(keybinds) = from_yaml { - default_keybinds.merge_keybinds(Keybinds::from(keybinds)) - } else { - default_keybinds - } - } - - /// Unbinds the default keybindings in relation to their mode - fn unbind(from_yaml: KeybindsFromYaml) -> Keybinds { - let mut keybind_config = Self::new(); - let mut unbind_config: HashMap = HashMap::new(); - let keybinds_from_yaml = from_yaml.keybinds; - - for mode in InputMode::iter() { - if let Some(keybinds) = keybinds_from_yaml.get(&mode) { - for keybind in keybinds { - match keybind { - KeyActionUnbind::Unbind(unbind) => { - unbind_config.insert(mode, unbind.unbind.clone()); - }, - KeyActionUnbind::KeyAction(key_action_from_yaml) => { - keybind_config - .0 - .insert(mode, ModeKeybinds::from(key_action_from_yaml.clone())); - }, - } - } - } - } - - let mut default = Self::default().unbind_mode(unbind_config); - - // Toplevel Unbinds - if let Unbind::Keys(_) = from_yaml.unbind { - let mut unbind_config: HashMap = HashMap::new(); - for mode in InputMode::iter() { - unbind_config.insert(mode, from_yaml.unbind.clone()); - } - default = default.unbind_mode(unbind_config); - }; - - default.merge_keybinds(keybind_config) - } - - /// Unbind [`Key`] bindings respective to their mode - fn unbind_mode(&self, unbind: HashMap) -> Keybinds { - let mut keybinds = Keybinds::new(); - - for mode in InputMode::iter() { - if let Some(unbind) = unbind.get(&mode) { - match unbind { - Unbind::All(true) => {}, - Unbind::Keys(keys) => { - if let Some(defaults) = self.0.get(&mode) { - keybinds - .0 - .insert(mode, defaults.clone().unbind_keys(keys.to_vec())); - } - }, - Unbind::All(false) => { - if let Some(defaults) = self.0.get(&mode) { - keybinds.0.insert(mode, defaults.clone()); - } - }, - } - } else if let Some(defaults) = self.0.get(&mode) { - keybinds.0.insert(mode, defaults.clone()); - } - } - keybinds - } - - /// Merges two Keybinds structs into one Keybinds struct - /// `other` overrides the ModeKeybinds of `self`. - pub fn merge_keybinds(&self, other: Keybinds) -> Keybinds { - let mut keybinds = Keybinds::new(); - - for mode in InputMode::iter() { - let mut mode_keybinds = ModeKeybinds::new(); - if let Some(keybind) = self.0.get(&mode) { - mode_keybinds.0.extend(keybind.0.clone()); - }; - if let Some(keybind) = other.0.get(&mode) { - mode_keybinds.0.extend(keybind.0.clone()); - } - if !mode_keybinds.0.is_empty() { - keybinds.0.insert(mode, mode_keybinds); - } - } - keybinds - } - - /// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current - /// [`InputMode`] and [`Keybinds`]. - pub fn key_to_actions( - key: &Key, - raw_bytes: Vec, - mode: &InputMode, - keybinds: &Keybinds, - ) -> Vec { - let mode_keybind_or_action = |action: Action| { - keybinds - .0 - .get(mode) - .unwrap_or({ - // create a dummy mode to recover from - &ModeKeybinds::new() - }) - .0 - .get(key) - .cloned() - .unwrap_or_else(|| vec![action]) - }; - match *mode { - InputMode::Normal | InputMode::Locked => { - mode_keybind_or_action(Action::Write(raw_bytes)) - }, - InputMode::RenameTab => mode_keybind_or_action(Action::TabNameInput(raw_bytes)), - InputMode::RenamePane => mode_keybind_or_action(Action::PaneNameInput(raw_bytes)), - InputMode::EnterSearch => mode_keybind_or_action(Action::SearchInput(raw_bytes)), - _ => mode_keybind_or_action(Action::NoOp), - } - } -} - -impl ModeKeybinds { - fn new() -> ModeKeybinds { - ModeKeybinds(BTreeMap::>::new()) - } - - /// Merges `self` with `other`, if keys are the same, `other` overwrites. - fn merge(self, other: ModeKeybinds) -> ModeKeybinds { - let mut merged = self; - merged.0.extend(other.0); - merged - } - - /// Remove [`Key`]'s from [`ModeKeybinds`] - fn unbind_keys(self, unbind: Vec) -> Self { - let mut keymap = self; - for key in unbind { - keymap.0.remove(&key); - } - keymap - } - - pub fn to_cloned_vec(&self) -> Vec<(Key, Vec)> { - self.0 - .iter() - .map(|(key, vac)| (*key, vac.clone())) - .collect() - } -} - -impl From for Keybinds { - fn from(keybinds_from_yaml: KeybindsFromYaml) -> Keybinds { - let mut keybinds = Keybinds::new(); - - for mode in InputMode::iter() { - let mut mode_keybinds = ModeKeybinds::new(); - if let Some(key_action) = keybinds_from_yaml.keybinds.get(&mode) { - for keybind in key_action { - mode_keybinds = mode_keybinds.merge(ModeKeybinds::from(keybind.clone())); - } - } - keybinds.0.insert(mode, mode_keybinds); - } - keybinds - } -} - -/// For each [`Key`] assigned to [`Action`]s, -/// map the [`Action`]s to the [`Key`] -impl From for ModeKeybinds { - fn from(key_action: KeyActionFromYaml) -> ModeKeybinds { - let actions = key_action.action; - - ModeKeybinds( - key_action - .key - .into_iter() - .map(|k| (k, actions.clone())) - .collect::>>(), - ) - } -} - -impl From for ModeKeybinds { - fn from(key_action_unbind: KeyActionUnbind) -> ModeKeybinds { - match key_action_unbind { - KeyActionUnbind::KeyAction(key_action) => ModeKeybinds::from(key_action), - KeyActionUnbind::Unbind(_) => ModeKeybinds::new(), - } - } -} - -impl From> for ModeKeybinds { - fn from(key_action_from_yaml: Vec) -> ModeKeybinds { - let mut mode_keybinds = ModeKeybinds::new(); - - for keybind in key_action_from_yaml { - for key in keybind.key { - mode_keybinds.0.insert(key, keybind.action.clone()); - } - } - mode_keybinds - } -} - -impl Default for Unbind { - fn default() -> Unbind { - Unbind::All(false) - } } // The unit test location. diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 3f0b3929..eea80859 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -11,22 +11,20 @@ use crate::{ input::{ command::RunCommand, - config::{ConfigError, LayoutNameInTabError}, + config::{Config, ConfigError}, }, pane_size::{Dimension, PaneGeom}, setup, }; -use super::{ - config::ConfigFromYaml, - plugins::{PluginTag, PluginsConfigError}, -}; +use std::str::FromStr; + +use super::plugins::{PluginTag, PluginsConfigError}; use serde::{Deserialize, Serialize}; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryFrom; use std::vec::Vec; use std::{ - cmp::max, - fmt, fs, + fmt, ops::Not, path::{Path, PathBuf}, }; @@ -34,20 +32,18 @@ use std::{fs::File, io::prelude::*}; use url::Url; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)] -pub enum Direction { - #[serde(alias = "horizontal")] +pub enum SplitDirection { Horizontal, - #[serde(alias = "vertical")] Vertical, } -impl Not for Direction { +impl Not for SplitDirection { type Output = Self; fn not(self) -> Self::Output { match self { - Direction::Horizontal => Direction::Vertical, - Direction::Vertical => Direction::Horizontal, + SplitDirection::Horizontal => SplitDirection::Vertical, + SplitDirection::Vertical => SplitDirection::Horizontal, } } } @@ -55,7 +51,7 @@ impl Not for Direction { #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] pub enum SplitSize { #[serde(alias = "percent")] - Percent(u64), // 1 to 100 + Percent(usize), // 1 to 100 #[serde(alias = "fixed")] Fixed(usize), // An absolute number of columns or rows } @@ -68,21 +64,6 @@ pub enum Run { Command(RunCommand), } -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub enum RunFromYaml { - #[serde(rename = "plugin")] - Plugin(RunPluginFromYaml), - #[serde(rename = "command")] - Command(RunCommand), -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub struct RunPluginFromYaml { - #[serde(default)] - pub _allow_exec_host_cmd: bool, - pub location: Url, -} - #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct RunPlugin { #[serde(default)] @@ -123,487 +104,292 @@ impl fmt::Display for RunPluginLocation { } } -// The layout struct ultimately used to build the layouts. -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)] pub struct Layout { - pub direction: Direction, - #[serde(default)] - pub pane_name: Option, - #[serde(default)] - pub parts: Vec, + pub tabs: Vec<(Option, PaneLayout)>, + pub focused_tab_index: Option, + pub template: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)] +pub struct PaneLayout { + pub children_split_direction: SplitDirection, + pub name: Option, + pub children: Vec, pub split_size: Option, pub run: Option, - #[serde(default)] pub borderless: bool, pub focus: Option, + pub external_children_index: Option, } -// The struct that is used to deserialize the layout from -// a yaml configuration file, is needed because of: -// https://github.com/bincode-org/bincode/issues/245 -// flattened fields don't retain size information. -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(default)] -pub struct LayoutFromYamlIntermediate { - #[serde(default)] - pub template: LayoutTemplate, - #[serde(default)] - pub borderless: bool, - #[serde(default)] - pub tabs: Vec, - #[serde(default)] - pub session: SessionFromYaml, - #[serde(flatten)] - pub config: Option, -} - -// The struct that is used to deserialize the layout from -// a yaml configuration file -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] -#[serde(default)] -pub struct LayoutFromYaml { - #[serde(default)] - pub session: SessionFromYaml, - #[serde(default)] - pub template: LayoutTemplate, - #[serde(default)] - pub borderless: bool, - #[serde(default)] - pub tabs: Vec, -} - -type LayoutFromYamlIntermediateResult = Result; - -impl LayoutFromYamlIntermediate { - pub fn from_path(layout_path: &Path) -> LayoutFromYamlIntermediateResult { - let mut layout_file = File::open(&layout_path) - .or_else(|_| File::open(&layout_path.with_extension("yaml"))) - .map_err(|e| ConfigError::IoPath(e, layout_path.into()))?; - - let mut layout = String::new(); - layout_file.read_to_string(&mut layout)?; - let layout: Option = match serde_yaml::from_str(&layout) { - Err(e) => { - // needs direct check, as `[ErrorImpl]` is private - // https://github.com/dtolnay/serde-yaml/issues/121 - if layout.is_empty() { - return Ok(LayoutFromYamlIntermediate::default()); - } - return Err(ConfigError::Serde(e)); +impl PaneLayout { + pub fn insert_children_layout( + &mut self, + children_layout: &mut PaneLayout, + ) -> Result { + // returns true if successfully inserted and false otherwise + match self.external_children_index { + Some(external_children_index) => { + self.children + .insert(external_children_index, children_layout.clone()); + self.external_children_index = None; + Ok(true) }, - Ok(config) => config, - }; - - match layout { - Some(layout) => { - for tab in layout.tabs.clone() { - tab.check()?; + None => { + for pane in self.children.iter_mut() { + if pane.insert_children_layout(children_layout)? { + return Ok(true); + } } - Ok(layout) + Ok(false) }, - None => Ok(LayoutFromYamlIntermediate::default()), } } - - pub fn from_yaml(yaml: &str) -> LayoutFromYamlIntermediateResult { - let layout: LayoutFromYamlIntermediate = match serde_yaml::from_str(yaml) { - Err(e) => { - // needs direct check, as `[ErrorImpl]` is private - // https://github.com/dtolnay/serde-yaml/issues/121 - if yaml.is_empty() { - return Ok(LayoutFromYamlIntermediate::default()); - } - return Err(ConfigError::Serde(e)); - }, - Ok(config) => config, - }; - Ok(layout) - } - - pub fn to_layout_and_config(&self) -> (LayoutFromYaml, Option) { - let config = self.config.clone(); - let layout = self.clone().into(); - (layout, config) - } - - pub fn from_path_or_default( - layout: Option<&PathBuf>, - layout_dir: Option, - ) -> Option { - layout - .map(|layout| { - // The way we determine where to look for the layout is similar to - // how a path would look for an executable. - // See the gh issue for more: https://github.com/zellij-org/zellij/issues/1412#issuecomment-1131559720 - if layout.extension().is_some() || layout.components().count() > 1 { - // We look localy! - LayoutFromYamlIntermediate::from_path(layout) - } else { - // We look in the default dir - LayoutFromYamlIntermediate::from_dir(layout, layout_dir.as_ref()) - } - }) - .or_else(|| { - Some(LayoutFromYamlIntermediate::from_dir( - &std::path::PathBuf::from("default"), - layout_dir.as_ref(), - )) - }) - } - - // It wants to use Path here, but that doesn't compile. - #[allow(clippy::ptr_arg)] - pub fn from_dir( - layout: &PathBuf, - layout_dir: Option<&PathBuf>, - ) -> LayoutFromYamlIntermediateResult { - match layout_dir { - Some(dir) => { - let layout_path = &dir.join(layout); - if layout_path.with_extension("yaml").exists() { - Self::from_path(layout_path) - } else { - LayoutFromYamlIntermediate::from_default_assets(layout) - } - }, - None => LayoutFromYamlIntermediate::from_default_assets(layout), + pub fn children_block_count(&self) -> usize { + let mut count = 0; + if self.external_children_index.is_some() { + count += 1; } - } - // Currently still needed but on nightly - // this is already possible: - // HashMap<&'static str, Vec> - pub fn from_default_assets(path: &Path) -> LayoutFromYamlIntermediateResult { - match path.to_str() { - Some("default") => Self::default_from_assets(), - Some("strider") => Self::strider_from_assets(), - Some("disable-status-bar") => Self::disable_status_from_assets(), - Some("compact") => Self::compact_from_assets(), - None | Some(_) => Err(ConfigError::IoPath( - std::io::Error::new(std::io::ErrorKind::Other, "The layout was not found"), - path.into(), - )), + for pane in &self.children { + count += pane.children_block_count(); } + count } - - // TODO Deserialize the assets from bytes &[u8], - // once serde-yaml supports zero-copy - pub fn default_from_assets() -> LayoutFromYamlIntermediateResult { - let layout: LayoutFromYamlIntermediate = - serde_yaml::from_str(&String::from_utf8(setup::DEFAULT_LAYOUT.to_vec())?)?; - Ok(layout) + pub fn position_panes_in_space(&self, space: &PaneGeom) -> Vec<(PaneLayout, PaneGeom)> { + split_space(space, self, space) } - - pub fn strider_from_assets() -> LayoutFromYamlIntermediateResult { - let layout: LayoutFromYamlIntermediate = - serde_yaml::from_str(&String::from_utf8(setup::STRIDER_LAYOUT.to_vec())?)?; - Ok(layout) + pub fn extract_run_instructions(&self) -> Vec> { + let mut run_instructions = vec![]; + if self.children.is_empty() { + run_instructions.push(self.run.clone()); + } + for child in &self.children { + let mut child_run_instructions = child.extract_run_instructions(); + run_instructions.append(&mut child_run_instructions); + } + run_instructions } - - pub fn disable_status_from_assets() -> LayoutFromYamlIntermediateResult { - let layout: LayoutFromYamlIntermediate = - serde_yaml::from_str(&String::from_utf8(setup::NO_STATUS_LAYOUT.to_vec())?)?; - Ok(layout) - } - - pub fn compact_from_assets() -> LayoutFromYamlIntermediateResult { - let layout: LayoutFromYamlIntermediate = - serde_yaml::from_str(&String::from_utf8(setup::COMPACT_BAR_LAYOUT.to_vec())?)?; - Ok(layout) + pub fn with_one_pane() -> Self { + let mut default_layout = PaneLayout::default(); + default_layout.children = vec![PaneLayout::default()]; + default_layout } } -type LayoutFromYamlResult = Result; - -impl LayoutFromYaml { - pub fn new(layout_path: &Path) -> LayoutFromYamlResult { - let mut layout_file = File::open(&layout_path) - .or_else(|_| File::open(&layout_path.with_extension("yaml"))) - .map_err(|e| ConfigError::IoPath(e, layout_path.into()))?; - - let mut layout = String::new(); - layout_file.read_to_string(&mut layout)?; - let layout: Option = match serde_yaml::from_str(&layout) { - Err(e) => { - // needs direct check, as `[ErrorImpl]` is private - // https://github.com/dtolnay/serde-yaml/issues/121 - if layout.is_empty() { - return Ok(LayoutFromYaml::default()); - } - return Err(ConfigError::Serde(e)); - }, - Ok(config) => config, - }; - - match layout { - Some(layout) => { - for tab in layout.tabs.clone() { - tab.check()?; - } - Ok(layout) - }, - None => Ok(LayoutFromYaml::default()), - } - } - - // It wants to use Path here, but that doesn't compile. - #[allow(clippy::ptr_arg)] - pub fn from_dir(layout: &PathBuf, layout_dir: Option<&PathBuf>) -> LayoutFromYamlResult { - match layout_dir { - Some(dir) => { - Self::new(&dir.join(layout)).or_else(|_| Self::from_default_assets(layout)) - }, - None => Self::from_default_assets(layout), - } - } - - pub fn from_path_or_default( - layout: Option<&PathBuf>, - layout_path: Option<&PathBuf>, - layout_dir: Option, - ) -> Option { - layout - .map(|p| LayoutFromYaml::from_dir(p, layout_dir.as_ref())) - .or_else(|| layout_path.map(|p| LayoutFromYaml::new(p))) - .or_else(|| { - Some(LayoutFromYaml::from_dir( - &std::path::PathBuf::from("default"), - layout_dir.as_ref(), - )) - }) - } - - // Currently still needed but on nightly - // this is already possible: - // HashMap<&'static str, Vec> - pub fn from_default_assets(path: &Path) -> LayoutFromYamlResult { - match path.to_str() { - Some("default") => Self::default_from_assets(), - Some("strider") => Self::strider_from_assets(), - Some("disable-status-bar") => Self::disable_status_from_assets(), - None | Some(_) => Err(ConfigError::IoPath( - std::io::Error::new(std::io::ErrorKind::Other, "The layout was not found"), - path.into(), - )), - } - } - - // TODO Deserialize the assets from bytes &[u8], - // once serde-yaml supports zero-copy - pub fn default_from_assets() -> LayoutFromYamlResult { - let layout: LayoutFromYaml = - serde_yaml::from_str(&String::from_utf8(setup::DEFAULT_LAYOUT.to_vec())?)?; - Ok(layout) - } - - pub fn strider_from_assets() -> LayoutFromYamlResult { - let layout: LayoutFromYaml = - serde_yaml::from_str(&String::from_utf8(setup::STRIDER_LAYOUT.to_vec())?)?; - Ok(layout) - } - - pub fn disable_status_from_assets() -> LayoutFromYamlResult { - let layout: LayoutFromYaml = - serde_yaml::from_str(&String::from_utf8(setup::NO_STATUS_LAYOUT.to_vec())?)?; - Ok(layout) - } -} - -// The struct that is used to deserialize the session from -// a yaml configuration file -#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] -pub struct SessionFromYaml { - pub name: Option, - #[serde(default = "default_as_some_true")] - pub attach: Option, -} - -fn default_as_some_true() -> Option { - Some(true) -} - -// The struct that carries the information template that is used to -// construct the layout -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub struct LayoutTemplate { - pub direction: Direction, - #[serde(default)] - pub pane_name: Option, - #[serde(default)] - pub borderless: bool, - #[serde(default)] - pub parts: Vec, - #[serde(default)] - pub body: bool, - pub split_size: Option, - pub focus: Option, - pub run: Option, -} - -impl LayoutTemplate { - // Insert an optional `[TabLayout]` at the correct position - pub fn insert_tab_layout(mut self, tab_layout: Option) -> Self { - if self.body { - return tab_layout.unwrap_or_default().into(); - } - for (i, part) in self.parts.clone().iter().enumerate() { - if part.body { - self.parts.push(tab_layout.unwrap_or_default().into()); - self.parts.swap_remove(i); - break; - } - // recurse - let new_part = part.clone().insert_tab_layout(tab_layout.clone()); - self.parts.push(new_part); - self.parts.swap_remove(i); - } - self - } - - fn from_vec_tab_layout(tab_layout: Vec) -> Vec { - tab_layout - .iter() - .map(|tab_layout| Self::from(tab_layout.to_owned())) - .collect() - } -} - -// The tab-layout struct used to specify each individual tab. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub struct TabLayout { - #[serde(default)] - pub direction: Direction, - pub pane_name: Option, - #[serde(default)] - pub borderless: bool, - #[serde(default)] - pub parts: Vec, - pub split_size: Option, - #[serde(default)] - pub name: String, - pub focus: Option, - pub run: Option, +pub enum LayoutParts { + Tabs(Vec<(Option, Layout)>), // String is the tab name + Panes(Vec), } -impl TabLayout { - fn check(&self) -> Result { - for part in &self.parts { - part.check()?; - if !part.name.is_empty() { - return Err(ConfigError::LayoutNameInTab(LayoutNameInTabError)); - } +impl LayoutParts { + pub fn is_empty(&self) -> bool { + match self { + LayoutParts::Panes(panes) => panes.is_empty(), + LayoutParts::Tabs(tabs) => tabs.is_empty(), } - Ok(self.clone()) + } + pub fn insert_pane(&mut self, index: usize, layout: Layout) -> Result<(), ConfigError> { + match self { + LayoutParts::Panes(panes) => { + panes.insert(index, layout); + Ok(()) + }, + LayoutParts::Tabs(_tabs) => Err(ConfigError::new_kdl_error( + "Trying to insert a pane into a tab layout".into(), + 0, + 0, + )), + } + } +} + +impl Default for LayoutParts { + fn default() -> Self { + LayoutParts::Panes(vec![]) } } impl Layout { - pub fn total_terminal_panes(&self) -> usize { - let mut total_panes = 0; - total_panes += self.parts.len(); - for part in &self.parts { - match part.run { - Some(Run::Command(_)) | None => { - total_panes += part.total_terminal_panes(); - }, - Some(Run::Plugin(_)) => {}, - } + pub fn stringified_from_path_or_default( + layout_path: Option<&PathBuf>, + layout_dir: Option, + ) -> Result<(String, String), ConfigError> { + // (path_to_layout as String, stringified_layout) + match layout_path { + Some(layout_path) => { + // The way we determine where to look for the layout is similar to + // how a path would look for an executable. + // See the gh issue for more: https://github.com/zellij-org/zellij/issues/1412#issuecomment-1131559720 + if layout_path.extension().is_some() || layout_path.components().count() > 1 { + // We look localy! + Layout::stringified_from_path(layout_path) + } else { + // We look in the default dir + Layout::stringified_from_dir(layout_path, layout_dir.as_ref()) + } + }, + None => Layout::stringified_from_dir( + &std::path::PathBuf::from("default"), + layout_dir.as_ref(), + ), } - total_panes } - - pub fn total_borderless_panes(&self) -> usize { - let mut total_borderless_panes = 0; - total_borderless_panes += self.parts.iter().filter(|p| p.borderless).count(); - for part in &self.parts { - total_borderless_panes += part.total_borderless_panes(); + pub fn from_path_or_default( + layout_path: Option<&PathBuf>, + layout_dir: Option, + config: Config, + ) -> Result<(Layout, Config), ConfigError> { + let (path_to_raw_layout, raw_layout) = + Layout::stringified_from_path_or_default(layout_path, layout_dir)?; + let layout = Layout::from_kdl(&raw_layout, path_to_raw_layout)?; + let config = Config::from_kdl(&raw_layout, Some(config))?; // this merges the two config, with + Ok((layout, config)) + } + pub fn from_str(raw: &str, path_to_raw_layout: String) -> Result { + Layout::from_kdl(raw, path_to_raw_layout) + } + pub fn stringified_from_dir( + layout: &PathBuf, + layout_dir: Option<&PathBuf>, + ) -> Result<(String, String), ConfigError> { + // (path_to_layout as String, stringified_layout) + match layout_dir { + Some(dir) => { + let layout_path = &dir.join(layout); + if layout_path.with_extension("kdl").exists() { + Self::stringified_from_path(layout_path) + } else { + Layout::stringified_from_default_assets(layout) + } + }, + None => Layout::stringified_from_default_assets(layout), } - total_borderless_panes } - pub fn extract_run_instructions(&self) -> Vec> { - let mut run_instructions = vec![]; - if self.parts.is_empty() { - run_instructions.push(self.run.clone()); + pub fn stringified_from_path(layout_path: &Path) -> Result<(String, String), ConfigError> { + // (path_to_layout as String, stringified_layout) + let mut layout_file = File::open(&layout_path) + .or_else(|_| File::open(&layout_path.with_extension("kdl"))) + .map_err(|e| ConfigError::IoPath(e, layout_path.into()))?; + + let mut kdl_layout = String::new(); + layout_file.read_to_string(&mut kdl_layout)?; + Ok((layout_path.as_os_str().to_string_lossy().into(), kdl_layout)) + } + pub fn stringified_from_default_assets(path: &Path) -> Result<(String, String), ConfigError> { + // (path_to_layout as String, stringified_layout) + // TODO: ideally these should not be hard-coded + // we should load layouts by name from the config + // and load them from a hashmap or some such + match path.to_str() { + Some("default") => Ok(( + "Default layout".into(), + Self::stringified_default_from_assets()?, + )), + Some("strider") => Ok(( + "Strider layout".into(), + Self::stringified_strider_from_assets()?, + )), + Some("disable-status-bar") => Ok(( + "Disable Status Bar layout".into(), + Self::stringified_disable_status_from_assets()?, + )), + Some("compact") => Ok(( + "Compact layout".into(), + Self::stringified_compact_from_assets()?, + )), + None | Some(_) => Err(ConfigError::IoPath( + std::io::Error::new(std::io::ErrorKind::Other, "The layout was not found"), + path.into(), + )), } - for part in &self.parts { - let mut current_runnables = part.extract_run_instructions(); - run_instructions.append(&mut current_runnables); + } + pub fn stringified_default_from_assets() -> Result { + Ok(String::from_utf8(setup::DEFAULT_LAYOUT.to_vec())?) + } + + pub fn stringified_strider_from_assets() -> Result { + Ok(String::from_utf8(setup::STRIDER_LAYOUT.to_vec())?) + } + + pub fn stringified_disable_status_from_assets() -> Result { + Ok(String::from_utf8(setup::NO_STATUS_LAYOUT.to_vec())?) + } + + pub fn stringified_compact_from_assets() -> Result { + Ok(String::from_utf8(setup::COMPACT_BAR_LAYOUT.to_vec())?) + } + + pub fn new_tab(&self) -> PaneLayout { + match &self.template { + Some(template) => template.clone(), + None => PaneLayout::default(), } - run_instructions } - pub fn position_panes_in_space(&self, space: &PaneGeom) -> Vec<(Layout, PaneGeom)> { - split_space(space, self) + pub fn is_empty(&self) -> bool { + !self.tabs.is_empty() + } + // TODO: do we need both of these? + pub fn has_tabs(&self) -> bool { + !self.tabs.is_empty() } - pub fn merge_layout_parts(&mut self, mut parts: Vec) { - self.parts.append(&mut parts); + pub fn tabs(&self) -> Vec<(Option, PaneLayout)> { + // String is the tab name + self.tabs.clone() } - fn from_vec_tab_layout(tab_layout: Vec) -> Result, ConfigError> { - tab_layout - .iter() - .map(|tab_layout| Layout::try_from(tab_layout.to_owned())) - .collect() - } - - fn from_vec_template_layout( - layout_template: Vec, - ) -> Result, ConfigError> { - layout_template - .iter() - .map(|layout_template| Layout::try_from(layout_template.to_owned())) - .collect() + pub fn focused_tab_index(&self) -> Option { + self.focused_tab_index } } -fn layout_size(direction: Direction, layout: &Layout) -> usize { - fn child_layout_size( - direction: Direction, - parent_direction: Direction, - layout: &Layout, - ) -> usize { - let size = if parent_direction == direction { 1 } else { 0 }; - if layout.parts.is_empty() { - size - } else { - let children_size = layout - .parts - .iter() - .map(|p| child_layout_size(direction, layout.direction, p)) - .sum(); - max(size, children_size) - } - } - child_layout_size(direction, direction, layout) -} - -fn split_space(space_to_split: &PaneGeom, layout: &Layout) -> Vec<(Layout, PaneGeom)> { +fn split_space( + space_to_split: &PaneGeom, + layout: &PaneLayout, + total_space_to_split: &PaneGeom, +) -> Vec<(PaneLayout, PaneGeom)> { let mut pane_positions = Vec::new(); - let sizes: Vec> = layout.parts.iter().map(|part| part.split_size).collect(); + let sizes: Vec> = + layout.children.iter().map(|part| part.split_size).collect(); let mut split_geom = Vec::new(); - let (mut current_position, split_dimension_space, mut inherited_dimension) = - match layout.direction { - Direction::Vertical => (space_to_split.x, space_to_split.cols, space_to_split.rows), - Direction::Horizontal => (space_to_split.y, space_to_split.rows, space_to_split.cols), - }; + let ( + mut current_position, + split_dimension_space, + inherited_dimension, + total_split_dimension_space, + ) = match layout.children_split_direction { + SplitDirection::Vertical => ( + space_to_split.x, + space_to_split.cols, + space_to_split.rows, + total_space_to_split.cols, + ), + SplitDirection::Horizontal => ( + space_to_split.y, + space_to_split.rows, + space_to_split.cols, + total_space_to_split.rows, + ), + }; let flex_parts = sizes.iter().filter(|s| s.is_none()).count(); - for (&size, part) in sizes.iter().zip(&layout.parts) { - let split_dimension = match size { + let mut total_pane_size = 0; + for (&size, _part) in sizes.iter().zip(&*layout.children) { + let mut split_dimension = match size { Some(SplitSize::Percent(percent)) => Dimension::percent(percent as f64), Some(SplitSize::Fixed(size)) => Dimension::fixed(size), None => { let free_percent = if let Some(p) = split_dimension_space.as_percent() { p - sizes .iter() - .map(|&s| { - if let Some(SplitSize::Percent(ip)) = s { - ip as f64 - } else { - 0.0 - } + .map(|&s| match s { + Some(SplitSize::Percent(ip)) => ip as f64, + _ => 0.0, }) .sum::() } else { @@ -612,22 +398,17 @@ fn split_space(space_to_split: &PaneGeom, layout: &Layout) -> Vec<(Layout, PaneG Dimension::percent(free_percent / flex_parts as f64) }, }; - inherited_dimension.set_inner( - layout - .parts - .iter() - .map(|p| layout_size(!layout.direction, p)) - .max() - .unwrap(), - ); - let geom = match layout.direction { - Direction::Vertical => PaneGeom { + split_dimension.adjust_inner(total_split_dimension_space.as_usize()); + total_pane_size += split_dimension.as_usize(); + + let geom = match layout.children_split_direction { + SplitDirection::Vertical => PaneGeom { x: current_position, y: space_to_split.y, cols: split_dimension, rows: inherited_dimension, }, - Direction::Horizontal => PaneGeom { + SplitDirection::Horizontal => PaneGeom { x: space_to_split.x, y: current_position, cols: inherited_dimension, @@ -635,18 +416,32 @@ fn split_space(space_to_split: &PaneGeom, layout: &Layout) -> Vec<(Layout, PaneG }, }; split_geom.push(geom); - current_position += layout_size(layout.direction, part); + current_position += split_dimension.as_usize(); } - for (i, part) in layout.parts.iter().enumerate() { + // add extra space from rounding errors to the last pane + if total_pane_size < split_dimension_space.as_usize() { + let increase_by = split_dimension_space.as_usize() - total_pane_size; + if let Some(last_geom) = split_geom.last_mut() { + match layout.children_split_direction { + SplitDirection::Vertical => last_geom.cols.increase_inner(increase_by), + SplitDirection::Horizontal => last_geom.rows.increase_inner(increase_by), + } + } + } + for (i, part) in layout.children.iter().enumerate() { let part_position_and_size = split_geom.get(i).unwrap(); - if !part.parts.is_empty() { - let mut part_positions = split_space(part_position_and_size, part); + if !part.children.is_empty() { + let mut part_positions = + split_space(part_position_and_size, part, total_space_to_split); pane_positions.append(&mut part_positions); } else { pane_positions.push((part.clone(), *part_position_and_size)); } } + if pane_positions.is_empty() { + pane_positions.push((layout.clone(), space_to_split.clone())); + } pane_positions } @@ -658,163 +453,45 @@ impl TryFrom for RunPluginLocation { "zellij" => Ok(Self::Zellij(PluginTag::new(url.path()))), "file" => { let path = PathBuf::from(url.path()); - let canonicalize = |p: &Path| { - fs::canonicalize(p) - .map_err(|_| PluginsConfigError::InvalidPluginLocation(p.to_owned())) - }; - canonicalize(&path) - .or_else(|_| match path.strip_prefix("/") { - Ok(path) => canonicalize(path), - Err(_) => Err(PluginsConfigError::InvalidPluginLocation(path.to_owned())), - }) - .map(Self::File) + Ok(Self::File(path)) }, _ => Err(PluginsConfigError::InvalidUrl(url)), } } } -impl TryFrom for Run { - type Error = PluginsConfigError; - - fn try_from(run: RunFromYaml) -> Result { - match run { - RunFromYaml::Command(command) => Ok(Run::Command(command)), - RunFromYaml::Plugin(plugin) => Ok(Run::Plugin(RunPlugin { - _allow_exec_host_cmd: plugin._allow_exec_host_cmd, - location: plugin.location.try_into()?, - })), - } - } -} - -impl From for LayoutFromYaml { - fn from(layout_from_yaml_intermediate: LayoutFromYamlIntermediate) -> Self { - Self { - template: layout_from_yaml_intermediate.template, - borderless: layout_from_yaml_intermediate.borderless, - tabs: layout_from_yaml_intermediate.tabs, - session: layout_from_yaml_intermediate.session, - } - } -} - -impl From for LayoutFromYamlIntermediate { - fn from(layout_from_yaml: LayoutFromYaml) -> Self { - Self { - template: layout_from_yaml.template, - borderless: layout_from_yaml.borderless, - tabs: layout_from_yaml.tabs, - config: None, - session: layout_from_yaml.session, - } - } -} - -impl Default for LayoutFromYamlIntermediate { +impl Default for SplitDirection { fn default() -> Self { - LayoutFromYaml::default().into() + SplitDirection::Horizontal } } -impl TryFrom for Layout { - type Error = ConfigError; - - fn try_from(tab: TabLayout) -> Result { - Ok(Layout { - direction: tab.direction, - pane_name: tab.pane_name, - borderless: tab.borderless, - parts: Self::from_vec_tab_layout(tab.parts)?, - split_size: tab.split_size, - focus: tab.focus, - run: tab.run.map(Run::try_from).transpose()?, - }) - } -} - -impl From for LayoutTemplate { - fn from(tab: TabLayout) -> Self { - Self { - direction: tab.direction, - pane_name: tab.pane_name, - borderless: tab.borderless, - parts: Self::from_vec_tab_layout(tab.parts), - body: false, - split_size: tab.split_size, - focus: tab.focus, - run: tab.run, +impl FromStr for SplitDirection { + type Err = Box; + fn from_str(s: &str) -> Result { + match s { + "vertical" | "Vertical" => Ok(SplitDirection::Vertical), + "horizontal" | "Horizontal" => Ok(SplitDirection::Horizontal), + _ => Err("split direction must be either vertical or horizontal".into()), } } } -impl TryFrom for Layout { - type Error = ConfigError; - - fn try_from(template: LayoutTemplate) -> Result { - Ok(Layout { - direction: template.direction, - pane_name: template.pane_name, - borderless: template.borderless, - parts: Self::from_vec_template_layout(template.parts)?, - split_size: template.split_size, - focus: template.focus, - run: template - .run - .map(Run::try_from) - // FIXME: This is just Result::transpose but that method is unstable, when it - // stabalizes we should swap this out. - .map_or(Ok(None), |r| r.map(Some))?, - }) - } -} - -impl Default for TabLayout { - fn default() -> Self { - Self { - direction: Direction::Horizontal, - borderless: false, - parts: vec![], - split_size: None, - run: None, - name: String::new(), - pane_name: None, - focus: None, +impl FromStr for SplitSize { + type Err = Box; + fn from_str(s: &str) -> Result { + if s.chars().last() == Some('%') { + let char_count = s.chars().count(); + let percent_size = usize::from_str_radix(&s[..char_count.saturating_sub(1)], 10)?; + Ok(SplitSize::Percent(percent_size)) + } else { + let fixed_size = usize::from_str_radix(s, 10)?; + Ok(SplitSize::Fixed(fixed_size)) } } } -impl Default for LayoutTemplate { - fn default() -> Self { - Self { - direction: Direction::Horizontal, - pane_name: None, - body: false, - borderless: false, - parts: vec![LayoutTemplate { - direction: Direction::Horizontal, - pane_name: None, - body: true, - borderless: false, - split_size: None, - focus: None, - run: None, - parts: vec![], - }], - split_size: None, - focus: None, - run: None, - } - } -} - -impl Default for Direction { - fn default() -> Self { - Direction::Horizontal - } -} - // The unit test location. -#[cfg(test)] #[path = "./unit/layout_test.rs"] +#[cfg(test)] mod layout_test; diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs index 29a7816c..6722cfd8 100644 --- a/zellij-utils/src/input/mod.rs +++ b/zellij-utils/src/input/mod.rs @@ -1,4 +1,3 @@ -//! The way terminal input is handled. pub mod actions; pub mod command; pub mod config; diff --git a/zellij-utils/src/input/options.rs b/zellij-utils/src/input/options.rs index 460712ef..60707597 100644 --- a/zellij-utils/src/input/options.rs +++ b/zellij-utils/src/input/options.rs @@ -106,6 +106,14 @@ pub struct Options { /// Explicit full path to open the scrollback editor (default is $EDITOR or $VISUAL) #[clap(long, value_parser)] pub scrollback_editor: Option, + + #[clap(long, value_parser)] + #[serde(default)] + pub session_name: Option, + + #[clap(long, value_parser)] + #[serde(default)] + pub attach_to_session: Option, } #[derive(ArgEnum, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)] @@ -122,6 +130,17 @@ impl Default for Clipboard { } } +impl FromStr for Clipboard { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "System" | "system" => Ok(Self::System), + "Primary" | "primary" => Ok(Self::Primary), + _ => Err(format!("No such clipboard: {}", s)), + } + } +} + impl Options { pub fn from_yaml(from_yaml: Option) -> Options { if let Some(opts) = from_yaml { @@ -130,7 +149,6 @@ impl Options { Options::default() } } - /// Merges two [`Options`] structs, a `Some` in `other` /// will supersede a `Some` in `self` // TODO: Maybe a good candidate for a macro? @@ -153,6 +171,10 @@ impl Options { let scrollback_editor = other .scrollback_editor .or_else(|| self.scrollback_editor.clone()); + let session_name = other.session_name.or_else(|| self.session_name.clone()); + let attach_to_session = other + .attach_to_session + .or_else(|| self.attach_to_session.clone()); Options { simplified_ui, @@ -171,6 +193,8 @@ impl Options { copy_clipboard, copy_on_select, scrollback_editor, + session_name, + attach_to_session, } } @@ -208,6 +232,10 @@ impl Options { let scrollback_editor = other .scrollback_editor .or_else(|| self.scrollback_editor.clone()); + let session_name = other.session_name.or_else(|| self.session_name.clone()); + let attach_to_session = other + .attach_to_session + .or_else(|| self.attach_to_session.clone()); Options { simplified_ui, @@ -226,6 +254,8 @@ impl Options { copy_clipboard, copy_on_select, scrollback_editor, + session_name, + attach_to_session, } } @@ -249,7 +279,7 @@ pub struct CliOptions { #[clap(long, conflicts_with("pane-frames"), value_parser)] pub no_pane_frames: bool, #[clap(flatten)] - options: Options, + pub options: Options, } impl From for Options { @@ -280,6 +310,7 @@ impl From for Options { copy_clipboard: opts.copy_clipboard, copy_on_select: opts.copy_on_select, scrollback_editor: opts.scrollback_editor, + ..Default::default() } } } diff --git a/zellij-utils/src/input/plugins.rs b/zellij-utils/src/input/plugins.rs index 8dec828d..55ea4283 100644 --- a/zellij-utils/src/input/plugins.rs +++ b/zellij-utils/src/input/plugins.rs @@ -1,45 +1,39 @@ //! Plugins configuration metadata use std::borrow::Borrow; use std::collections::HashMap; -use std::convert::TryFrom; use std::fs; use std::path::{Path, PathBuf}; use thiserror::Error; -use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use url::Url; -use super::config::ConfigFromYaml; use super::layout::{RunPlugin, RunPluginLocation}; pub use crate::data::PluginTag; -use crate::setup; -lazy_static! { - static ref DEFAULT_CONFIG_PLUGINS: PluginsConfig = { - let cfg = String::from_utf8(setup::DEFAULT_CONFIG.to_vec()).unwrap(); - let cfg_yaml: ConfigFromYaml = serde_yaml::from_str(&cfg).unwrap(); - PluginsConfig::try_from(cfg_yaml.plugins).unwrap() - }; -} - -#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] -pub struct PluginsConfigFromYaml(Vec); +use std::collections::BTreeMap; +use std::fmt; /// Used in the config struct for plugin metadata -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct PluginsConfig(HashMap); +#[derive(Clone, PartialEq, Deserialize, Serialize)] +pub struct PluginsConfig(pub HashMap); + +impl fmt::Debug for PluginsConfig { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut stable_sorted = BTreeMap::new(); + for (plugin_tag, plugin_config) in self.0.iter() { + stable_sorted.insert(plugin_tag, plugin_config); + } + write!(f, "{:#?}", stable_sorted) + } +} impl PluginsConfig { pub fn new() -> Self { Self(HashMap::new()) } - - /// Entrypoint from the config module - pub fn get_plugins_with_default(user_plugins: Self) -> Self { - let mut base_plugins = DEFAULT_CONFIG_PLUGINS.clone(); - base_plugins.0.extend(user_plugins.0); - base_plugins + pub fn from_data(data: HashMap) -> Self { + PluginsConfig(data) } /// Get plugin config from run configuration specified in layout files. @@ -74,37 +68,7 @@ impl PluginsConfig { impl Default for PluginsConfig { fn default() -> Self { - Self::get_plugins_with_default(PluginsConfig::new()) - } -} - -impl TryFrom for PluginsConfig { - type Error = PluginsConfigError; - - fn try_from(yaml: PluginsConfigFromYaml) -> Result { - let mut plugins = HashMap::new(); - for plugin in yaml.0 { - if plugins.contains_key(&plugin.tag) { - return Err(PluginsConfigError::DuplicatePlugins(plugin.tag)); - } - plugins.insert(plugin.tag.clone(), plugin.into()); - } - - Ok(PluginsConfig(plugins)) - } -} - -impl From for PluginConfig { - fn from(plugin: PluginConfigFromYaml) -> Self { - PluginConfig { - path: plugin.path, - run: match plugin.run { - PluginTypeFromYaml::Pane => PluginType::Pane(None), - PluginTypeFromYaml::Headless => PluginType::Headless, - }, - _allow_exec_host_cmd: plugin._allow_exec_host_cmd, - location: RunPluginLocation::Zellij(plugin.tag), - } + PluginsConfig(HashMap::new()) } } @@ -172,31 +136,6 @@ impl Default for PluginType { } } -#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] -pub struct PluginConfigFromYaml { - pub path: PathBuf, - pub tag: PluginTag, - #[serde(default)] - pub run: PluginTypeFromYaml, - #[serde(default)] - pub config: serde_yaml::Value, - #[serde(default)] - pub _allow_exec_host_cmd: bool, -} - -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub enum PluginTypeFromYaml { - Headless, - Pane, -} - -impl Default for PluginTypeFromYaml { - fn default() -> Self { - Self::Pane - } -} - #[derive(Error, Debug, PartialEq)] pub enum PluginsConfigError { #[error("Duplication in plugin tag names is not allowed: '{}'", String::from(.0.clone()))] @@ -206,99 +145,3 @@ pub enum PluginsConfigError { #[error("Could not find plugin at the path: '{0:?}'")] InvalidPluginLocation(PathBuf), } - -#[cfg(test)] -mod tests { - use super::*; - use crate::input::config::ConfigError; - use std::convert::TryInto; - - #[test] - fn run_plugin_permissions_are_inherited() -> Result<(), ConfigError> { - let yaml_plugins: PluginsConfigFromYaml = serde_yaml::from_str( - " - - path: boo.wasm - tag: boo - _allow_exec_host_cmd: false - ", - )?; - let plugins = PluginsConfig::try_from(yaml_plugins)?; - - assert_eq!( - plugins.get(RunPlugin { - _allow_exec_host_cmd: true, - location: RunPluginLocation::Zellij(PluginTag::new("boo")) - }), - Some(PluginConfig { - _allow_exec_host_cmd: true, - path: PathBuf::from("boo.wasm"), - location: RunPluginLocation::Zellij(PluginTag::new("boo")), - run: PluginType::Pane(None), - }) - ); - - Ok(()) - } - - #[test] - fn try_from_yaml_fails_when_duplicate_tag_names_are_present() -> Result<(), ConfigError> { - let ConfigFromYaml { plugins, .. } = serde_yaml::from_str( - " - plugins: - - path: /foo/bar/baz.wasm - tag: boo - - path: /foo/bar/boo.wasm - tag: boo - ", - )?; - - assert_eq!( - PluginsConfig::try_from(plugins), - Err(PluginsConfigError::DuplicatePlugins(PluginTag::new("boo"))) - ); - - Ok(()) - } - - #[test] - fn default_plugins() -> Result<(), ConfigError> { - let ConfigFromYaml { plugins, .. } = serde_yaml::from_str( - " - plugins: - - path: boo.wasm - tag: boo - ", - )?; - let plugins = PluginsConfig::get_plugins_with_default(plugins.try_into()?); - - assert_eq!(plugins.iter().count(), 5); - Ok(()) - } - - #[test] - fn default_plugins_allow_overriding() -> Result<(), ConfigError> { - let ConfigFromYaml { plugins, .. } = serde_yaml::from_str( - " - plugins: - - path: boo.wasm - tag: tab-bar - ", - )?; - let plugins = PluginsConfig::get_plugins_with_default(plugins.try_into()?); - - assert_eq!( - plugins.get(RunPlugin { - _allow_exec_host_cmd: false, - location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")) - }), - Some(PluginConfig { - _allow_exec_host_cmd: false, - path: PathBuf::from("boo.wasm"), - location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), - run: PluginType::Pane(None), - }) - ); - - Ok(()) - } -} diff --git a/zellij-utils/src/input/theme.rs b/zellij-utils/src/input/theme.rs index b148e0d4..c76deb31 100644 --- a/zellij-utils/src/input/theme.rs +++ b/zellij-utils/src/input/theme.rs @@ -2,72 +2,75 @@ use serde::{ de::{Error, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; +use std::{ + collections::{BTreeMap, HashMap}, + fmt, +}; -use std::fs::File; -use std::io::Read; -use std::path::Path; -use std::{collections::HashMap, fmt}; - -use super::{config::ConfigError, options::Options}; -use crate::data::{Palette, PaletteColor}; -use crate::shared::detect_theme_hue; - -/// Intermediate deserialization of themes -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct ThemesFromYamlIntermediate(HashMap); - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct ThemesFromYaml { - pub themes: ThemesFromYamlIntermediate, -} - -type ThemesFromYamlResult = Result; +use crate::data::Palette; #[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)] -pub struct UiConfigFromYaml { - pub pane_frames: FrameConfigFromYaml, +pub struct UiConfig { + pub pane_frames: FrameConfig, +} + +impl UiConfig { + pub fn merge(&self, other: UiConfig) -> Self { + let mut merged = self.clone(); + merged.pane_frames = merged.pane_frames.merge(other.pane_frames); + merged + } } #[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)] -pub struct FrameConfigFromYaml { +pub struct FrameConfig { pub rounded_corners: bool, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -struct ThemeFromYaml { - palette: PaletteFromYaml, +impl FrameConfig { + pub fn merge(&self, other: FrameConfig) -> Self { + let mut merged = self.clone(); + merged.rounded_corners = other.rounded_corners; + merged + } +} + +#[derive(Clone, PartialEq, Default)] +pub struct Themes(HashMap); + +impl fmt::Debug for Themes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut stable_sorted = BTreeMap::new(); + for (theme_name, theme) in self.0.iter() { + stable_sorted.insert(theme_name, theme); + } + write!(f, "{:#?}", stable_sorted) + } +} + +impl Themes { + pub fn from_data(theme_data: HashMap) -> Self { + Themes(theme_data) + } + pub fn insert(&mut self, theme_name: String, theme: Theme) { + self.0.insert(theme_name, theme); + } + pub fn merge(&self, mut other: Themes) -> Self { + let mut merged = self.clone(); + for (name, theme) in other.0.drain() { + merged.0.insert(name, theme); + } + merged + } + pub fn get_theme(&self, theme_name: &str) -> Option<&Theme> { + self.0.get(theme_name) + } } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct Theme { #[serde(flatten)] - palette: PaletteFromYaml, -} - -/// Intermediate deserialization struct -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Default)] -pub struct PaletteFromYaml { - pub fg: PaletteColorFromYaml, - pub bg: PaletteColorFromYaml, - pub black: PaletteColorFromYaml, - pub red: PaletteColorFromYaml, - pub green: PaletteColorFromYaml, - pub yellow: PaletteColorFromYaml, - pub blue: PaletteColorFromYaml, - pub magenta: PaletteColorFromYaml, - pub cyan: PaletteColorFromYaml, - pub white: PaletteColorFromYaml, - pub orange: PaletteColorFromYaml, -} - -/// Intermediate deserialization enum -// This is here in order to make the untagged enum work -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] -#[serde(untagged)] -pub enum PaletteColorFromYaml { - Rgb((u8, u8, u8)), - EightBit(u8), - Hex(HexColor), + pub palette: Palette, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -134,96 +137,6 @@ impl Serialize for HexColor { } } -impl Default for PaletteColorFromYaml { - fn default() -> Self { - PaletteColorFromYaml::EightBit(0) - } -} - -impl ThemesFromYaml { - pub fn from_path(theme_path: &Path) -> ThemesFromYamlResult { - let mut theme_file = File::open(&theme_path) - .or_else(|_| File::open(&theme_path.with_extension("yaml"))) - .map_err(|e| ConfigError::IoPath(e, theme_path.into()))?; - - let mut theme = String::new(); - theme_file.read_to_string(&mut theme)?; - - let theme: ThemesFromYaml = match serde_yaml::from_str(&theme) { - Err(e) => return Err(ConfigError::Serde(e)), - Ok(theme) => theme, - }; - - Ok(theme) - } -} - -impl From for ThemesFromYamlIntermediate { - fn from(yaml: ThemesFromYaml) -> Self { - yaml.themes - } -} - -impl ThemesFromYamlIntermediate { - pub fn theme_config(self, opts: &Options) -> Option { - let mut from_yaml = self; - match &opts.theme { - Some(theme) => from_yaml.from_default_theme(theme.to_owned()), - None => from_yaml.from_default_theme("default".into()), - } - } - - fn get_theme(&mut self, theme: String) -> Option { - self.0.remove(&theme) - } - - #[allow(clippy::wrong_self_convention)] - fn from_default_theme(&mut self, theme: String) -> Option { - self.clone() - .get_theme(theme) - .map(|t| Palette::from(t.palette)) - } - - /// Merges two Theme structs into one Theme struct - /// `other` overrides the Theme of `self`. - pub fn merge(&self, other: Self) -> Self { - let mut theme = self.0.clone(); - theme.extend(other.0); - Self(theme) - } -} - -impl From for Palette { - fn from(yaml: PaletteFromYaml) -> Self { - Palette { - fg: yaml.fg.into(), - bg: yaml.bg.into(), - black: yaml.black.into(), - red: yaml.red.into(), - green: yaml.green.into(), - yellow: yaml.yellow.into(), - blue: yaml.blue.into(), - magenta: yaml.magenta.into(), - cyan: yaml.cyan.into(), - white: yaml.white.into(), - orange: yaml.orange.into(), - theme_hue: detect_theme_hue(yaml.bg.into()), - ..Palette::default() - } - } -} - -impl From for PaletteColor { - fn from(yaml: PaletteColorFromYaml) -> Self { - match yaml { - PaletteColorFromYaml::Rgb(color) => PaletteColor::Rgb(color), - PaletteColorFromYaml::EightBit(color) => PaletteColor::EightBit(color), - PaletteColorFromYaml::Hex(color) => PaletteColor::Rgb(color.into()), - } - } -} - -// The unit test location. #[cfg(test)] #[path = "./unit/theme_test.rs"] mod theme_test; diff --git a/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml b/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml deleted file mode 100644 index 6b599373..00000000 --- a/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml +++ /dev/null @@ -1,41 +0,0 @@ ---- -template: - direction: Horizontal - parts: - - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 21 - - direction: Vertical - split_size: - Percent: 79 - parts: - - direction: Horizontal - split_size: - Percent: 22 - - direction: Horizontal - split_size: - Percent: 78 - parts: - - direction: Horizontal - split_size: - Percent: 23 - - direction: Vertical - body: true - split_size: - Percent: 90 - - direction: Vertical - split_size: - Percent: 15 - - direction: Vertical - split_size: - Percent: 15 - - direction: Vertical - split_size: - Percent: 15 - -tabs: - - direction: Horizontal - split_size: - Percent: 24 diff --git a/zellij-utils/src/input/unit/fixtures/layouts/multiple-tabs-should-not-error.yaml b/zellij-utils/src/input/unit/fixtures/layouts/multiple-tabs-should-not-error.yaml deleted file mode 100644 index 65378759..00000000 --- a/zellij-utils/src/input/unit/fixtures/layouts/multiple-tabs-should-not-error.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -direction: Horizontal -parts: - - direction: Horizontal - parts: - - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 50 - - direction: Horizontal - tabs: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 diff --git a/zellij-utils/src/input/unit/fixtures/layouts/no-layout-template-specified.yaml b/zellij-utils/src/input/unit/fixtures/layouts/no-layout-template-specified.yaml deleted file mode 100644 index 7794c912..00000000 --- a/zellij-utils/src/input/unit/fixtures/layouts/no-layout-template-specified.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -tabs: - - direction: Vertical - parts: - - direction: Horizontal - - direction: Horizontal diff --git a/zellij-utils/src/input/unit/fixtures/layouts/no-tab-section-specified.yaml b/zellij-utils/src/input/unit/fixtures/layouts/no-tab-section-specified.yaml deleted file mode 100644 index 8b0f3daf..00000000 --- a/zellij-utils/src/input/unit/fixtures/layouts/no-tab-section-specified.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -template: - direction: Horizontal - parts: - - direction: Horizontal - body: true diff --git a/zellij-utils/src/input/unit/fixtures/layouts/session-name-to-layout.yaml b/zellij-utils/src/input/unit/fixtures/layouts/session-name-to-layout.yaml deleted file mode 100644 index 144d555b..00000000 --- a/zellij-utils/src/input/unit/fixtures/layouts/session-name-to-layout.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -session: - name: "zellij-session" diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-command.yaml b/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-command.yaml deleted file mode 100644 index 9ad1034d..00000000 --- a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-command.yaml +++ /dev/null @@ -1,35 +0,0 @@ ---- -template: - direction: Horizontal - parts: - - direction: Vertical - split_size: - Fixed: 1 - run: - plugin: tab-bar - - direction: Horizontal - body: true - - direction: Vertical - split_size: - Fixed: 2 - run: - plugin: status-bar - -tabs: - - direction: Vertical - parts: - - direction: Horizontal - split_size: - Percent: 50 - - direction: Horizontal - parts: - - direction: Vertical - split_size: - Percent: 50 - run: - command: {cmd: htop} - - direction: Vertical - split_size: - Percent: 50 - run: - command: {cmd: htop, args: ["-C"]} diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-tabs-merged-correctly.yaml b/zellij-utils/src/input/unit/fixtures/layouts/three-tabs-merged-correctly.yaml deleted file mode 100644 index e2a09a73..00000000 --- a/zellij-utils/src/input/unit/fixtures/layouts/three-tabs-merged-correctly.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -template: - direction: Vertical - parts: - - direction: Horizontal - body: true - - direction: Horizontal - - -tabs: - - direction: Horizontal - split_size: - Percent: 50 - - direction: Horizontal - split_size: - Percent: 50 - parts: - - direction: Horizontal - split_size: - Percent: 50 - - direction: Horizontal - - direction: Vertical - split_size: - Percent: 50 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Horizontal diff --git a/zellij-utils/src/input/unit/fixtures/themes/dracula.kdl b/zellij-utils/src/input/unit/fixtures/themes/dracula.kdl new file mode 100644 index 00000000..77a25f4b --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/themes/dracula.kdl @@ -0,0 +1,18 @@ +// Dracula Theme + +themes { + dracula { + // From https://github.com/dracula/zellij + bg 40 42 54 + red 255 85 85 + green 80 250 123 + yellow 241 250 140 + blue 98 114 164 + magenta 255 121 198 + orange 255 184 108 + fg 248 248 242 + cyan 139 233 253 + black 0 0 0 + white 255 255 255 + } +} diff --git a/zellij-utils/src/input/unit/fixtures/themes/dracula.yaml b/zellij-utils/src/input/unit/fixtures/themes/dracula.yaml deleted file mode 100644 index b9c8a5af..00000000 --- a/zellij-utils/src/input/unit/fixtures/themes/dracula.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Dracula Theme - -themes: - dracula: - # From https://github.com/dracula/zellij - bg: [40, 42, 54] - red: [255, 85, 85] - green: [80, 250, 123] - yellow: [241, 250, 140] - blue: [98, 114, 164] - magenta: [255, 121, 198] - orange: [255, 184, 108] - fg: [248, 248, 242] - cyan: [139, 233, 253] - black: [0, 0, 0] - white: [255, 255, 255] diff --git a/zellij-utils/src/input/unit/fixtures/themes/nord.kdl b/zellij-utils/src/input/unit/fixtures/themes/nord.kdl new file mode 100644 index 00000000..361a21fd --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/themes/nord.kdl @@ -0,0 +1,17 @@ +// Nord theme + +themes { + nord { + fg 216 222 233 //#D8DEE9 + bg 46 52 64 //#2E3440 + black 59 66 82 //#3B4252 + red 191 97 106 //#BF616A + green 163 190 140 //#A3BE8C + yellow 235203139 //#EBCB8B + blue 129 161 193 //#81A1C1 + magenta 180 142 173 //#B48EAD + cyan 136 192 208 //#88C0D0 + white 229 233 240 //#E5E9F0 + orange 208 135 112 //#D08770 + } +} diff --git a/zellij-utils/src/input/unit/fixtures/themes/nord.yaml b/zellij-utils/src/input/unit/fixtures/themes/nord.yaml deleted file mode 100644 index 61851ad2..00000000 --- a/zellij-utils/src/input/unit/fixtures/themes/nord.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Nord theme - -themes: - nord: - fg: [216, 222, 233] #D8DEE9 - bg: [46, 52, 64] #2E3440 - black: [59, 66, 82] #3B4252 - red: [191, 97, 106] #BF616A - green: [163, 190, 140] #A3BE8C - yellow: [235,203,139] #EBCB8B - blue: [129, 161, 193] #81A1C1 - magenta: [180, 142, 173] #B48EAD - cyan: [136, 192, 208] #88C0D0 - white: [229, 233, 240] #E5E9F0 - orange: [208, 135, 112] #D08770 - diff --git a/zellij-utils/src/input/unit/keybinds_test.rs b/zellij-utils/src/input/unit/keybinds_test.rs index 1579f013..57126d59 100644 --- a/zellij-utils/src/input/unit/keybinds_test.rs +++ b/zellij-utils/src/input/unit/keybinds_test.rs @@ -1,810 +1,544 @@ use super::super::actions::*; use super::super::keybinds::*; -use crate::data::{CharOrArrow, Key}; +use crate::data::{self, CharOrArrow, Key}; +use crate::input::config::Config; +use insta::assert_snapshot; +use strum::IntoEnumIterator; #[test] -fn merge_keybinds_merges_different_keys() { - let mut mode_keybinds_self = ModeKeybinds::new(); - mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]); - let mut mode_keybinds_other = ModeKeybinds::new(); - mode_keybinds_other - .0 - .insert(Key::Backspace, vec![Action::NoOp]); - - let mut mode_keybinds_expected = ModeKeybinds::new(); - mode_keybinds_expected - .0 - .insert(Key::F(1), vec![Action::NoOp]); - mode_keybinds_expected - .0 - .insert(Key::Backspace, vec![Action::NoOp]); - - let mode_keybinds_merged = mode_keybinds_self.merge(mode_keybinds_other); - - assert_eq!(mode_keybinds_expected, mode_keybinds_merged); -} - -#[test] -fn merge_mode_keybinds_overwrites_same_keys() { - let mut mode_keybinds_self = ModeKeybinds::new(); - mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]); - let mut mode_keybinds_other = ModeKeybinds::new(); - mode_keybinds_other - .0 - .insert(Key::F(1), vec![Action::GoToTab(1)]); - - let mut mode_keybinds_expected = ModeKeybinds::new(); - mode_keybinds_expected - .0 - .insert(Key::F(1), vec![Action::GoToTab(1)]); - - let mode_keybinds_merged = mode_keybinds_self.merge(mode_keybinds_other); - - assert_eq!(mode_keybinds_expected, mode_keybinds_merged); -} - -#[test] -fn merge_keybinds_merges() { - let mut mode_keybinds_self = ModeKeybinds::new(); - mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]); - let mut mode_keybinds_other = ModeKeybinds::new(); - mode_keybinds_other - .0 - .insert(Key::Backspace, vec![Action::NoOp]); - let mut keybinds_self = Keybinds::new(); - keybinds_self - .0 - .insert(InputMode::Normal, mode_keybinds_self.clone()); - let mut keybinds_other = Keybinds::new(); - keybinds_other - .0 - .insert(InputMode::Resize, mode_keybinds_other.clone()); - let mut keybinds_expected = Keybinds::new(); - keybinds_expected - .0 - .insert(InputMode::Normal, mode_keybinds_self); - keybinds_expected - .0 - .insert(InputMode::Resize, mode_keybinds_other); - +fn can_define_keybindings_in_configfile() { + let config_contents = r#" + keybinds { + normal { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let ctrl_g_normal_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Normal, &Key::Ctrl('g')); assert_eq!( - keybinds_expected, - keybinds_self.merge_keybinds(keybinds_other) - ) + ctrl_g_normal_mode_action, + Some(&vec![Action::SwitchToMode(InputMode::Locked)]), + "Keybinding successfully defined in config" + ); } #[test] -fn merge_keybinds_overwrites_same_keys() { - let mut mode_keybinds_self = ModeKeybinds::new(); - mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]); - mode_keybinds_self.0.insert(Key::F(2), vec![Action::NoOp]); - mode_keybinds_self.0.insert(Key::F(3), vec![Action::NoOp]); - let mut mode_keybinds_other = ModeKeybinds::new(); - mode_keybinds_other - .0 - .insert(Key::F(1), vec![Action::GoToTab(1)]); - mode_keybinds_other - .0 - .insert(Key::F(2), vec![Action::GoToTab(2)]); - mode_keybinds_other - .0 - .insert(Key::F(3), vec![Action::GoToTab(3)]); - let mut keybinds_self = Keybinds::new(); - keybinds_self - .0 - .insert(InputMode::Normal, mode_keybinds_self); - let mut keybinds_other = Keybinds::new(); - keybinds_other - .0 - .insert(InputMode::Normal, mode_keybinds_other.clone()); - let mut keybinds_expected = Keybinds::new(); - keybinds_expected - .0 - .insert(InputMode::Normal, mode_keybinds_other); - +fn can_define_multiple_keybinds_for_same_action() { + let config_contents = r#" + keybinds { + normal { + bind "Alt h" "Alt Left" { MoveFocusOrTab "Left"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let alt_h_normal_mode_action = config.keybinds.get_actions_for_key_in_mode( + &InputMode::Normal, + &Key::Alt(CharOrArrow::Direction(data::Direction::Left)), + ); + let alt_left_normal_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Normal, &Key::Alt(CharOrArrow::Char('h'))); assert_eq!( - keybinds_expected, - keybinds_self.merge_keybinds(keybinds_other) - ) + alt_h_normal_mode_action, + Some(&vec![Action::MoveFocusOrTab(Direction::Left)]), + "First keybinding successfully defined in config" + ); + assert_eq!( + alt_left_normal_mode_action, + Some(&vec![Action::MoveFocusOrTab(Direction::Left)]), + "Second keybinding successfully defined in config" + ); } #[test] -fn from_keyaction_from_yaml_to_mode_keybindings() { - let actions = vec![Action::NoOp, Action::GoToTab(1)]; - let keyaction = KeyActionFromYaml { - action: actions.clone(), - key: vec![Key::F(1), Key::Backspace, Key::Char('t')], - }; - - let mut expected = ModeKeybinds::new(); - expected.0.insert(Key::F(1), actions.clone()); - expected.0.insert(Key::Backspace, actions.clone()); - expected.0.insert(Key::Char('t'), actions); - - assert_eq!(expected, ModeKeybinds::from(keyaction)); +fn can_define_series_of_actions_for_same_keybinding() { + let config_contents = r#" + keybinds { + pane { + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + assert_eq!( + z_in_pane_mode, + Some(&vec![ + Action::TogglePaneFrames, + Action::SwitchToMode(InputMode::Normal) + ]), + "Action series successfully defined" + ); } #[test] -fn toplevel_unbind_unbinds_all() { - let from_yaml = KeybindsFromYaml { - unbind: Unbind::All(true), - keybinds: HashMap::new(), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - assert_eq!(keybinds_from_yaml, Keybinds::new()); +fn keybindings_bind_order_is_preserved() { + let config_contents = r#" + keybinds { + pane { + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + bind "z" { SwitchToMode "Resize"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + assert_eq!( + z_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Resize)]), + "Second keybinding was applied" + ); } #[test] -fn no_unbind_unbinds_none() { - let from_yaml = KeybindsFromYaml { - unbind: Unbind::All(false), - keybinds: HashMap::new(), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - assert_eq!(keybinds_from_yaml, Keybinds::default()); +fn uppercase_and_lowercase_keybindings_are_distinct() { + let config_contents = r#" + keybinds { + pane { + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + bind "Z" { SwitchToMode "Resize"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + let uppercase_z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('Z')); + assert_eq!( + z_in_pane_mode, + Some(&vec![ + Action::TogglePaneFrames, + Action::SwitchToMode(InputMode::Normal) + ]), + "Lowercase z successfully bound" + ); + assert_eq!( + uppercase_z_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Resize)]), + "Uppercase z successfully bound" + ); } #[test] -fn last_keybind_is_taken() { - let actions_1 = vec![Action::NoOp, Action::NewTab(None)]; - let keyaction_1 = KeyActionFromYaml { - action: actions_1, - key: vec![Key::F(1), Key::Backspace, Key::Char('t')], - }; - let actions_2 = vec![Action::GoToTab(1)]; - let keyaction_2 = KeyActionFromYaml { - action: actions_2.clone(), - key: vec![Key::F(1), Key::Backspace, Key::Char('t')], - }; - - let mut expected = ModeKeybinds::new(); - expected.0.insert(Key::F(1), actions_2.clone()); - expected.0.insert(Key::Backspace, actions_2.clone()); - expected.0.insert(Key::Char('t'), actions_2); - - assert_eq!(expected, ModeKeybinds::from(vec![keyaction_1, keyaction_2])); +fn can_override_keybindings() { + let default_config_contents = r#" + keybinds { + pane { + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + } + } + "#; + let config_contents = r#" + keybinds { + pane { + bind "z" { SwitchToMode "Resize"; } + } + } + "#; + let default_config = Config::from_kdl(default_config_contents, None).unwrap(); + let config = Config::from_kdl(config_contents, Some(default_config)).unwrap(); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + assert_eq!( + z_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Resize)]), + "Keybinding from config overrode keybinding from default config" + ); } #[test] -fn last_keybind_overwrites() { - let actions_1 = vec![Action::NoOp, Action::NewTab(None)]; - let keyaction_1 = KeyActionFromYaml { - action: actions_1.clone(), - key: vec![Key::F(1), Key::Backspace, Key::Char('t')], - }; - let actions_2 = vec![Action::GoToTab(1)]; - let keyaction_2 = KeyActionFromYaml { - action: actions_2.clone(), - key: vec![Key::F(1), Key::Char('t')], - }; - - let mut expected = ModeKeybinds::new(); - expected.0.insert(Key::F(1), actions_2.clone()); - expected.0.insert(Key::Backspace, actions_1); - expected.0.insert(Key::Char('t'), actions_2); - - assert_eq!(expected, ModeKeybinds::from(vec![keyaction_1, keyaction_2])); +fn can_add_to_default_keybindings() { + // this test just makes sure keybindings defined in a custom config are added to different + // keybindings defined in the default config + let default_config_contents = r#" + keybinds { + pane { + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + } + } + "#; + let config_contents = r#" + keybinds { + pane { + bind "r" { SwitchToMode "Resize"; } + } + } + "#; + let default_config = Config::from_kdl(default_config_contents, None).unwrap(); + let config = Config::from_kdl(config_contents, Some(default_config)).unwrap(); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + let r_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('r')); + assert_eq!( + z_in_pane_mode, + Some(&vec![ + Action::TogglePaneFrames, + Action::SwitchToMode(InputMode::Normal) + ]), + "Keybinding from default config bound" + ); + assert_eq!( + r_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Resize)]), + "Keybinding from custom config bound as well" + ); } #[test] -fn unbind_single_mode() { - let unbind = Unbind::All(true); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds); - - let keybinds_from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(false), - }; - - let keybinds = Keybinds::unbind(keybinds_from_yaml); - let result = keybinds.0.get(&InputMode::Normal); - assert!(result.is_none()); +fn can_clear_default_keybindings() { + let default_config_contents = r#" + keybinds { + normal { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + pane { + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + } + } + "#; + let config_contents = r#" + keybinds clear-defaults=true { + normal { + bind "Ctrl r" { SwitchToMode "Locked"; } + } + pane { + bind "r" { SwitchToMode "Resize"; } + } + } + "#; + let default_config = Config::from_kdl(default_config_contents, None).unwrap(); + let config = Config::from_kdl(config_contents, Some(default_config)).unwrap(); + let ctrl_g_normal_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Normal, &Key::Ctrl('g')); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + let ctrl_r_in_normal_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Normal, &Key::Ctrl('r')); + let r_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('r')); + assert_eq!( + ctrl_g_normal_mode_action, None, + "Keybinding from normal mode in default config cleared" + ); + assert_eq!( + z_in_pane_mode, None, + "Keybinding from pane mode in default config cleared" + ); + assert_eq!( + r_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Resize)]), + "Keybinding from pane mode in custom config still bound" + ); + assert_eq!( + ctrl_r_in_normal_mode, + Some(&vec![Action::SwitchToMode(InputMode::Locked)]), + "Keybinding from normal mode in custom config still bound" + ); } #[test] -fn unbind_multiple_modes() { - let unbind = Unbind::All(true); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds.clone()); - keys.insert(InputMode::Pane, key_action_unbinds); - - let keybinds_from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(false), - }; - - let keybinds = Keybinds::unbind(keybinds_from_yaml); - let normal = keybinds.0.get(&InputMode::Normal); - let pane = keybinds.0.get(&InputMode::Pane); - assert!(normal.is_none()); - assert!(pane.is_none()); +fn can_clear_default_keybindings_per_single_mode() { + let default_config_contents = r#" + keybinds { + normal { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + pane { + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + } + } + "#; + let config_contents = r#" + keybinds { + pane clear-defaults=true { + bind "r" { SwitchToMode "Resize"; } + } + } + "#; + let default_config = Config::from_kdl(default_config_contents, None).unwrap(); + let config = Config::from_kdl(config_contents, Some(default_config)).unwrap(); + let ctrl_g_normal_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Normal, &Key::Ctrl('g')); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + let r_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('r')); + assert_eq!( + ctrl_g_normal_mode_action, + Some(&vec![Action::SwitchToMode(InputMode::Locked)]), + "Keybind in different mode from default config not cleared" + ); + assert_eq!( + z_in_pane_mode, None, + "Keybinding from pane mode in default config cleared" + ); + assert_eq!( + r_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Resize)]), + "Keybinding from pane mode in custom config still bound" + ); } #[test] -fn unbind_single_keybind_single_mode() { - let unbind = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds); - - let keybinds_from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(false), - }; - - let keybinds = Keybinds::unbind(keybinds_from_yaml); - let mode_keybinds = keybinds.0.get(&InputMode::Normal); - let result = mode_keybinds - .expect("Mode shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - assert!(result.is_none()); +fn can_unbind_multiple_keys_globally() { + let default_config_contents = r#" + keybinds { + normal { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + pane { + bind "Ctrl g" { SwitchToMode "Locked"; } + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + bind "r" { TogglePaneFrames; } + } + } + "#; + let config_contents = r#" + keybinds { + unbind "Ctrl g" "z" + pane { + bind "t" { SwitchToMode "Tab"; } + } + } + "#; + let default_config = Config::from_kdl(default_config_contents, None).unwrap(); + let config = Config::from_kdl(config_contents, Some(default_config)).unwrap(); + let ctrl_g_normal_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Normal, &Key::Ctrl('g')); + let ctrl_g_pane_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Ctrl('g')); + let r_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('r')); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + let t_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('t')); + assert_eq!( + ctrl_g_normal_mode_action, None, + "First keybind uncleared in one mode" + ); + assert_eq!( + ctrl_g_pane_mode_action, None, + "First keybind uncleared in another mode" + ); + assert_eq!(z_in_pane_mode, None, "Second keybind cleared as well"); + assert_eq!( + r_in_pane_mode, + Some(&vec![Action::TogglePaneFrames]), + "Unrelated keybinding in default config still bound" + ); + assert_eq!( + t_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Tab)]), + "Keybinding from custom config still bound" + ); } #[test] -fn unbind_single_keybind_multiple_modes() { - let unbind_n = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]); - let unbind_h = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('h'))]); - let unbind_from_yaml_n = UnbindFromYaml { unbind: unbind_n }; - let unbind_from_yaml_h = UnbindFromYaml { unbind: unbind_h }; - let key_action_unbinds_n = vec![KeyActionUnbind::Unbind(unbind_from_yaml_n)]; - let key_action_unbinds_h = vec![KeyActionUnbind::Unbind(unbind_from_yaml_h)]; - - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds_n); - keys.insert(InputMode::Pane, key_action_unbinds_h); - - let keybinds_from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(false), - }; - - let keybinds = Keybinds::unbind(keybinds_from_yaml); - let normal = keybinds.0.get(&InputMode::Normal); - let pane = keybinds.0.get(&InputMode::Pane); - let result_normal = normal - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_pane = pane - .expect("Mode shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('h'))); - assert!(result_normal.is_none()); - assert!(result_pane.is_none()); +fn can_unbind_multiple_keys_per_single_mode() { + let default_config_contents = r#" + keybinds { + normal { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + pane { + bind "Ctrl g" { SwitchToMode "Locked"; } + bind "z" { TogglePaneFrames; SwitchToMode "Normal"; } + bind "r" { TogglePaneFrames; } + } + } + "#; + let config_contents = r#" + keybinds { + pane { + unbind "Ctrl g" "z" + bind "t" { SwitchToMode "Tab"; } + } + } + "#; + let default_config = Config::from_kdl(default_config_contents, None).unwrap(); + let config = Config::from_kdl(config_contents, Some(default_config)).unwrap(); + let ctrl_g_normal_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Normal, &Key::Ctrl('g')); + let ctrl_g_pane_mode_action = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Ctrl('g')); + let r_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('r')); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + let t_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('t')); + assert_eq!( + ctrl_g_normal_mode_action, + Some(&vec![Action::SwitchToMode(InputMode::Locked)]), + "Keybind in different mode not cleared" + ); + assert_eq!( + ctrl_g_pane_mode_action, None, + "First Keybind cleared in its mode" + ); + assert_eq!( + z_in_pane_mode, None, + "Second keybind cleared in its mode as well" + ); + assert_eq!( + r_in_pane_mode, + Some(&vec![Action::TogglePaneFrames]), + "Unrelated keybinding in default config still bound" + ); + assert_eq!( + t_in_pane_mode, + Some(&vec![Action::SwitchToMode(InputMode::Tab)]), + "Keybinding from custom config still bound" + ); } #[test] -fn unbind_multiple_keybinds_single_mode() { - let unbind = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n')), Key::Ctrl('p')]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds); - - let keybinds_from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(false), - }; - - let keybinds = Keybinds::unbind(keybinds_from_yaml); - let mode_keybinds = keybinds.0.get(&InputMode::Normal); - let result_n = mode_keybinds - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_p = mode_keybinds - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Ctrl('p')); - assert!(result_n.is_none()); - assert!(result_p.is_none()); +fn can_define_shared_keybinds_for_all_modes() { + let config_contents = r#" + keybinds { + shared { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + for mode in InputMode::iter() { + let action_in_mode = config + .keybinds + .get_actions_for_key_in_mode(&mode, &Key::Ctrl('g')); + assert_eq!( + action_in_mode, + Some(&vec![Action::SwitchToMode(InputMode::Locked)]), + "Keybind bound in mode" + ); + } } #[test] -fn unbind_multiple_keybinds_multiple_modes() { - let unbind_normal = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n')), Key::Ctrl('p')]); - let unbind_resize = Unbind::Keys(vec![Key::Char('h'), Key::Ctrl('r')]); - let unbind_from_yaml_normal = UnbindFromYaml { - unbind: unbind_normal, - }; - let unbind_from_yaml_resize = UnbindFromYaml { - unbind: unbind_resize, - }; - let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_normal)]; - let key_action_unbinds_resize = vec![KeyActionUnbind::Unbind(unbind_from_yaml_resize)]; - - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds_normal); - keys.insert(InputMode::Resize, key_action_unbinds_resize); - - let keybinds_from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(false), - }; - - let keybinds = Keybinds::unbind(keybinds_from_yaml); - let mode_keybinds_normal = keybinds.0.get(&InputMode::Normal); - let mode_keybinds_resize = keybinds.0.get(&InputMode::Resize); - let result_normal_1 = mode_keybinds_normal - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_normal_2 = mode_keybinds_normal - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Ctrl('p')); - let result_resize_1 = mode_keybinds_resize - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Char('h')); - let result_resize_2 = mode_keybinds_resize - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Ctrl('r')); - assert!(result_normal_1.is_none()); - assert!(result_resize_1.is_none()); - assert!(result_normal_2.is_none()); - assert!(result_resize_2.is_none()); +fn can_define_shared_keybinds_with_exclusion() { + let config_contents = r#" + keybinds { + shared_except "locked" { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + for mode in InputMode::iter() { + let action_in_mode = config + .keybinds + .get_actions_for_key_in_mode(&mode, &Key::Ctrl('g')); + if mode == InputMode::Locked { + assert_eq!(action_in_mode, None, "Keybind unbound in excluded mode"); + } else { + assert_eq!( + action_in_mode, + Some(&vec![Action::SwitchToMode(InputMode::Locked)]), + "Keybind bound in mode" + ); + } + } } #[test] -fn unbind_multiple_keybinds_all_modes() { - let unbind = Unbind::Keys(vec![ - Key::Alt(CharOrArrow::Char('n')), - Key::Alt(CharOrArrow::Char('h')), - ]); - let keys = HashMap::>::new(); - let keybinds_from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind, - }; - - let keybinds = Keybinds::unbind(keybinds_from_yaml); - let mode_keybinds_normal = keybinds.0.get(&InputMode::Normal); - let mode_keybinds_resize = keybinds.0.get(&InputMode::Resize); - let result_normal_1 = mode_keybinds_normal - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_normal_2 = mode_keybinds_normal - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Ctrl('f')); - let result_resize_1 = mode_keybinds_resize - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Char('n')); - let result_resize_2 = mode_keybinds_resize - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Ctrl('f')); - assert!(result_normal_1.is_none()); - assert!(result_resize_1.is_none()); - assert!(result_normal_2.is_none()); - assert!(result_resize_2.is_none()); +fn can_define_shared_keybinds_with_inclusion() { + let config_contents = r#" + keybinds { + shared_among "normal" "resize" "pane" { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + for mode in InputMode::iter() { + let action_in_mode = config + .keybinds + .get_actions_for_key_in_mode(&mode, &Key::Ctrl('g')); + if mode == InputMode::Normal || mode == InputMode::Resize || mode == InputMode::Pane { + assert_eq!( + action_in_mode, + Some(&vec![Action::SwitchToMode(InputMode::Locked)]), + "Keybind bound in included mode" + ); + } else { + assert_eq!(action_in_mode, None, "Keybind unbound in other modes"); + } + } } #[test] -fn unbind_all_toplevel_single_key_single_mode() { - let unbind = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('h'))]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds_normal); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(true), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - assert_eq!(keybinds_from_yaml, Keybinds::new()); +fn keybindings_unbinds_happen_after_binds() { + let config_contents = r#" + keybinds { + pane { + unbind "z" + bind "z" { SwitchToMode "Resize"; } + } + } + "#; + let config = Config::from_kdl(config_contents, None).unwrap(); + let z_in_pane_mode = config + .keybinds + .get_actions_for_key_in_mode(&InputMode::Pane, &Key::Char('z')); + assert_eq!(z_in_pane_mode, None, "Key was ultimately unbound"); } #[test] -fn unbind_all_toplevel_single_key_multiple_modes() { - let unbind_n = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]); - let unbind_h = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('h'))]); - let unbind_from_yaml_n = UnbindFromYaml { unbind: unbind_n }; - let unbind_from_yaml_h = UnbindFromYaml { unbind: unbind_h }; - let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_n)]; - let key_action_unbinds_pane = vec![KeyActionUnbind::Unbind(unbind_from_yaml_h)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds_normal); - keys.insert(InputMode::Pane, key_action_unbinds_pane); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(true), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - assert_eq!(keybinds_from_yaml, Keybinds::new()); +fn error_received_on_unknown_input_mode() { + let config_contents = r#" + keybinds { + i_do_not_exist { + bind "z" { SwitchToMode "Resize"; } + } + } + "#; + let config_error = Config::from_kdl(config_contents, None).unwrap_err(); + assert_snapshot!(format!("{:?}", config_error)); } #[test] -fn unbind_all_toplevel_multiple_key_multiple_modes() { - let unbind_n = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n')), Key::Ctrl('p')]); - let unbind_h = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('h')), Key::Ctrl('t')]); - let unbind_from_yaml_n = UnbindFromYaml { unbind: unbind_n }; - let unbind_from_yaml_h = UnbindFromYaml { unbind: unbind_h }; - let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_n)]; - let key_action_unbinds_pane = vec![KeyActionUnbind::Unbind(unbind_from_yaml_h)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds_normal); - keys.insert(InputMode::Pane, key_action_unbinds_pane); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(true), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - assert_eq!(keybinds_from_yaml, Keybinds::new()); -} - -#[test] -fn unbind_all_toplevel_all_key_multiple_modes() { - let unbind = Unbind::All(true); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml.clone())]; - let key_action_unbinds_pane = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbinds_normal); - keys.insert(InputMode::Pane, key_action_unbinds_pane); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(true), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - assert_eq!(keybinds_from_yaml, Keybinds::new()); -} - -#[test] -fn unbind_single_keybind_all_modes() { - let keys = HashMap::>::new(); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - let result_normal = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_pane = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_resize = keybinds_from_yaml - .0 - .get(&InputMode::Resize) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_tab = keybinds_from_yaml - .0 - .get(&InputMode::Tab) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - - assert!(result_normal.is_none()); - assert!(result_pane.is_none()); - assert!(result_resize.is_none()); - assert!(result_tab.is_none()); -} - -#[test] -fn unbind_single_toplevel_single_key_single_mode_identical() { - let unbind = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbind); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - let result_normal = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_pane = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_resize = keybinds_from_yaml - .0 - .get(&InputMode::Resize) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_tab = keybinds_from_yaml - .0 - .get(&InputMode::Tab) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - - assert!(result_normal.is_none()); - assert!(result_pane.is_none()); - assert!(result_resize.is_none()); - assert!(result_tab.is_none()); -} - -#[test] -fn unbind_single_toplevel_single_key_single_mode_differing() { - let unbind = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('l'))]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbind); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - let result_normal_n = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_normal_l = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('l'))); - let result_resize_n = keybinds_from_yaml - .0 - .get(&InputMode::Resize) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_resize_l = keybinds_from_yaml - .0 - .get(&InputMode::Resize) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('l'))); - - assert!(result_normal_n.is_none()); - assert!(result_normal_l.is_none()); - assert!(result_resize_n.is_none()); - assert!(result_resize_l.is_some()); -} - -#[test] -fn unbind_single_toplevel_single_key_multiple_modes() { - let unbind = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('l'))]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbind.clone()); - keys.insert(InputMode::Pane, key_action_unbind); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - let result_normal_n = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_normal_l = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('l'))); - let result_pane_n = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_pane_l = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('l'))); - - assert!(result_normal_n.is_none()); - assert!(result_normal_l.is_none()); - assert!(result_pane_n.is_none()); - assert!(result_pane_l.is_none()); -} - -#[test] -fn unbind_single_toplevel_multiple_keys_single_mode() { - let unbind = Unbind::Keys(vec![ - Key::Alt(CharOrArrow::Char('l')), - Key::Alt(CharOrArrow::Char('h')), - Key::Alt(CharOrArrow::Char('j')), - Key::Alt(CharOrArrow::Char('k')), - ]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbind.clone()); - keys.insert(InputMode::Pane, key_action_unbind); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - let result_normal_n = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_normal_l = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('l'))); - let result_normal_k = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('k'))); - let result_normal_h = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('h'))); - - assert!(result_normal_n.is_none()); - assert!(result_normal_l.is_none()); - assert!(result_normal_h.is_none()); - assert!(result_normal_k.is_none()); -} - -#[test] -fn unbind_single_toplevel_multiple_keys_multiple_modes() { - let unbind_normal = Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('l')), Key::Ctrl('p')]); - let unbind_from_yaml_normal = UnbindFromYaml { - unbind: unbind_normal, - }; - let key_action_unbind_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_normal)]; - let unbind = Unbind::Keys(vec![ - Key::Alt(CharOrArrow::Char('l')), - Key::Alt(CharOrArrow::Char('k')), - ]); - let unbind_from_yaml = UnbindFromYaml { unbind }; - let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbind_normal); - keys.insert(InputMode::Pane, key_action_unbind); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::Keys(vec![Key::Alt(CharOrArrow::Char('n'))]), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - - let result_normal_n = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_normal_p = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Ctrl('p')); - let result_normal_l = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('l'))); - let result_pane_p = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Ctrl('p')); - let result_pane_n = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('n'))); - let result_pane_l = keybinds_from_yaml - .0 - .get(&InputMode::Pane) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Alt(CharOrArrow::Char('l'))); - - assert!(result_normal_n.is_none()); - assert!(result_normal_l.is_none()); - assert!(result_normal_p.is_none()); - assert!(result_pane_n.is_none()); - assert!(result_pane_p.is_some()); - assert!(result_pane_l.is_none()); -} - -#[test] -fn uppercase_and_lowercase_are_distinct() { - let key_action_n = KeyActionFromYaml { - key: vec![Key::Char('n')], - action: vec![Action::NewTab(None)], - }; - let key_action_large_n = KeyActionFromYaml { - key: vec![Key::Char('N')], - action: vec![Action::NewPane(None)], - }; - - let key_action_unbind = vec![ - KeyActionUnbind::KeyAction(key_action_n), - KeyActionUnbind::KeyAction(key_action_large_n), - ]; - let mut keys = HashMap::>::new(); - keys.insert(InputMode::Normal, key_action_unbind); - let from_yaml = KeybindsFromYaml { - keybinds: keys, - unbind: Unbind::All(false), - }; - - let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml)); - let result_n = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Char('n')); - let result_large_n = keybinds_from_yaml - .0 - .get(&InputMode::Normal) - .expect("ModeKeybinds shouldn't be empty") - .0 - .get(&Key::Char('N')); - - assert!(result_n.is_some()); - assert!(result_large_n.is_some()); +fn error_received_on_unknown_key_instruction() { + let config_contents = r#" + keybinds { + pane { + i_am_not_bind_or_unbind + bind "z" { SwitchToMode "Resize"; } + } + } + "#; + let config_error = Config::from_kdl(config_contents, None).unwrap_err(); + assert_snapshot!(format!("{:?}", config_error)); } diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs index 22a10c6f..b4b309ba 100644 --- a/zellij-utils/src/input/unit/layout_test.rs +++ b/zellij-utils/src/input/unit/layout_test.rs @@ -1,859 +1,1013 @@ use super::super::layout::*; -use std::convert::TryInto; - -fn layout_test_dir(layout: String) -> PathBuf { - let root = Path::new(env!("CARGO_MANIFEST_DIR")); - let layout_dir = root.join("src/input/unit/fixtures/layouts"); - layout_dir.join(layout) -} - -fn default_layout_dir(layout: String) -> PathBuf { - let root = Path::new(env!("CARGO_MANIFEST_DIR")); - let layout_dir = root.join("assets/layouts"); - layout_dir.join(layout) -} +use insta::assert_snapshot; #[test] -fn default_layout_is_ok() { - let path = default_layout_dir("default.yaml".into()); - let layout = LayoutFromYaml::new(&path); - assert!(layout.is_ok()); -} - -#[test] -fn default_layout_has_one_tab() { - let path = default_layout_dir("default.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap(); - assert_eq!(layout_template.tabs.len(), 1); -} - -#[test] -fn default_layout_merged_correctly() { - let path = default_layout_dir("default.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[0].clone())); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: true, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(1)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), - _allow_exec_host_cmd: false, - })), - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: true, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(2)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("status-bar")), - _allow_exec_host_cmd: false, - })), - }, - ], - split_size: None, - run: None, +fn empty_layout() { + let kdl_layout = "layout"; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout::default()), + ..Default::default() }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); + assert_eq!(layout, expected_layout); } #[test] -fn default_layout_new_tab_correct() { - let path = default_layout_dir("default.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.as_ref().unwrap(); - let tab_layout = layout_template.template.clone().insert_tab_layout(None); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: true, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(1)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), - _allow_exec_host_cmd: false, - })), - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: true, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(2)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("status-bar")), - _allow_exec_host_cmd: false, - })), - }, - ], - split_size: None, - run: None, +fn layout_with_one_pane() { + let kdl_layout = r#" + layout { + pane + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![PaneLayout::default()], + ..Default::default() + }), + ..Default::default() }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); + assert_eq!(layout, expected_layout); } #[test] -fn default_strider_layout_is_ok() { - let path = default_layout_dir("strider.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - assert!(layout_from_yaml.is_ok()); +fn layout_with_multiple_panes() { + let kdl_layout = r#" + layout { + pane + pane + pane + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![ + PaneLayout::default(), + PaneLayout::default(), + PaneLayout::default(), + ], + ..Default::default() + }), + ..Default::default() + }; + assert_eq!(layout, expected_layout); } #[test] -fn default_disable_status_layout_is_ok() { - let path = default_layout_dir("disable-status-bar.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - assert!(layout_from_yaml.is_ok()); -} - -#[test] -fn default_disable_status_layout_has_no_tab() { - let path = default_layout_dir("disable-status-bar.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.as_ref().unwrap(); - assert_eq!(layout_template.tabs.len(), 0); -} - -#[test] -fn three_panes_with_tab_is_ok() { - let path = layout_test_dir("three-panes-with-tab.yaml".into()); - let layout = LayoutFromYaml::new(&path); - assert!(layout.is_ok()); -} - -#[test] -fn three_panes_with_tab_has_one_tab() { - let path = layout_test_dir("three-panes-with-tab.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap(); - assert_eq!(layout_template.tabs.len(), 1); -} - -#[test] -fn three_panes_with_tab_merged_correctly() { - let path = layout_test_dir("three-panes-with-tab.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[0].clone())); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, +fn layout_with_nested_panes() { + let kdl_layout = r#" + layout { + pane split_direction="Vertical" { + pane + pane + } + pane { + pane + pane + } + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![ + PaneLayout { + children_split_direction: SplitDirection::Vertical, + children: vec![PaneLayout::default(), PaneLayout::default()], + ..Default::default() }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, + PaneLayout { + children: vec![PaneLayout::default(), PaneLayout::default()], + ..Default::default() + }, + ], + ..Default::default() + }), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_tabs() { + let kdl_layout = r#" + layout { + tab + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + tabs: vec![(None, PaneLayout::default())], + template: Some(PaneLayout::default()), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_nested_differing_tabs() { + let kdl_layout = r#" + layout { + tab split_direction="Vertical" { + pane + pane + pane + } + tab { + pane + pane + } + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + tabs: vec![ + ( + None, + PaneLayout { + children_split_direction: SplitDirection::Vertical, + children: vec![ + PaneLayout::default(), + PaneLayout::default(), + PaneLayout::default(), ], + ..Default::default() + }, + ), + ( + None, + PaneLayout { + children_split_direction: SplitDirection::Horizontal, + children: vec![PaneLayout::default(), PaneLayout::default()], + ..Default::default() + }, + ), + ], + template: Some(PaneLayout::default()), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_panes_in_different_mixed_split_sizes() { + let kdl_layout = r#" + layout { + pane size=1; + pane size="10%"; + pane; + pane size=2; + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![ + PaneLayout { + split_size: Some(SplitSize::Fixed(1)), + ..Default::default() + }, + PaneLayout { + split_size: Some(SplitSize::Percent(10)), + ..Default::default() + }, + PaneLayout { split_size: None, - run: None, + ..Default::default() + }, + PaneLayout { + split_size: Some(SplitSize::Fixed(2)), + ..Default::default() }, ], - split_size: None, - run: None, - }], - split_size: None, - run: None, + ..Default::default() + }), + ..Default::default() }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); + assert_eq!(layout, expected_layout); } #[test] -fn three_panes_with_tab_new_tab_is_correct() { - let path = layout_test_dir("three-panes-with-tab.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap(); - let tab_layout = layout_template.template.clone().insert_tab_layout(None); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }], - split_size: None, - run: None, - }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); -} - -#[test] -fn three_panes_with_tab_and_default_plugins_is_ok() { - let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); - let layout = LayoutFromYaml::new(&path); - assert!(layout.is_ok()); -} - -#[test] -fn three_panes_with_tab_and_default_plugins_has_one_tab() { - let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap(); - assert_eq!(layout_template.tabs.len(), 1); -} - -#[test] -fn three_panes_with_tab_and_default_plugins_merged_correctly() { - let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[0].clone())); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(1)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), - _allow_exec_host_cmd: false, +fn layout_with_command_panes() { + let kdl_layout = r#" + layout { + pane command="htop" + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![PaneLayout { + run: Some(Run::Command(RunCommand { + command: PathBuf::from("htop"), + ..Default::default() })), - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - ], - split_size: None, - run: None, - }, - ], - split_size: None, - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(2)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("status-bar")), - _allow_exec_host_cmd: false, + ..Default::default() + }], + ..Default::default() + }), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_command_panes_and_cwd() { + let kdl_layout = r#" + layout { + pane command="htop" cwd="/path/to/my/cwd" + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![PaneLayout { + run: Some(Run::Command(RunCommand { + command: PathBuf::from("htop"), + cwd: Some(PathBuf::from("/path/to/my/cwd")), + ..Default::default() })), - }, - ], - split_size: None, - run: None, + ..Default::default() + }], + ..Default::default() + }), + ..Default::default() }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); + assert_eq!(layout, expected_layout); } #[test] -fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() { - let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap(); - let tab_layout = layout_template.template.clone().insert_tab_layout(None); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(1)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), - _allow_exec_host_cmd: false, +fn layout_with_command_panes_and_cwd_and_args() { + let kdl_layout = r#" + layout { + pane command="htop" cwd="/path/to/my/cwd" { + args "-h" "-v" + } + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![PaneLayout { + run: Some(Run::Command(RunCommand { + command: PathBuf::from("htop"), + cwd: Some(PathBuf::from("/path/to/my/cwd")), + args: vec![String::from("-h"), String::from("-v")], + ..Default::default() })), - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Fixed(2)), - run: Some(Run::Plugin(RunPlugin { - location: RunPluginLocation::Zellij(PluginTag::new("status-bar")), - _allow_exec_host_cmd: false, - })), - }, - ], - split_size: None, - run: None, + ..Default::default() + }], + ..Default::default() + }), + ..Default::default() }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); + assert_eq!(layout, expected_layout); } #[test] -fn deeply_nested_tab_is_ok() { - let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); - let layout = LayoutFromYaml::new(&path); - assert!(layout.is_ok()); -} - -#[test] -fn deeply_nested_tab_has_one_tab() { - let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap(); - assert_eq!(layout_template.tabs.len(), 1); -} - -#[test] -fn deeply_nested_tab_merged_correctly() { - let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[0].clone())); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(21)), - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(22)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(23)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(24)), - run: None, - }, - ], - split_size: Some(SplitSize::Percent(78)), - run: None, - }, - ], - split_size: Some(SplitSize::Percent(79)), - run: None, - }, - ], - split_size: Some(SplitSize::Percent(90)), - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(15)), - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(15)), - run: None, - }, - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(15)), - run: None, - }, - ], - split_size: None, - run: None, - }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); -} - -#[test] -fn three_tabs_is_ok() { - let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - assert!(layout_from_yaml.is_ok()); -} - -#[test] -fn three_tabs_has_three_tabs() { - let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.unwrap(); - assert_eq!(layout_template.tabs.len(), 3); -} - -#[test] -fn three_tabs_tab_one_merged_correctly() { - let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[0].clone())); - let merged_layout = Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - ], - split_size: None, - run: None, - }; - - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); -} - -#[test] -fn three_tabs_tab_two_merged_correctly() { - let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[1].clone())); - let merged_layout = Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - ], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - ], - split_size: None, - run: None, - }; - - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); -} - -#[test] -fn three_tabs_tab_three_merged_correctly() { - let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[2].clone())); - let merged_layout = Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![ - Layout { - direction: Direction::Vertical, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - ], - split_size: Some(SplitSize::Percent(50)), - run: None, - }, - Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }, - ], - split_size: None, - run: None, - }; - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); -} - -#[test] -fn no_tabs_is_ok() { - let path = layout_test_dir("no-tab-section-specified.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - assert!(layout_from_yaml.is_ok()); -} - -#[test] -fn no_tabs_has_no_tabs() { - let path = layout_test_dir("no-tab-section-specified.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.unwrap(); - assert_eq!(layout_template.tabs.len(), 0); -} - -#[test] -fn no_tabs_merged_correctly() { - let path = layout_test_dir("no-tab-section-specified.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.as_ref().unwrap(); - let tab_layout = layout_template.template.clone().insert_tab_layout(None); - let merged_layout = Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![Layout { - direction: Direction::Horizontal, - borderless: false, - pane_name: None, - focus: None, - parts: vec![], - split_size: None, - run: None, - }], - split_size: None, - run: None, - }; - - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); -} - -#[test] -fn no_layout_template_specified_is_ok() { - let path = layout_test_dir("no-layout-template-specified.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - assert!(layout_from_yaml.is_ok()); -} - -#[test] -fn no_layout_template_has_one_tab() { - let path = layout_test_dir("no-layout-template-specified.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.unwrap(); - assert_eq!(layout_template.tabs.len(), 1); -} - -#[test] -fn no_layout_template_merged_correctly() { - let path = layout_test_dir("no-layout-template-specified.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.as_ref().unwrap(); - let tab_layout = layout_template - .template - .clone() - .insert_tab_layout(Some(layout_template.tabs[0].clone())); - let merged_layout = Layout { - direction: Direction::Horizontal, - parts: vec![Layout { - direction: Direction::Vertical, - parts: vec![ - Layout { - direction: Direction::Horizontal, - parts: vec![], - split_size: None, - run: None, - borderless: false, - pane_name: None, - focus: None, +fn layout_with_plugin_panes() { + let kdl_layout = r#" + layout { + pane { + plugin location="zellij:tab-bar" + } + pane { + plugin location="file:/path/to/my/plugin.wasm" + } + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![ + PaneLayout { + run: Some(Run::Plugin(RunPlugin { + location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")), + _allow_exec_host_cmd: false, + })), + ..Default::default() }, - Layout { - direction: Direction::Horizontal, - parts: vec![], - split_size: None, - run: None, - borderless: false, - pane_name: None, - focus: None, + PaneLayout { + run: Some(Run::Plugin(RunPlugin { + location: RunPluginLocation::File(PathBuf::from("/path/to/my/plugin.wasm")), + _allow_exec_host_cmd: false, + })), + ..Default::default() }, ], - split_size: None, - run: None, - borderless: false, - pane_name: None, - focus: None, - }], - split_size: None, - run: None, - borderless: false, - pane_name: None, - focus: None, + ..Default::default() + }), + ..Default::default() }; - - assert_eq!(merged_layout, tab_layout.try_into().unwrap()); + assert_eq!(layout, expected_layout); } #[test] -fn session_name_to_layout_is_ok() { - let path = layout_test_dir("session-name-to-layout.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - assert!(layout_from_yaml.is_ok()); +fn layout_with_borderless_panes() { + let kdl_layout = r#" + layout { + pane borderless=true + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![PaneLayout { + borderless: true, + ..Default::default() + }], + ..Default::default() + }), + ..Default::default() + }; + assert_eq!(layout, expected_layout); } #[test] -fn session_name_to_layout_has_name() { - let path = layout_test_dir("session-name-to-layout.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.unwrap(); - let session_layout = layout_template.session; - - let expected_session = SessionFromYaml { - name: Some(String::from("zellij-session")), - attach: Some(true), +fn layout_with_focused_panes() { + let kdl_layout = r#" + layout { + pane focus=true + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![PaneLayout { + focus: Some(true), + ..Default::default() + }], + ..Default::default() + }), + ..Default::default() }; - - assert_eq!(expected_session, session_layout); + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_pane_names() { + let kdl_layout = r#" + layout { + pane name="my awesome pane" + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + template: Some(PaneLayout { + children: vec![PaneLayout { + name: Some("my awesome pane".into()), + ..Default::default() + }], + ..Default::default() + }), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_tab_names() { + let kdl_layout = r#" + layout { + tab name="my cool tab name 1" + tab name="my cool tab name 2" + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + tabs: vec![ + ( + Some("my cool tab name 1".into()), + PaneLayout { + children: vec![], + ..Default::default() + }, + ), + ( + Some("my cool tab name 2".into()), + PaneLayout { + children: vec![], + ..Default::default() + }, + ), + ], + template: Some(PaneLayout::default()), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_focused_tab() { + let kdl_layout = r#" + layout { + tab + tab focus=true + tab + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + tabs: vec![ + (None, PaneLayout::default()), + (None, PaneLayout::default()), + (None, PaneLayout::default()), + ], + template: Some(PaneLayout::default()), + focused_tab_index: Some(1), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_tab_templates() { + let kdl_layout = r#" + layout { + tab_template name="one-above-one-below" { + pane + children + pane + } + one-above-one-below name="my first tab" split_direction="Vertical" { + pane + pane + } + one-above-one-below name="my second tab" { + pane + pane + } + one-above-one-below + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + let expected_layout = Layout { + tabs: vec![ + ( + Some("my first tab".into()), + PaneLayout { + children_split_direction: SplitDirection::Horizontal, + children: vec![ + PaneLayout::default(), + PaneLayout { + children_split_direction: SplitDirection::Vertical, + children: vec![PaneLayout::default(), PaneLayout::default()], + ..Default::default() + }, + PaneLayout::default(), + ], + ..Default::default() + }, + ), + ( + Some("my second tab".into()), + PaneLayout { + children_split_direction: SplitDirection::Horizontal, + children: vec![ + PaneLayout::default(), + PaneLayout { + children_split_direction: SplitDirection::Horizontal, + children: vec![PaneLayout::default(), PaneLayout::default()], + ..Default::default() + }, + PaneLayout::default(), + ], + ..Default::default() + }, + ), + ( + None, + PaneLayout { + children_split_direction: SplitDirection::Horizontal, + children: vec![ + PaneLayout::default(), + PaneLayout::default(), + PaneLayout::default(), + ], + ..Default::default() + }, + ), + ], + template: Some(PaneLayout::default()), + ..Default::default() + }; + assert_eq!(layout, expected_layout); +} + +#[test] +fn layout_with_default_tab_template() { + let kdl_layout = r#" + layout { + default_tab_template { + pane + children + pane + } + tab name="my first tab" split_direction="Vertical" { + pane + pane + } + tab name="my second tab" { + pane + pane + } + tab + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn layout_with_pane_templates() { + let kdl_layout = r#" + layout { + pane_template name="left-and-right" split_direction="Vertical" { + pane + children + pane + } + left-and-right { + pane + } + left-and-right { + pane + pane + } + left-and-right split_direction="Vertical" { + pane + pane + } + left-and-right + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn layout_with_tab_and_pane_templates() { + let kdl_layout = r#" + layout { + tab_template name="left-right-and-htop" { + left-and-right { + pane command="htop" + } + } + pane_template name="left-and-right" split_direction="Vertical" { + pane + children + pane + } + left-right-and-htop + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn layout_with_nested_pane_templates() { + let kdl_layout = r#" + layout { + pane_template name="left-and-right" split_direction="Vertical" { + pane + children + up-and-down + pane + } + pane_template name="up-and-down" split_direction="Horizontal" { + pane + pane + } + left-and-right + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn layout_with_nested_branched_pane_templates() { + let kdl_layout = r#" + layout { + pane_template name="left-and-right" split_direction="Vertical" { + pane + children + up-and-down + three-horizontal-panes + } + pane_template name="three-horizontal-panes" split_direction="Horizontal" { + pane + pane + pane + } + pane_template name="up-and-down" split_direction="Horizontal" { + pane + pane + } + left-and-right + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn circular_dependency_pane_templates_error() { + let kdl_layout = r#" + layout { + pane_template name="one" split_direction="Vertical" { + pane + children + two + } + pane_template name="two" split_direction="Horizontal" { + pane + three + pane + } + pane_template name="three" split_direction="Horizontal" { + one + } + one + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()); + assert!(layout.is_err(), "circular dependency detected"); +} + +#[test] +fn children_not_as_first_child_of_tab_template() { + let kdl_layout = r#" + layout { + tab_template name="horizontal-with-vertical-top" { + pane split_direction="Vertical" { + pane + children + } + pane + } + horizontal-with-vertical-top name="my tab" { + pane + pane + } + horizontal-with-vertical-top + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn error_on_more_than_one_children_block_in_tab_template() { + let kdl_layout = r#" + layout { + tab_template name="horizontal-with-vertical-top" { + pane split_direction="Vertical" { + pane + children + } + children + pane + } + horizontal-with-vertical-top name="my tab" { + pane + pane + } + horizontal-with-vertical-top + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()); + assert!( + layout.is_err(), + "error provided for more than one children block" + ); +} + +#[test] +fn children_not_as_first_child_of_pane_template() { + let kdl_layout = r#" + layout { + pane_template name="horizontal-with-vertical-top" { + pane split_direction="Vertical" { + pane + children + } + pane + } + horizontal-with-vertical-top name="my tab" { + pane + pane + } + horizontal-with-vertical-top + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn error_on_more_than_one_children_block_in_pane_template() { + let kdl_layout = r#" + layout { + pane_template name="horizontal-with-vertical-top" { + pane split_direction="Vertical" { + pane + children + } + children + pane + } + horizontal-with-vertical-top name="my tab" { + pane + pane + } + horizontal-with-vertical-top + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()); + assert!( + layout.is_err(), + "error provided for more than one children block" + ); +} + +#[test] +fn combined_tab_and_pane_template_both_with_children() { + let kdl_layout = r#" + layout { + tab_template name="horizontal-with-vertical-top" { + vertical-sandwich { + pane name="middle" + } + children + } + pane_template name="vertical-sandwich" split_direction="Vertical" { + pane + children + pane + } + horizontal-with-vertical-top name="my tab" { + pane + pane + } + horizontal-with-vertical-top + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn cannot_define_tab_template_name_with_space() { + let kdl_layout = r#" + layout { + tab_template name="with space" { + pane + children + pane + } + pane + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()); + assert!(layout.is_err(), "error provided for tab name with space"); +} + +#[test] +fn cannot_define_pane_template_name_with_space() { + let kdl_layout = r#" + layout { + pane_template name="with space" { + pane + children + pane + } + pane + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()); + assert!(layout.is_err(), "error provided for tab name with space"); +} + +#[test] +fn cannot_define_panes_and_tabs_on_same_level() { + let kdl_layout = r#" + layout { + pane + tab { + pane + } + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()); + assert!( + layout.is_err(), + "error provided for tab and pane on the same level" + ); +} + +#[test] +fn cannot_define_tab_template_names_as_keywords() { + let keywords = vec![ + "pane", + "layout", + "pane_template", + "tab_template", + "default_tab_template", + "command", + "plugin", + "children", + "tab", + ]; + for keyword in keywords { + let kdl_layout = format!( + " + layout {{ + tab_template name=\"{}\" {{ + pane + children + pane + }} + pane + }} + ", + keyword + ); + let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into()); + assert!( + layout.is_err(), + "{}", + format!( + "error provided for tab template name with keyword: {}", + keyword + ) + ); + } +} + +#[test] +fn cannot_define_pane_template_names_as_keywords() { + let keywords = vec![ + "pane", + "layout", + "pane_template", + "tab_template", + "command", + "plugin", + "children", + "tab", + ]; + for keyword in keywords { + let kdl_layout = format!( + " + layout {{ + pane_template name=\"{}\" {{ + pane + children + pane + }} + pane + }} + ", + keyword + ); + let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into()); + assert!( + layout.is_err(), + "{}", + format!( + "error provided for pane template name with keyword: {}", + keyword + ) + ); + } +} + +#[test] +fn error_on_multiple_layout_nodes_in_file() { + let kdl_layout = format!( + " + layout + layout + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_unknown_layout_node() { + let kdl_layout = format!( + " + layout {{ + pane + i_am_not_a_proper_node + pane + }} + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_unknown_layout_pane_property() { + let kdl_layout = format!( + " + layout {{ + pane spit_size=1 + }} + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_unknown_layout_pane_template_property() { + let kdl_layout = format!( + " + layout {{ + pane_template name=\"my_cool_template\" spit_size=1 + }} + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_unknown_layout_tab_property() { + let kdl_layout = format!( + " + layout {{ + tab spit_size=1 + }} + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_unknown_layout_tab_template_property() { + let kdl_layout = format!( + " + layout {{ + tab_template name=\"my_cool_template\" spit_size=1 + }} + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_pane_templates_without_a_name() { + let kdl_layout = format!( + " + layout {{ + pane_template {{ + pane + children + pane + }} + }} + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_tab_templates_without_a_name() { + let kdl_layout = format!( + " + layout {{ + tab_template {{ + pane + children + pane + }} + }} + " + ); + let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); +} + +#[test] +fn error_on_more_than_one_focused_tab() { + let kdl_layout = r#" + layout { + tab focus=true + tab focus=true + tab + } + "#; + let layout_error = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap_err(); + assert_snapshot!(format!("{:?}", layout_error)); } diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__keybinds__keybinds_test__error_received_on_unknown_input_mode.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__keybinds__keybinds_test__error_received_on_unknown_input_mode.snap new file mode 100644 index 00000000..eab0dc6f --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__keybinds__keybinds_test__error_received_on_unknown_input_mode.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/keybinds_test.rs +assertion_line: 476 +expression: "format!(\"{:?}\", config_error)" +--- +KdlError(KdlError { error_message: "Invalid mode: 'i_do_not_exist'", src: None, offset: Some(32), len: Some(14) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__keybinds__keybinds_test__error_received_on_unknown_key_instruction.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__keybinds__keybinds_test__error_received_on_unknown_key_instruction.snap new file mode 100644 index 00000000..cce4254a --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__keybinds__keybinds_test__error_received_on_unknown_key_instruction.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/keybinds_test.rs +assertion_line: 490 +expression: "format!(\"{:?}\", config_error)" +--- +KdlError(KdlError { error_message: "Unknown keybind instruction: 'i_am_not_bind_or_unbind'", src: None, offset: Some(55), len: Some(23) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap new file mode 100644 index 00000000..f82879d2 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap @@ -0,0 +1,139 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 848 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: Some( + 1, + ), + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap new file mode 100644 index 00000000..003a3d41 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap @@ -0,0 +1,147 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 801 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [ + ( + Some( + "my tab", + ), + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ( + None, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: Some( + 1, + ), + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap new file mode 100644 index 00000000..a964c655 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap @@ -0,0 +1,201 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 899 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [ + ( + Some( + "my tab", + ), + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: Some( + "middle", + ), + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ( + None, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: Some( + "middle", + ), + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_more_than_one_focused_tab.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_more_than_one_focused_tab.snap new file mode 100644 index 00000000..b640aa43 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_more_than_one_focused_tab.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 979 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Only one tab can be focused", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(0), len: Some(98) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_multiple_layout_nodes_in_file.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_multiple_layout_nodes_in_file.snap new file mode 100644 index 00000000..0c2811ec --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_multiple_layout_nodes_in_file.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 879 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Only one layout node per file allowed", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(0), len: Some(31) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_pane_templates_without_a_name.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_pane_templates_without_a_name.snap new file mode 100644 index 00000000..cf7fc692 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_pane_templates_without_a_name.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 951 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Pane templates must have a name", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(30), len: Some(96) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_tab_templates_without_a_name.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_tab_templates_without_a_name.snap new file mode 100644 index 00000000..c7b591f8 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_tab_templates_without_a_name.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 966 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Tab templates must have a name", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(30), len: Some(95) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_node.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_node.snap new file mode 100644 index 00000000..b2b28ffe --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_node.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 892 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Unknown layout node: 'i_am_not_a_proper_node'", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(47), len: Some(22) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_pane_property.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_pane_property.snap new file mode 100644 index 00000000..573ca75a --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_pane_property.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 926 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Unknown pane property: spit_size", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(35), len: Some(11) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_pane_template_property.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_pane_template_property.snap new file mode 100644 index 00000000..09701ebe --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_pane_template_property.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 939 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Unknown pane property: spit_size", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(68), len: Some(11) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_tab_property.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_tab_property.snap new file mode 100644 index 00000000..bbe1769c --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_tab_property.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 925 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Invalid tab property 'spit_size'", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(30), len: Some(15) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_tab_template_property.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_tab_template_property.snap new file mode 100644 index 00000000..134970f7 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__error_on_unknown_layout_tab_template_property.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 936 +expression: "format!(\"{:?}\", layout_error)" +--- +KdlError(KdlError { error_message: "Invalid tab property 'spit_size'", src: Some(NamedSource { name: "layout_file_name", source: ""), offset: Some(30), len: Some(48) }) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap new file mode 100644 index 00000000..f61145b4 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap @@ -0,0 +1,231 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 549 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [ + ( + Some( + "my first tab", + ), + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ( + Some( + "my second tab", + ), + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ( + None, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap new file mode 100644 index 00000000..77b7478c --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap @@ -0,0 +1,125 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 756 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap new file mode 100644 index 00000000..fd12e42b --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap @@ -0,0 +1,94 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 729 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap new file mode 100644 index 00000000..561c35f1 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap @@ -0,0 +1,239 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 626 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap new file mode 100644 index 00000000..72101338 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap @@ -0,0 +1,96 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 648 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [ + ( + None, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: Some( + Command( + RunCommand { + command: "htop", + args: [], + cwd: None, + }, + ), + ), + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), + ], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__theme__layout_test__dracula_theme_from_file.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__theme__layout_test__dracula_theme_from_file.snap new file mode 100644 index 00000000..26ee77f8 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__theme__layout_test__dracula_theme_from_file.snap @@ -0,0 +1,109 @@ +--- +source: zellij-utils/src/input/./unit/theme_test.rs +assertion_line: 15 +expression: "format!(\"{:#?}\", theme)" +--- +( + "dracula", + Theme { + palette: Palette { + source: Default, + theme_hue: Dark, + fg: Rgb( + ( + 248, + 248, + 242, + ), + ), + bg: Rgb( + ( + 40, + 42, + 54, + ), + ), + black: Rgb( + ( + 0, + 0, + 0, + ), + ), + red: Rgb( + ( + 255, + 85, + 85, + ), + ), + green: Rgb( + ( + 80, + 250, + 123, + ), + ), + yellow: Rgb( + ( + 241, + 250, + 140, + ), + ), + blue: Rgb( + ( + 98, + 114, + 164, + ), + ), + magenta: Rgb( + ( + 255, + 121, + 198, + ), + ), + cyan: Rgb( + ( + 139, + 233, + 253, + ), + ), + white: Rgb( + ( + 255, + 255, + 255, + ), + ), + orange: Rgb( + ( + 255, + 184, + 108, + ), + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + }, +) diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__theme__theme_test__dracula_theme_from_file.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__theme__theme_test__dracula_theme_from_file.snap new file mode 100644 index 00000000..26ee77f8 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__theme__theme_test__dracula_theme_from_file.snap @@ -0,0 +1,109 @@ +--- +source: zellij-utils/src/input/./unit/theme_test.rs +assertion_line: 15 +expression: "format!(\"{:#?}\", theme)" +--- +( + "dracula", + Theme { + palette: Palette { + source: Default, + theme_hue: Dark, + fg: Rgb( + ( + 248, + 248, + 242, + ), + ), + bg: Rgb( + ( + 40, + 42, + 54, + ), + ), + black: Rgb( + ( + 0, + 0, + 0, + ), + ), + red: Rgb( + ( + 255, + 85, + 85, + ), + ), + green: Rgb( + ( + 80, + 250, + 123, + ), + ), + yellow: Rgb( + ( + 241, + 250, + 140, + ), + ), + blue: Rgb( + ( + 98, + 114, + 164, + ), + ), + magenta: Rgb( + ( + 255, + 121, + 198, + ), + ), + cyan: Rgb( + ( + 139, + 233, + 253, + ), + ), + white: Rgb( + ( + 255, + 255, + 255, + ), + ), + orange: Rgb( + ( + 255, + 184, + 108, + ), + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + }, +) diff --git a/zellij-utils/src/input/unit/theme_test.rs b/zellij-utils/src/input/unit/theme_test.rs index ad5b480a..56259201 100644 --- a/zellij-utils/src/input/unit/theme_test.rs +++ b/zellij-utils/src/input/unit/theme_test.rs @@ -1,5 +1,6 @@ use super::super::theme::*; -use std::path::PathBuf; +use insta::assert_snapshot; +use std::path::{Path, PathBuf}; fn theme_test_dir(theme: String) -> PathBuf { let root = Path::new(env!("CARGO_MANIFEST_DIR")); @@ -8,15 +9,15 @@ fn theme_test_dir(theme: String) -> PathBuf { } #[test] -fn dracula_theme_is_ok() { - let path = theme_test_dir("dracula.yaml".into()); - let theme = ThemesFromYaml::from_path(&path); - assert!(theme.is_ok()); +fn dracula_theme_from_file() { + let path = theme_test_dir("dracula.kdl".into()); + let theme = Theme::from_path(path).unwrap(); + assert_snapshot!(format!("{:#?}", theme)); } #[test] fn no_theme_is_err() { - let path = theme_test_dir("nonexistent.yaml".into()); - let theme = ThemesFromYaml::from_path(&path); + let path = theme_test_dir("nonexistent.kdl".into()); + let theme = Theme::from_path(path); assert!(theme.is_err()); } diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index 354107f5..93008788 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -3,10 +3,8 @@ use crate::{ cli::CliArgs, data::{ClientId, InputMode, Style}, errors::{get_current_ctx, ErrorContext}, - input::{ - actions::Action, keybinds::Keybinds, layout::LayoutFromYaml, options::Options, - plugins::PluginsConfig, - }, + input::keybinds::Keybinds, + input::{actions::Action, layout::Layout, options::Options, plugins::PluginsConfig}, pane_size::{Size, SizeInPixels}, }; use interprocess::local_socket::LocalSocketStream; @@ -87,7 +85,7 @@ pub enum ClientToServerMsg { ClientAttributes, Box, Box, - Box, + Box, Option, ), AttachClient(ClientAttributes, Options), diff --git a/zellij-utils/src/kdl/kdl_layout_parser.rs b/zellij-utils/src/kdl/kdl_layout_parser.rs new file mode 100644 index 00000000..4bf3aea6 --- /dev/null +++ b/zellij-utils/src/kdl/kdl_layout_parser.rs @@ -0,0 +1,888 @@ +use crate::input::{ + command::RunCommand, + config::ConfigError, + layout::{Layout, PaneLayout, Run, RunPlugin, RunPluginLocation, SplitDirection, SplitSize}, +}; + +use kdl::*; + +use std::collections::{HashMap, HashSet}; +use std::str::FromStr; + +use crate::{ + kdl_child_with_name, kdl_children_nodes, kdl_get_bool_property_or_child_value, + kdl_get_bool_property_or_child_value_with_error, kdl_get_child, + kdl_get_int_property_or_child_value, kdl_get_property_or_child, kdl_get_string_entry, + kdl_get_string_property_or_child_value, kdl_get_string_property_or_child_value_with_error, + kdl_name, kdl_parsing_error, kdl_property_names, kdl_property_or_child_value_node, + kdl_string_arguments, +}; + +use std::convert::TryFrom; +use std::path::PathBuf; +use std::vec::Vec; +use url::Url; + +pub struct KdlLayoutParser<'a> { + raw_layout: &'a str, + tab_templates: HashMap, + pane_templates: HashMap, + default_tab_template: Option<(PaneLayout, KdlNode)>, +} + +impl<'a> KdlLayoutParser<'a> { + pub fn new(raw_layout: &'a str) -> Self { + KdlLayoutParser { + raw_layout, + tab_templates: HashMap::new(), + pane_templates: HashMap::new(), + default_tab_template: None, + } + } + fn is_a_reserved_word(&self, word: &str) -> bool { + word == "pane" + || word == "layout" + || word == "pane_template" + || word == "tab_template" + || word == "default_tab_template" + || word == "command" + || word == "plugin" + || word == "children" + || word == "tab" + || word == "args" + || word == "borderless" + || word == "focus" + || word == "name" + || word == "size" + || word == "cwd" + || word == "split_direction" + } + fn is_a_valid_pane_property(&self, property_name: &str) -> bool { + property_name == "borderless" + || property_name == "focus" + || property_name == "name" + || property_name == "size" + || property_name == "plugin" + || property_name == "command" + || property_name == "cwd" + || property_name == "args" + || property_name == "split_direction" + || property_name == "pane" + || property_name == "children" + } + fn is_a_valid_tab_property(&self, property_name: &str) -> bool { + property_name == "focus" || property_name == "name" || property_name == "split_direction" + } + fn assert_legal_node_name(&self, name: &str, kdl_node: &KdlNode) -> Result<(), ConfigError> { + if name.contains(char::is_whitespace) { + Err(ConfigError::new_kdl_error( + format!("Node names ({}) cannot contain whitespace.", name), + kdl_node.span().offset(), + kdl_node.span().len(), + )) + } else if self.is_a_reserved_word(&name) { + Err(ConfigError::new_kdl_error( + format!("Node name '{}' is a reserved word.", name), + kdl_node.span().offset(), + kdl_node.span().len(), + )) + } else { + Ok(()) + } + } + fn parse_split_size(&self, kdl_node: &KdlNode) -> Result, ConfigError> { + if let Some(size) = kdl_get_string_property_or_child_value!(kdl_node, "size") { + Ok(Some(SplitSize::from_str(size)?)) + } else if let Some(size) = kdl_get_int_property_or_child_value!(kdl_node, "size") { + Ok(Some(SplitSize::Fixed(size as usize))) + } else if let Some(node) = kdl_property_or_child_value_node!(kdl_node, "size") { + Err(kdl_parsing_error!( + format!("size should be a fixed number (eg. 1) or a quoted percent (eg. \"50%\")"), + node + )) + } else if let Some(node) = kdl_child_with_name!(kdl_node, "size") { + Err(kdl_parsing_error!( + format!( + "size cannot be bare, it should have a value (eg. 'size 1', or 'size \"50%\"')" + ), + node + )) + } else { + Ok(None) + } + } + fn parse_plugin_block(&self, plugin_block: &KdlNode) -> Result, ConfigError> { + let _allow_exec_host_cmd = + kdl_get_bool_property_or_child_value_with_error!(plugin_block, "_allow_exec_host_cmd") + .unwrap_or(false); + let string_url = + kdl_get_string_property_or_child_value_with_error!(plugin_block, "location").ok_or( + ConfigError::new_kdl_error( + "Plugins must have a location".into(), + plugin_block.span().offset(), + plugin_block.span().len(), + ), + )?; + let url_node = kdl_get_property_or_child!(plugin_block, "location").ok_or( + ConfigError::new_kdl_error( + "Plugins must have a location".into(), + plugin_block.span().offset(), + plugin_block.span().len(), + ), + )?; + let url = Url::parse(string_url).map_err(|e| { + ConfigError::new_kdl_error( + format!("Failed to parse url: {:?}", e), + url_node.span().offset(), + url_node.span().len(), + ) + })?; + let location = RunPluginLocation::try_from(url)?; + Ok(Some(Run::Plugin(RunPlugin { + _allow_exec_host_cmd, + location, + }))) + } + fn parse_pane_command(&self, pane_node: &KdlNode) -> Result, ConfigError> { + let command = kdl_get_string_property_or_child_value_with_error!(pane_node, "command") + .map(|c| PathBuf::from(c)); + let cwd = kdl_get_string_property_or_child_value_with_error!(pane_node, "cwd") + .map(|c| PathBuf::from(c)); + let args = match kdl_get_child!(pane_node, "args") { + Some(kdl_args) => { + if kdl_args.entries().is_empty() { + return Err(kdl_parsing_error!(format!("args cannot be empty and should contain one or more command arguments (eg. args \"-h\" \"-v\")"), kdl_args)); + } + Some( + kdl_string_arguments!(kdl_args) + .iter() + .map(|s| String::from(*s)) + .collect(), + ) + }, + None => None, + }; + match (command, cwd, args) { + (None, Some(_cwd), _) => Err(ConfigError::new_kdl_error( + "cwd can only be set if a command was specified".into(), + pane_node.span().offset(), + pane_node.span().len(), + )), + (None, _, Some(_args)) => Err(ConfigError::new_kdl_error( + "args can only be set if a command was specified".into(), + pane_node.span().offset(), + pane_node.span().len(), + )), + (Some(command), cwd, args) => Ok(Some(Run::Command(RunCommand { + command, + args: args.unwrap_or_else(|| vec![]), + cwd, + }))), + _ => Ok(None), + } + } + fn parse_command_or_plugin_block( + &self, + kdl_node: &KdlNode, + ) -> Result, ConfigError> { + let mut run = self.parse_pane_command(kdl_node)?; + if let Some(plugin_block) = kdl_get_child!(kdl_node, "plugin") { + if run.is_some() { + return Err(ConfigError::new_kdl_error( + "Cannot have both a command and a plugin block for a single pane".into(), + plugin_block.span().offset(), + plugin_block.span().len(), + )); + } + run = self.parse_plugin_block(plugin_block)?; + } + Ok(run) + } + fn parse_pane_node(&self, kdl_node: &KdlNode) -> Result { + self.assert_valid_pane_properties(kdl_node)?; + let borderless = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless"); + let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); + let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") + .map(|name| name.to_string()); + let split_size = self.parse_split_size(kdl_node)?; + let run = self.parse_command_or_plugin_block(kdl_node)?; + let children_split_direction = self.parse_split_direction(kdl_node)?; + let (external_children_index, children) = match kdl_children_nodes!(kdl_node) { + Some(children) => self.parse_child_pane_nodes_for_pane(&children)?, + None => (None, vec![]), + }; + Ok(PaneLayout { + borderless: borderless.unwrap_or_default(), + focus, + name, + split_size, + run, + children_split_direction, + external_children_index, + children, + ..Default::default() + }) + } + fn parse_pane_node_with_template( + &self, + kdl_node: &KdlNode, + mut pane_layout: PaneLayout, + pane_layout_kdl_node: &KdlNode, + ) -> Result { + let borderless = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless"); + let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); + let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") + .map(|name| name.to_string()); + let split_size = self.parse_split_size(kdl_node)?; + let run = self.parse_command_or_plugin_block(kdl_node)?; + + let children_split_direction = self.parse_split_direction(kdl_node)?; + match kdl_children_nodes!(kdl_node) { + Some(children) => { + let child_panes = self.parse_child_pane_nodes_for_tab(children)?; + let child_panes_layout = PaneLayout { + children_split_direction, + children: child_panes, + ..Default::default() + }; + self.assert_one_children_block(&pane_layout, pane_layout_kdl_node)?; + self.insert_layout_children_or_error( + &mut pane_layout, + child_panes_layout, + pane_layout_kdl_node, + )?; + }, + None => { + if let Some(borderless) = borderless { + pane_layout.borderless = borderless; + } + if let Some(focus) = focus { + pane_layout.focus = Some(focus); + } + if let Some(name) = name { + pane_layout.name = Some(name); + } + if let Some(split_size) = split_size { + pane_layout.split_size = Some(split_size); + } + if let Some(run) = run { + pane_layout.run = Some(run); + } + if let Some(index_of_children) = pane_layout.external_children_index { + pane_layout + .children + .insert(index_of_children, PaneLayout::default()); + } + }, + } + pane_layout.external_children_index = None; + Ok(pane_layout) + } + fn parse_split_direction(&self, kdl_node: &KdlNode) -> Result { + Ok(match kdl_get_string_entry!(kdl_node, "split_direction") { + Some(direction) => SplitDirection::from_str(direction)?, + None => SplitDirection::default(), + }) + } + fn parse_pane_template_node(&mut self, kdl_node: &KdlNode) -> Result<(), ConfigError> { + self.assert_valid_pane_properties(kdl_node)?; + let template_name = kdl_get_string_property_or_child_value!(kdl_node, "name") + .map(|s| s.to_string()) + .ok_or(ConfigError::new_kdl_error( + "Pane templates must have a name".into(), + kdl_node.span().offset(), + kdl_node.span().len(), + ))?; + self.assert_legal_node_name(&template_name, kdl_node)?; + let borderless = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless"); + let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); + let split_size = self.parse_split_size(kdl_node)?; + let run = self.parse_command_or_plugin_block(kdl_node)?; + let children_split_direction = self.parse_split_direction(kdl_node)?; + let (external_children_index, pane_parts) = match kdl_children_nodes!(kdl_node) { + Some(children) => self.parse_child_pane_nodes_for_pane(&children)?, + None => (None, vec![]), + }; + self.pane_templates.insert( + template_name, + ( + PaneLayout { + borderless: borderless.unwrap_or_default(), + focus, + split_size, + run, + children_split_direction, + external_children_index, + children: pane_parts, + ..Default::default() + }, + kdl_node.clone(), + ), + ); + Ok(()) + } + fn parse_tab_node( + &mut self, + kdl_node: &KdlNode, + ) -> Result<(bool, Option, PaneLayout), ConfigError> { + // (is_focused, Option, PaneLayout) + self.assert_valid_tab_properties(kdl_node)?; + let tab_name = + kdl_get_string_property_or_child_value!(kdl_node, "name").map(|s| s.to_string()); + let is_focused = kdl_get_bool_property_or_child_value!(kdl_node, "focus").unwrap_or(false); + let children_split_direction = match kdl_get_string_entry!(kdl_node, "split_direction") { + Some(direction) => SplitDirection::from_str(direction)?, + None => SplitDirection::default(), + }; + let children = match kdl_children_nodes!(kdl_node) { + Some(children) => self.parse_child_pane_nodes_for_tab(children)?, + None => vec![], + }; + Ok(( + is_focused, + tab_name, + PaneLayout { + children_split_direction, + children, + ..Default::default() + }, + )) + } + fn parse_child_pane_nodes_for_tab( + &self, + children: &[KdlNode], + ) -> Result, ConfigError> { + let mut nodes = vec![]; + for child in children { + if kdl_name!(child) == "pane" { + nodes.push(self.parse_pane_node(child)?); + } else if let Some((pane_template, pane_template_kdl_node)) = + self.pane_templates.get(kdl_name!(child)).cloned() + { + nodes.push(self.parse_pane_node_with_template( + child, + pane_template, + &pane_template_kdl_node, + )?); + } else if self.is_a_valid_tab_property(kdl_name!(child)) { + return Err(ConfigError::new_kdl_error( + format!("Tab property '{}' must be placed on the tab title line and not in the child braces", kdl_name!(child)), + child.span().offset(), + child.span().len() + )); + } else { + return Err(ConfigError::new_kdl_error( + format!("Invalid tab property: {}", kdl_name!(child)), + child.span().offset(), + child.span().len(), + )); + } + } + if nodes.is_empty() { + nodes.push(PaneLayout::default()); + } + Ok(nodes) + } + fn parse_child_pane_nodes_for_pane( + &self, + children: &[KdlNode], + ) -> Result<(Option, Vec), ConfigError> { + // usize is external_children_index + let mut external_children_index = None; + let mut nodes = vec![]; + for (i, child) in children.iter().enumerate() { + if kdl_name!(child) == "pane" { + nodes.push(self.parse_pane_node(child)?); + } else if kdl_name!(child) == "children" { + external_children_index = Some(i); + } else if let Some((pane_template, pane_template_kdl_node)) = + self.pane_templates.get(kdl_name!(child)).cloned() + { + nodes.push(self.parse_pane_node_with_template( + child, + pane_template, + &pane_template_kdl_node, + )?); + } else if !self.is_a_valid_pane_property(kdl_name!(child)) { + return Err(ConfigError::new_kdl_error( + format!("Unknown pane property: {}", kdl_name!(child)), + child.span().offset(), + child.span().len(), + )); + } + } + Ok((external_children_index, nodes)) + } + fn assert_one_children_block( + &self, + layout: &PaneLayout, + kdl_node: &KdlNode, + ) -> Result<(), ConfigError> { + let children_block_count = layout.children_block_count(); + if children_block_count != 1 { + return Err(ConfigError::new_kdl_error(format!("This template has {} children blocks, only 1 is allowed when used to insert child panes", children_block_count), kdl_node.span().offset(), kdl_node.span().len())); + } + Ok(()) + } + fn assert_valid_pane_properties(&self, pane_node: &KdlNode) -> Result<(), ConfigError> { + for entry in pane_node.entries() { + match entry + .name() + .map(|e| e.value()) + .or_else(|| entry.value().as_string()) + { + Some(string_name) => { + if !self.is_a_valid_pane_property(string_name) { + return Err(ConfigError::new_kdl_error( + format!("Unknown pane property: {}", string_name), + entry.span().offset(), + entry.span().len(), + )); + } + }, + None => { + return Err(ConfigError::new_kdl_error( + "Unknown pane property".into(), + entry.span().offset(), + entry.span().len(), + )); + }, + } + } + Ok(()) + } + fn assert_valid_tab_properties(&self, pane_node: &KdlNode) -> Result<(), ConfigError> { + let all_property_names = kdl_property_names!(pane_node); + for name in all_property_names { + if !self.is_a_valid_tab_property(name) { + return Err(ConfigError::new_kdl_error( + format!("Invalid tab property '{}'", name), + pane_node.span().offset(), + pane_node.span().len(), + )); + } + } + Ok(()) + } + fn insert_layout_children_or_error( + &self, + layout: &mut PaneLayout, + mut child_panes_layout: PaneLayout, + kdl_node: &KdlNode, + ) -> Result<(), ConfigError> { + let successfully_inserted = layout.insert_children_layout(&mut child_panes_layout)?; + if !successfully_inserted { + Err(ConfigError::new_kdl_error( + "This template does not have children".into(), + kdl_node.span().offset(), + kdl_node.span().len(), + )) + } else { + Ok(()) + } + } + fn parse_tab_node_with_template( + &self, + kdl_node: &KdlNode, + mut tab_layout: PaneLayout, + tab_layout_kdl_node: &KdlNode, + ) -> Result<(bool, Option, PaneLayout), ConfigError> { + // (is_focused, Option, PaneLayout) + let tab_name = + kdl_get_string_property_or_child_value!(kdl_node, "name").map(|s| s.to_string()); + let is_focused = kdl_get_bool_property_or_child_value!(kdl_node, "focus").unwrap_or(false); + let children_split_direction = match kdl_get_string_entry!(kdl_node, "split_direction") { + Some(direction) => SplitDirection::from_str(direction)?, + None => SplitDirection::default(), + }; + match kdl_children_nodes!(kdl_node) { + Some(children) => { + let child_panes = self.parse_child_pane_nodes_for_tab(children)?; + let child_panes_layout = PaneLayout { + children_split_direction, + children: child_panes, + ..Default::default() + }; + self.assert_one_children_block(&tab_layout, &tab_layout_kdl_node)?; + self.insert_layout_children_or_error( + &mut tab_layout, + child_panes_layout, + &tab_layout_kdl_node, + )?; + }, + None => { + if let Some(index_of_children) = tab_layout.external_children_index { + tab_layout + .children + .insert(index_of_children, PaneLayout::default()); + } + }, + } + tab_layout.external_children_index = None; + Ok((is_focused, tab_name, tab_layout)) + } + fn populate_one_tab_template(&mut self, kdl_node: &KdlNode) -> Result<(), ConfigError> { + let template_name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") + .map(|s| s.to_string()) + .ok_or(ConfigError::new_kdl_error( + "Tab templates must have a name".into(), + kdl_node.span().offset(), + kdl_node.span().len(), + ))?; + self.assert_legal_node_name(&template_name, kdl_node)?; + self.tab_templates.insert( + template_name, + (self.parse_tab_template_node(kdl_node)?, kdl_node.clone()), + ); + Ok(()) + } + fn populate_default_tab_template(&mut self, kdl_node: &KdlNode) -> Result<(), ConfigError> { + self.default_tab_template = + Some((self.parse_tab_template_node(kdl_node)?, kdl_node.clone())); + Ok(()) + } + fn parse_tab_template_node(&self, kdl_node: &KdlNode) -> Result { + self.assert_valid_tab_properties(kdl_node)?; + let children_split_direction = + match kdl_get_string_property_or_child_value_with_error!(kdl_node, "split_direction") { + Some(direction) => SplitDirection::from_str(direction)?, + None => SplitDirection::default(), + }; + let mut tab_children = vec![]; + let mut external_children_index = None; + if let Some(children) = kdl_children_nodes!(kdl_node) { + for (i, child) in children.iter().enumerate() { + if kdl_name!(child) == "pane" { + tab_children.push(self.parse_pane_node(child)?); + } else if kdl_name!(child) == "children" { + external_children_index = Some(i); + } else if let Some((pane_template, pane_template_kdl_node)) = + self.pane_templates.get(kdl_name!(child)).cloned() + { + tab_children.push(self.parse_pane_node_with_template( + child, + pane_template, + &pane_template_kdl_node, + )?); + } else if self.is_a_valid_tab_property(kdl_name!(child)) { + return Err(ConfigError::new_kdl_error( + format!("Tab property '{}' must be placed on the tab_template title line and not in the child braces", kdl_name!(child)), + child.span().offset(), + child.span().len() + )); + } else { + return Err(ConfigError::new_kdl_error( + format!("Invalid tab_template property: {}", kdl_name!(child)), + child.span().offset(), + child.span().len(), + )); + } + } + } + Ok(PaneLayout { + children_split_direction, + children: tab_children, + external_children_index, + ..Default::default() + }) + } + fn default_template(&self) -> Result, ConfigError> { + match &self.default_tab_template { + Some((template, _kdl_node)) => { + let mut template = template.clone(); + if let Some(children_index) = template.external_children_index { + template + .children + .insert(children_index, PaneLayout::default()) + } + template.external_children_index = None; + Ok(Some(template)) + }, + None => Ok(None), + } + } + pub fn get_pane_template_dependency_tree( + &self, + kdl_children: &'a [KdlNode], + ) -> Result>, ConfigError> { + let mut dependency_tree = HashMap::new(); + for child in kdl_children { + if kdl_name!(child) == "pane_template" { + let template_name = kdl_get_string_property_or_child_value!(child, "name").ok_or( + ConfigError::new_kdl_error( + "Pane templates must have a name".into(), + child.span().offset(), + child.span().len(), + ), + )?; + let mut template_children = HashSet::new(); + self.get_pane_template_dependencies(child, &mut template_children)?; + dependency_tree.insert(template_name, template_children); + } + } + Ok(dependency_tree) + } + fn get_pane_template_dependencies( + &self, + node: &'a KdlNode, + all_dependencies: &mut HashSet<&'a str>, + ) -> Result<(), ConfigError> { + if let Some(children) = kdl_children_nodes!(node) { + for child in children { + let child_name = kdl_name!(child); + if child_name == "pane" { + self.get_pane_template_dependencies(child, all_dependencies)?; + } else if !self.is_a_reserved_word(child_name) { + all_dependencies.insert(child_name); + self.get_pane_template_dependencies(child, all_dependencies)?; + } + } + } + Ok(()) + } + pub fn parse_pane_template_by_name( + &mut self, + pane_template_name: &str, + kdl_children: &[KdlNode], + ) -> Result<(), ConfigError> { + for child in kdl_children.iter() { + let child_name = kdl_name!(child); + if child_name == "pane_template" { + let child_name = kdl_get_string_property_or_child_value!(child, "name"); + if child_name == Some(pane_template_name) { + self.parse_pane_template_node(child)?; + } + } + } + Ok(()) + } + fn populate_pane_templates( + &mut self, + layout_children: &[KdlNode], + kdl_layout: &KdlDocument, + ) -> Result<(), ConfigError> { + let mut pane_template_dependency_tree = + self.get_pane_template_dependency_tree(layout_children)?; + let mut pane_template_names_to_parse: Vec<&str> = vec![]; + // toposort the dependency tree so that we parse the pane_templates before their + // dependencies + while !pane_template_dependency_tree.is_empty() { + let mut candidates: Vec<&str> = vec![]; + for (pane_tempalte, dependencies) in pane_template_dependency_tree.iter() { + if dependencies.is_empty() { + candidates.push(pane_tempalte); + } + } + if candidates.is_empty() { + return Err(ConfigError::new_kdl_error( + "Circular dependency detected between pane templates.".into(), + kdl_layout.span().offset(), + kdl_layout.span().len(), + )); + } + for candidate_to_remove in candidates { + pane_template_dependency_tree.remove(candidate_to_remove); + for (_pane_tempalte, dependencies) in pane_template_dependency_tree.iter_mut() { + dependencies.remove(candidate_to_remove); + } + pane_template_names_to_parse.push(candidate_to_remove); + } + } + // once we've toposorted, parse the sorted list in order + for pane_template_name in pane_template_names_to_parse { + self.parse_pane_template_by_name(pane_template_name, &layout_children)?; + } + Ok(()) + } + fn populate_tab_templates(&mut self, layout_children: &[KdlNode]) -> Result<(), ConfigError> { + for child in layout_children.iter() { + let child_name = kdl_name!(child); + if child_name == "tab_template" { + self.populate_one_tab_template(child)?; + } else if child_name == "default_tab_template" { + self.populate_default_tab_template(child)?; + } + } + Ok(()) + } + fn layout_with_tabs( + &self, + tabs: Vec<(Option, PaneLayout)>, + focused_tab_index: Option, + ) -> Result { + let template = self + .default_template()? + .unwrap_or_else(|| PaneLayout::default()); + + Ok(Layout { + tabs: tabs, + template: Some(template), + focused_tab_index, + ..Default::default() + }) + } + fn layout_with_one_tab(&self, panes: Vec) -> Result { + let main_tab_layout = PaneLayout { + children: panes, + ..Default::default() + }; + let default_template = self.default_template()?; + let tabs = if default_template.is_none() { + // in this case, the layout will be created as the default template and we don't need + // to explicitly place it in the first tab + vec![] + } else { + vec![(None, main_tab_layout.clone())] + }; + let template = default_template.unwrap_or_else(|| main_tab_layout.clone()); + // create a layout with one tab that has these child panes + Ok(Layout { + tabs, + template: Some(template), + ..Default::default() + }) + } + fn layout_with_one_pane(&self) -> Result { + let template = self + .default_template()? + .unwrap_or_else(|| PaneLayout::default()); + Ok(Layout { + template: Some(template), + ..Default::default() + }) + } + fn populate_layout_child( + &mut self, + child: &KdlNode, + child_tabs: &mut Vec<(bool, Option, PaneLayout)>, + child_panes: &mut Vec, + ) -> Result<(), ConfigError> { + let child_name = kdl_name!(child); + if child_name == "pane" { + if !child_tabs.is_empty() { + return Err(ConfigError::new_kdl_error( + "Cannot have both tabs and panes in the same node".into(), + child.span().offset(), + child.span().len(), + )); + } + child_panes.push(self.parse_pane_node(child)?); + } else if child_name == "tab" { + if !child_panes.is_empty() { + return Err(ConfigError::new_kdl_error( + "Cannot have both tabs and panes in the same node".into(), + child.span().offset(), + child.span().len(), + )); + } + match &self.default_tab_template { + Some((default_tab_template, default_tab_template_kdl_node)) => { + let default_tab_template = default_tab_template.clone(); + child_tabs.push(self.parse_tab_node_with_template( + child, + default_tab_template, + default_tab_template_kdl_node, + )?); + }, + None => { + child_tabs.push(self.parse_tab_node(child)?); + }, + } + } else if let Some((tab_template, tab_template_kdl_node)) = + self.tab_templates.get(child_name).cloned() + { + if !child_panes.is_empty() { + return Err(ConfigError::new_kdl_error( + "Cannot have both tabs and panes in the same node".into(), + child.span().offset(), + child.span().len(), + )); + } + child_tabs.push(self.parse_tab_node_with_template( + child, + tab_template, + &tab_template_kdl_node, + )?); + } else if let Some((pane_template, pane_template_kdl_node)) = + self.pane_templates.get(child_name).cloned() + { + if !child_tabs.is_empty() { + return Err(ConfigError::new_kdl_error( + "Cannot have both tabs and panes in the same node".into(), + child.span().offset(), + child.span().len(), + )); + } + child_panes.push(self.parse_pane_node_with_template( + child, + pane_template, + &pane_template_kdl_node, + )?); + } else if !self.is_a_reserved_word(child_name) { + return Err(ConfigError::new_kdl_error( + format!("Unknown layout node: '{}'", child_name), + child.span().offset(), + child.span().len(), + )); + } + Ok(()) + } + pub fn parse(&mut self) -> Result { + let kdl_layout: KdlDocument = self.raw_layout.parse()?; + let layout_node = kdl_layout + .nodes() + .iter() + .find(|n| kdl_name!(n) == "layout") + .ok_or(ConfigError::new_kdl_error( + "No layout found".into(), + kdl_layout.span().offset(), + kdl_layout.span().len(), + ))?; + let has_multiple_layout_nodes = kdl_layout + .nodes() + .iter() + .filter(|n| kdl_name!(n) == "layout") + .count() + > 1; + if has_multiple_layout_nodes { + return Err(ConfigError::new_kdl_error( + "Only one layout node per file allowed".into(), + kdl_layout.span().offset(), + kdl_layout.span().len(), + )); + } + let mut child_tabs = vec![]; + let mut child_panes = vec![]; + if let Some(children) = kdl_children_nodes!(layout_node) { + self.populate_pane_templates(children, &kdl_layout)?; + self.populate_tab_templates(children)?; + for child in children { + self.populate_layout_child(child, &mut child_tabs, &mut child_panes)?; + } + } + if !child_tabs.is_empty() { + let has_more_than_one_focused_tab = child_tabs + .iter() + .filter(|(is_focused, _, _)| *is_focused) + .count() + > 1; + if has_more_than_one_focused_tab { + return Err(ConfigError::new_kdl_error( + "Only one tab can be focused".into(), + kdl_layout.span().offset(), + kdl_layout.span().len(), + )); + } + let focused_tab_index = child_tabs.iter().position(|(is_focused, _, _)| *is_focused); + let child_tabs: Vec<(Option, PaneLayout)> = child_tabs + .drain(..) + .map(|(_is_focused, tab_name, pane_layout)| (tab_name, pane_layout)) + .collect(); + self.layout_with_tabs(child_tabs, focused_tab_index) + } else if !child_panes.is_empty() { + self.layout_with_one_tab(child_panes) + } else { + self.layout_with_one_pane() + } + } +} diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs new file mode 100644 index 00000000..7092653c --- /dev/null +++ b/zellij-utils/src/kdl/mod.rs @@ -0,0 +1,1626 @@ +mod kdl_layout_parser; +use crate::data::{InputMode, Key, Palette, PaletteColor}; +use crate::envs::EnvironmentVariables; +use crate::input::command::RunCommand; +use crate::input::config::{Config, ConfigError, KdlError}; +use crate::input::keybinds::Keybinds; +use crate::input::layout::{Layout, RunPlugin, RunPluginLocation}; +use crate::input::options::{Clipboard, OnForceClose, Options}; +use crate::input::plugins::{PluginConfig, PluginTag, PluginType, PluginsConfig}; +use crate::input::theme::{FrameConfig, Theme, Themes, UiConfig}; +use kdl_layout_parser::KdlLayoutParser; +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use strum::IntoEnumIterator; +use url::Url; + +use miette::NamedSource; + +use kdl::{KdlDocument, KdlEntry, KdlNode}; + +use std::path::PathBuf; +use std::str::FromStr; + +use crate::input::actions::{Action, Direction, ResizeDirection, SearchDirection, SearchOption}; +use crate::input::command::RunCommandAction; + +#[macro_export] +macro_rules! parse_kdl_action_arguments { + ( $action_name:expr, $action_arguments:expr, $action_node:expr ) => {{ + if !$action_arguments.is_empty() { + Err(ConfigError::new_kdl_error( + format!("Action '{}' must have arguments", $action_name), + $action_node.span().offset(), + $action_node.span().len(), + )) + } else { + match $action_name { + "Quit" => Ok(Action::Quit), + "FocusNextPane" => Ok(Action::FocusNextPane), + "FocusPreviousPane" => Ok(Action::FocusPreviousPane), + "SwitchFocus" => Ok(Action::SwitchFocus), + "EditScrollback" => Ok(Action::EditScrollback), + "ScrollUp" => Ok(Action::ScrollUp), + "ScrollDown" => Ok(Action::ScrollDown), + "ScrollToBottom" => Ok(Action::ScrollToBottom), + "PageScrollUp" => Ok(Action::PageScrollUp), + "PageScrollDown" => Ok(Action::PageScrollDown), + "HalfPageScrollUp" => Ok(Action::HalfPageScrollUp), + "HalfPageScrollDown" => Ok(Action::HalfPageScrollDown), + "ToggleFocusFullscreen" => Ok(Action::ToggleFocusFullscreen), + "TogglePaneFrames" => Ok(Action::TogglePaneFrames), + "ToggleActiveSyncTab" => Ok(Action::ToggleActiveSyncTab), + "TogglePaneEmbedOrFloating" => Ok(Action::TogglePaneEmbedOrFloating), + "ToggleFloatingPanes" => Ok(Action::ToggleFloatingPanes), + "CloseFocus" => Ok(Action::CloseFocus), + "UndoRenamePane" => Ok(Action::UndoRenamePane), + "NoOp" => Ok(Action::NoOp), + "GoToNextTab" => Ok(Action::GoToNextTab), + "GoToPreviousTab" => Ok(Action::GoToPreviousTab), + "CloseTab" => Ok(Action::CloseTab), + "ToggleTab" => Ok(Action::ToggleTab), + "UndoRenameTab" => Ok(Action::UndoRenameTab), + "Detach" => Ok(Action::Detach), + "Copy" => Ok(Action::Copy), + "Confirm" => Ok(Action::Confirm), + "Deny" => Ok(Action::Deny), + _ => Err(ConfigError::new_kdl_error( + format!("Unsupported action: {:?}", $action_name), + $action_node.span().offset(), + $action_node.span().len(), + )), + } + } + }}; +} + +#[macro_export] +macro_rules! parse_kdl_action_u8_arguments { + ( $action_name:expr, $action_arguments:expr, $action_node:expr ) => {{ + let mut bytes = vec![]; + for kdl_entry in $action_arguments.iter() { + match kdl_entry.value().as_i64() { + Some(int_value) => bytes.push(int_value as u8), + None => { + return Err(ConfigError::new_kdl_error( + format!("Arguments for '{}' must be integers", $action_name), + kdl_entry.span().offset(), + kdl_entry.span().len(), + )); + }, + } + } + Action::new_from_bytes($action_name, bytes, $action_node) + }}; +} + +#[macro_export] +macro_rules! kdl_parsing_error { + ( $message:expr, $entry:expr ) => { + ConfigError::new_kdl_error($message, $entry.span().offset(), $entry.span().len()) + }; +} + +#[macro_export] +macro_rules! kdl_entries_as_i64 { + ( $node:expr ) => { + $node + .entries() + .iter() + .map(|kdl_node| kdl_node.value().as_i64()) + }; +} + +#[macro_export] +macro_rules! kdl_first_entry_as_string { + ( $node:expr ) => { + $node + .entries() + .iter() + .next() + .and_then(|s| s.value().as_string()) + }; +} + +#[macro_export] +macro_rules! kdl_first_entry_as_i64 { + ( $node:expr ) => { + $node + .entries() + .iter() + .next() + .and_then(|i| i.value().as_i64()) + }; +} + +#[macro_export] +macro_rules! entry_count { + ( $node:expr ) => {{ + $node.entries().iter().len() + }}; +} + +#[macro_export] +macro_rules! parse_kdl_action_char_or_string_arguments { + ( $action_name:expr, $action_arguments:expr, $action_node:expr ) => {{ + let mut chars_to_write = String::new(); + for kdl_entry in $action_arguments.iter() { + match kdl_entry.value().as_string() { + Some(string_value) => chars_to_write.push_str(string_value), + None => { + return Err(ConfigError::new_kdl_error( + format!("All entries for action '{}' must be strings", $action_name), + kdl_entry.span().offset(), + kdl_entry.span().len(), + )) + }, + } + } + Action::new_from_string($action_name, chars_to_write, $action_node) + }}; +} + +#[macro_export] +macro_rules! kdl_arg_is_truthy { + ( $kdl_node:expr, $arg_name:expr ) => { + match $kdl_node.get($arg_name) { + Some(arg) => match arg.value().as_bool() { + Some(value) => value, + None => { + return Err(ConfigError::new_kdl_error( + format!("Argument must be true or false, found: {}", arg.value()), + arg.span().offset(), + arg.span().len(), + )) + }, + }, + None => false, + } + }; +} + +#[macro_export] +macro_rules! kdl_children_nodes_or_error { + ( $kdl_node:expr, $error:expr ) => { + $kdl_node + .children() + .ok_or(ConfigError::new_kdl_error( + $error.into(), + $kdl_node.span().offset(), + $kdl_node.span().len(), + ))? + .nodes() + }; +} + +#[macro_export] +macro_rules! kdl_children_nodes { + ( $kdl_node:expr ) => { + $kdl_node.children().map(|c| c.nodes()) + }; +} + +#[macro_export] +macro_rules! kdl_property_nodes { + ( $kdl_node:expr ) => {{ + $kdl_node + .entries() + .iter() + .filter_map(|e| e.name()) + .map(|e| e.value()) + }}; +} + +#[macro_export] +macro_rules! kdl_children_or_error { + ( $kdl_node:expr, $error:expr ) => { + $kdl_node.children().ok_or(ConfigError::new_kdl_error( + $error.into(), + $kdl_node.span().offset(), + $kdl_node.span().len(), + ))? + }; +} + +#[macro_export] +macro_rules! kdl_children { + ( $kdl_node:expr ) => { + $kdl_node.children().iter().copied().collect() + }; +} + +#[macro_export] +macro_rules! kdl_string_arguments { + ( $kdl_node:expr ) => {{ + let res: Result, _> = $kdl_node + .entries() + .iter() + .map(|e| { + e.value().as_string().ok_or(ConfigError::new_kdl_error( + "Not a string".into(), + e.span().offset(), + e.span().len(), + )) + }) + .collect(); + res? + }}; +} + +#[macro_export] +macro_rules! kdl_property_names { + ( $kdl_node:expr ) => {{ + $kdl_node + .entries() + .iter() + .filter_map(|e| e.name()) + .map(|e| e.value()) + }}; +} + +#[macro_export] +macro_rules! kdl_argument_values { + ( $kdl_node:expr ) => { + $kdl_node.entries().iter().collect() + }; +} + +#[macro_export] +macro_rules! kdl_name { + ( $kdl_node:expr ) => { + $kdl_node.name().value() + }; +} + +#[macro_export] +macro_rules! kdl_document_name { + ( $kdl_node:expr ) => { + $kdl_node.node().name().value() + }; +} + +#[macro_export] +macro_rules! keys_from_kdl { + ( $kdl_node:expr ) => { + kdl_string_arguments!($kdl_node) + .iter() + .map(|k| { + Key::from_str(k).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid key: '{}'", k), + $kdl_node.span().offset(), + $kdl_node.span().len(), + ) + }) + }) + .collect::>()? + }; +} + +#[macro_export] +macro_rules! actions_from_kdl { + ( $kdl_node:expr ) => { + kdl_children_nodes_or_error!($kdl_node, "no actions found for key_block") + .iter() + .map(|kdl_action| Action::try_from(kdl_action)) + .collect::>()? + }; +} + +pub fn kdl_arguments_that_are_strings<'a>( + arguments: impl Iterator, +) -> Result, ConfigError> { + // pub fn kdl_arguments_that_are_strings <'a>(arguments: impl Iterator) -> Result, ConfigError> { + let mut args: Vec = vec![]; + for kdl_entry in arguments { + match kdl_entry.value().as_string() { + Some(string_value) => args.push(string_value.to_string()), + None => { + return Err(ConfigError::new_kdl_error( + format!("Argument must be a string"), + kdl_entry.span().offset(), + kdl_entry.span().len(), + )); + }, + } + } + Ok(args) +} + +pub fn kdl_child_string_value_for_entry<'a>( + command_metadata: &'a KdlDocument, + entry_name: &'a str, +) -> Option<&'a str> { + command_metadata + .get(entry_name) + .and_then(|cwd| cwd.entries().iter().next()) + .and_then(|cwd_value| cwd_value.value().as_string()) +} + +impl Action { + pub fn new_from_bytes( + action_name: &str, + bytes: Vec, + action_node: &KdlNode, + ) -> Result { + match action_name { + "Write" => Ok(Action::Write(bytes)), + "PaneNameInput" => Ok(Action::PaneNameInput(bytes)), + "TabNameInput" => Ok(Action::TabNameInput(bytes)), + "SearchInput" => Ok(Action::SearchInput(bytes)), + "GoToTab" => { + let tab_index = *bytes.get(0).ok_or_else(|| { + ConfigError::new_kdl_error( + format!("Missing tab index"), + action_node.span().offset(), + action_node.span().len(), + ) + })? as u32; + Ok(Action::GoToTab(tab_index)) + }, + _ => Err(ConfigError::new_kdl_error( + "Failed to parse action".into(), + action_node.span().offset(), + action_node.span().len(), + )), + } + } + pub fn new_from_string( + action_name: &str, + string: String, + action_node: &KdlNode, + ) -> Result { + match action_name { + "WriteChars" => Ok(Action::WriteChars(string)), + "SwitchToMode" => match InputMode::from_str(string.as_str()) { + Ok(input_mode) => Ok(Action::SwitchToMode(input_mode)), + Err(_e) => { + return Err(ConfigError::new_kdl_error( + format!("Unknown InputMode '{}'", string), + action_node.span().offset(), + action_node.span().len(), + )) + }, + }, + "Resize" => { + let direction = ResizeDirection::from_str(string.as_str()).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid direction: '{}'", string), + action_node.span().offset(), + action_node.span().len(), + ) + })?; + Ok(Action::Resize(direction)) + }, + "MoveFocus" => { + let direction = Direction::from_str(string.as_str()).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid direction: '{}'", string), + action_node.span().offset(), + action_node.span().len(), + ) + })?; + Ok(Action::MoveFocus(direction)) + }, + "MoveFocusOrTab" => { + let direction = Direction::from_str(string.as_str()).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid direction: '{}'", string), + action_node.span().offset(), + action_node.span().len(), + ) + })?; + Ok(Action::MoveFocusOrTab(direction)) + }, + "MovePane" => { + if string.is_empty() { + return Ok(Action::MovePane(None)); + } else { + let direction = Direction::from_str(string.as_str()).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid direction: '{}'", string), + action_node.span().offset(), + action_node.span().len(), + ) + })?; + Ok(Action::MovePane(Some(direction))) + } + }, + "DumpScreen" => Ok(Action::DumpScreen(string)), + "NewPane" => { + if string.is_empty() { + return Ok(Action::NewPane(None)); + } else { + let direction = Direction::from_str(string.as_str()).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid direction: '{}'", string), + action_node.span().offset(), + action_node.span().len(), + ) + })?; + Ok(Action::NewPane(Some(direction))) + } + }, + "SearchToggleOption" => { + let toggle_option = SearchOption::from_str(string.as_str()).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid direction: '{}'", string), + action_node.span().offset(), + action_node.span().len(), + ) + })?; + Ok(Action::SearchToggleOption(toggle_option)) + }, + "Search" => { + let search_direction = + SearchDirection::from_str(string.as_str()).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid direction: '{}'", string), + action_node.span().offset(), + action_node.span().len(), + ) + })?; + Ok(Action::Search(search_direction)) + }, + _ => Err(ConfigError::new_kdl_error( + format!("Unsupported action: {}", action_name), + action_node.span().offset(), + action_node.span().len(), + )), + } + } +} + +impl TryFrom<(&str, &KdlDocument)> for PaletteColor { + type Error = ConfigError; + + fn try_from( + (color_name, theme_colors): (&str, &KdlDocument), + ) -> Result { + let color = theme_colors + .get(color_name) + .ok_or(ConfigError::new_kdl_error( + format!("Missing theme color: {}", color_name), + theme_colors.span().offset(), + theme_colors.span().len(), + ))?; + let entry_count = entry_count!(color); + let is_rgb = || entry_count == 3; + let is_three_digit_hex = || { + match kdl_first_entry_as_string!(color) { + // 4 including the '#' character + Some(s) => entry_count == 1 && s.starts_with('#') && s.len() == 4, + None => false, + } + }; + let is_six_digit_hex = || { + match kdl_first_entry_as_string!(color) { + // 7 including the '#' character + Some(s) => entry_count == 1 && s.starts_with('#') && s.len() == 7, + None => false, + } + }; + let is_eight_bit = || kdl_first_entry_as_i64!(color).is_some() && entry_count == 1; + if is_rgb() { + let mut channels = kdl_entries_as_i64!(color); + let r = channels.next().unwrap().ok_or(ConfigError::new_kdl_error( + format!("invalid rgb color"), + color.span().offset(), + color.span().len(), + ))? as u8; + let g = channels.next().unwrap().ok_or(ConfigError::new_kdl_error( + format!("invalid rgb color"), + color.span().offset(), + color.span().len(), + ))? as u8; + let b = channels.next().unwrap().ok_or(ConfigError::new_kdl_error( + format!("invalid rgb color"), + color.span().offset(), + color.span().len(), + ))? as u8; + Ok(PaletteColor::Rgb((r, g, b))) + } else if is_three_digit_hex() { + // eg. #fff (hex, will be converted to rgb) + let mut s = String::from(kdl_first_entry_as_string!(color).unwrap()); + s.remove(0); + let r = u8::from_str_radix(&s[0..1], 16).map_err(|_| { + ConfigError::new_kdl_error( + "Failed to parse hex color".into(), + color.span().offset(), + color.span().len(), + ) + })? * 0x11; + let g = u8::from_str_radix(&s[1..2], 16).map_err(|_| { + ConfigError::new_kdl_error( + "Failed to parse hex color".into(), + color.span().offset(), + color.span().len(), + ) + })? * 0x11; + let b = u8::from_str_radix(&s[2..3], 16).map_err(|_| { + ConfigError::new_kdl_error( + "Failed to parse hex color".into(), + color.span().offset(), + color.span().len(), + ) + })? * 0x11; + Ok(PaletteColor::Rgb((r, g, b))) + } else if is_six_digit_hex() { + // eg. #ffffff (hex, will be converted to rgb) + let mut s = String::from(kdl_first_entry_as_string!(color).unwrap()); + s.remove(0); + let r = u8::from_str_radix(&s[0..2], 16).map_err(|_| { + ConfigError::new_kdl_error( + "Failed to parse hex color".into(), + color.span().offset(), + color.span().len(), + ) + })?; + let g = u8::from_str_radix(&s[2..4], 16).map_err(|_| { + ConfigError::new_kdl_error( + "Failed to parse hex color".into(), + color.span().offset(), + color.span().len(), + ) + })?; + let b = u8::from_str_radix(&s[4..6], 16).map_err(|_| { + ConfigError::new_kdl_error( + "Failed to parse hex color".into(), + color.span().offset(), + color.span().len(), + ) + })?; + Ok(PaletteColor::Rgb((r, g, b))) + } else if is_eight_bit() { + let n = kdl_first_entry_as_i64!(color).ok_or(ConfigError::new_kdl_error( + "Failed to parse color".into(), + color.span().offset(), + color.span().len(), + ))?; + Ok(PaletteColor::EightBit(n as u8)) + } else { + Err(ConfigError::new_kdl_error( + "Failed to parse color".into(), + color.span().offset(), + color.span().len(), + )) + } + } +} + +impl TryFrom<&KdlNode> for Action { + // type Error = Box; + type Error = ConfigError; + fn try_from(kdl_action: &KdlNode) -> Result { + let action_name = kdl_name!(kdl_action); + let action_arguments: Vec<&KdlEntry> = kdl_argument_values!(kdl_action); + // let action_arguments: Vec<&KdlValue> = kdl_argument_values!(kdl_action); + let action_children: Vec<&KdlDocument> = kdl_children!(kdl_action); + match action_name { + "Quit" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "FocusNextPane" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "FocusPreviousPane" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "SwitchFocus" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "EditScrollback" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "ScrollUp" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "ScrollDown" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "ScrollToBottom" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "PageScrollUp" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "PageScrollDown" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "HalfPageScrollUp" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "HalfPageScrollDown" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "ToggleFocusFullscreen" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "TogglePaneFrames" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "ToggleActiveSyncTab" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "TogglePaneEmbedOrFloating" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "ToggleFloatingPanes" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "CloseFocus" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "UndoRenamePane" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "NoOp" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "GoToNextTab" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "GoToPreviousTab" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "CloseTab" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "ToggleTab" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "UndoRenameTab" => { + parse_kdl_action_arguments!(action_name, action_arguments, kdl_action) + }, + "Detach" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "Copy" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "Confirm" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "Deny" => parse_kdl_action_arguments!(action_name, action_arguments, kdl_action), + "Write" => parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action), + "WriteChars" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "SwitchToMode" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "Search" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "Resize" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "MoveFocus" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "MoveFocusOrTab" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "MovePane" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "DumpScreen" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "NewPane" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "PaneNameInput" => { + parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action) + }, + "NewTab" => Ok(Action::NewTab(None, None)), + "GoToTab" => parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action), + "TabNameInput" => { + parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action) + }, + "SearchInput" => { + parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action) + }, + "SearchToggleOption" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), + "Run" => { + let arguments = action_arguments.iter().copied(); + let mut args = kdl_arguments_that_are_strings(arguments)?; + if args.is_empty() { + return Err(ConfigError::new_kdl_error( + "No command found in Run action".into(), + kdl_action.span().offset(), + kdl_action.span().len(), + )); + } + let command = args.remove(0); + let command_metadata = action_children.iter().next(); + let cwd = command_metadata + .and_then(|c_m| kdl_child_string_value_for_entry(c_m, "cwd")) + .map(|cwd_string| PathBuf::from(cwd_string)); + let direction = command_metadata + .and_then(|c_m| kdl_child_string_value_for_entry(c_m, "direction")) + .and_then(|direction_string| Direction::from_str(direction_string).ok()); + let run_command_action = RunCommandAction { + command: PathBuf::from(command), + args, + cwd, + direction, + }; + Ok(Action::Run(run_command_action)) + }, + _ => Err(ConfigError::new_kdl_error( + format!("Unsupported action: {}", action_name).into(), + kdl_action.span().offset(), + kdl_action.span().len(), + )), + } + } +} + +#[macro_export] +macro_rules! kdl_property_first_arg_as_string { + ( $kdl_node:expr, $property_name:expr ) => { + $kdl_node + .get($property_name) + .and_then(|p| p.entries().iter().next()) + .and_then(|p| p.value().as_string()) + }; +} + +#[macro_export] +macro_rules! kdl_property_first_arg_as_string_or_error { + ( $kdl_node:expr, $property_name:expr ) => {{ + match $kdl_node.get($property_name) { + Some(property) => match property.entries().iter().next() { + Some(first_entry) => match first_entry.value().as_string() { + Some(string_entry) => Some((string_entry, first_entry)), + None => { + return Err(ConfigError::new_kdl_error( + format!( + "Property {} must be a string, found: {}", + $property_name, + first_entry.value() + ), + property.span().offset(), + property.span().len(), + )); + }, + }, + None => { + return Err(ConfigError::new_kdl_error( + format!("Property {} must have a value", $property_name), + property.span().offset(), + property.span().len(), + )); + }, + }, + None => None, + } + }}; +} + +#[macro_export] +macro_rules! kdl_property_first_arg_as_bool_or_error { + ( $kdl_node:expr, $property_name:expr ) => {{ + match $kdl_node.get($property_name) { + Some(property) => match property.entries().iter().next() { + Some(first_entry) => match first_entry.value().as_bool() { + Some(bool_entry) => Some((bool_entry, first_entry)), + None => { + return Err(ConfigError::new_kdl_error( + format!( + "Property {} must be true or false, found {}", + $property_name, + first_entry.value() + ), + property.span().offset(), + property.span().len(), + )); + }, + }, + None => { + return Err(ConfigError::new_kdl_error( + format!("Property {} must have a value", $property_name), + property.span().offset(), + property.span().len(), + )); + }, + }, + None => None, + } + }}; +} + +#[macro_export] +macro_rules! kdl_property_first_arg_as_i64_or_error { + ( $kdl_node:expr, $property_name:expr ) => {{ + match $kdl_node.get($property_name) { + Some(property) => match property.entries().iter().next() { + Some(first_entry) => match first_entry.value().as_i64() { + Some(int_entry) => Some((int_entry, first_entry)), + None => { + return Err(ConfigError::new_kdl_error( + format!( + "Property {} must be numeric, found {}", + $property_name, + first_entry.value() + ), + property.span().offset(), + property.span().len(), + )); + }, + }, + None => { + return Err(ConfigError::new_kdl_error( + format!("Property {} must have a value", $property_name), + property.span().offset(), + property.span().len(), + )); + }, + }, + None => None, + } + }}; +} + +#[macro_export] +macro_rules! kdl_has_string_argument { + ( $kdl_node:expr, $string_argument:expr ) => { + $kdl_node + .entries() + .iter() + .find(|e| e.value().as_string() == Some($string_argument)) + .is_some() + }; +} + +#[macro_export] +macro_rules! kdl_children_property_first_arg_as_string { + ( $kdl_node:expr, $property_name:expr ) => { + $kdl_node + .children() + .and_then(|c| c.get($property_name)) + .and_then(|p| p.entries().iter().next()) + .and_then(|p| p.value().as_string()) + }; +} + +#[macro_export] +macro_rules! kdl_property_first_arg_as_bool { + ( $kdl_node:expr, $property_name:expr ) => { + $kdl_node + .get($property_name) + .and_then(|p| p.entries().iter().next()) + .and_then(|p| p.value().as_bool()) + }; +} + +#[macro_export] +macro_rules! kdl_children_property_first_arg_as_bool { + ( $kdl_node:expr, $property_name:expr ) => { + $kdl_node + .children() + .and_then(|c| c.get($property_name)) + .and_then(|p| p.entries().iter().next()) + .and_then(|p| p.value().as_bool()) + }; +} + +#[macro_export] +macro_rules! kdl_property_first_arg_as_i64 { + ( $kdl_node:expr, $property_name:expr ) => { + $kdl_node + .get($property_name) + .and_then(|p| p.entries().iter().next()) + .and_then(|p| p.value().as_i64()) + }; +} + +#[macro_export] +macro_rules! kdl_get_child { + ( $kdl_node:expr, $child_name:expr ) => { + $kdl_node.children().and_then(|c| c.get($child_name)) + }; +} + +#[macro_export] +macro_rules! kdl_get_child_entry_bool_value { + ( $kdl_node:expr, $child_name:expr ) => { + $kdl_node + .children() + .and_then(|c| c.get($child_name)) + .and_then(|c| c.get(0)) + .and_then(|c| c.value().as_bool()) + }; +} + +#[macro_export] +macro_rules! kdl_get_child_entry_string_value { + ( $kdl_node:expr, $child_name:expr ) => { + $kdl_node + .children() + .and_then(|c| c.get($child_name)) + .and_then(|c| c.get(0)) + .and_then(|c| c.value().as_string()) + }; +} + +#[macro_export] +macro_rules! kdl_get_bool_property_or_child_value { + ( $kdl_node:expr, $name:expr ) => { + $kdl_node + .get($name) + .and_then(|e| e.value().as_bool()) + .or_else(|| { + $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)) + .and_then(|c| c.value().as_bool()) + }) + }; +} + +#[macro_export] +macro_rules! kdl_get_bool_property_or_child_value_with_error { + ( $kdl_node:expr, $name:expr ) => { + match $kdl_node.get($name) { + Some(e) => match e.value().as_bool() { + Some(bool_value) => Some(bool_value), + None => { + return Err(kdl_parsing_error!( + format!( + "{} should be either true or false, found {}", + $name, + e.value() + ), + e + )) + }, + }, + None => { + let child_value = $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)); + match child_value { + Some(e) => match e.value().as_bool() { + Some(bool_value) => Some(bool_value), + None => { + return Err(kdl_parsing_error!( + format!( + "{} should be either true or false, found {}", + $name, + e.value() + ), + e + )) + }, + }, + None => { + if let Some(child_node) = kdl_child_with_name!($kdl_node, $name) { + return Err(kdl_parsing_error!( + format!( + "{} must have a value, eg. '{} true'", + child_node.name().value(), + child_node.name().value() + ), + child_node + )); + } + None + }, + } + }, + } + }; +} + +#[macro_export] +macro_rules! kdl_get_string_property_or_child_value { + ( $kdl_node:expr, $name:expr ) => { + $kdl_node + .get($name) + .and_then(|e| e.value().as_string()) + .or_else(|| { + $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)) + .and_then(|c| c.value().as_string()) + }) + }; +} + +#[macro_export] +macro_rules! kdl_property_or_child_value_node { + ( $kdl_node:expr, $name:expr ) => { + $kdl_node.get($name).or_else(|| { + $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)) + }) + }; +} + +#[macro_export] +macro_rules! kdl_child_with_name { + ( $kdl_node:expr, $name:expr ) => {{ + $kdl_node + .children() + .and_then(|children| children.nodes().iter().find(|c| c.name().value() == $name)) + }}; +} + +#[macro_export] +macro_rules! kdl_get_string_property_or_child_value_with_error { + ( $kdl_node:expr, $name:expr ) => { + match $kdl_node.get($name) { + Some(e) => match e.value().as_string() { + Some(string_value) => Some(string_value), + None => { + return Err(kdl_parsing_error!( + format!( + "{} should be a string, found {} - not a string", + $name, + e.value() + ), + e + )) + }, + }, + None => { + let child_value = $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)); + match child_value { + Some(e) => match e.value().as_string() { + Some(string_value) => Some(string_value), + None => { + return Err(kdl_parsing_error!( + format!( + "{} should be a string, found {} - not a string", + $name, + e.value() + ), + e + )) + }, + }, + None => { + if let Some(child_node) = kdl_child_with_name!($kdl_node, $name) { + return Err(kdl_parsing_error!( + format!( + "{} must have a value, eg. '{} \"foo\"'", + child_node.name().value(), + child_node.name().value() + ), + child_node + )); + } + None + }, + } + }, + } + }; +} + +#[macro_export] +macro_rules! kdl_get_property_or_child { + ( $kdl_node:expr, $name:expr ) => { + $kdl_node + .get($name) + // .and_then(|e| e.value().as_string()) + .or_else(|| { + $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)) + }) + }; +} + +#[macro_export] +macro_rules! kdl_get_int_property_or_child_value { + ( $kdl_node:expr, $name:expr ) => { + $kdl_node + .get($name) + .and_then(|e| e.value().as_i64()) + .or_else(|| { + $kdl_node + .children() + .and_then(|c| c.get($name)) + .and_then(|c| c.get(0)) + .and_then(|c| c.value().as_i64()) + }) + }; +} + +#[macro_export] +macro_rules! kdl_get_string_entry { + ( $kdl_node:expr, $entry_name:expr ) => { + $kdl_node + .get($entry_name) + .and_then(|e| e.value().as_string()) + }; +} + +#[macro_export] +macro_rules! kdl_get_int_entry { + ( $kdl_node:expr, $entry_name:expr ) => { + $kdl_node.get($entry_name).and_then(|e| e.value().as_i64()) + }; +} + +impl Options { + pub fn from_kdl(kdl_options: &KdlDocument) -> Result { + let on_force_close = + match kdl_property_first_arg_as_string_or_error!(kdl_options, "on_force_close") { + Some((string, entry)) => Some(OnForceClose::from_str(string).map_err(|_| { + kdl_parsing_error!( + format!("Invalid value for on_force_close: '{}'", string), + entry + ) + })?), + None => None, + }; + let simplified_ui = + kdl_property_first_arg_as_bool_or_error!(kdl_options, "simplified_ui").map(|(v, _)| v); + let default_shell = + kdl_property_first_arg_as_string_or_error!(kdl_options, "default_shell") + .map(|(string, _entry)| PathBuf::from(string)); + let pane_frames = + kdl_property_first_arg_as_bool_or_error!(kdl_options, "pane_frames").map(|(v, _)| v); + let theme = kdl_property_first_arg_as_string_or_error!(kdl_options, "theme") + .map(|(theme, _entry)| theme.to_string()); + let default_mode = + match kdl_property_first_arg_as_string_or_error!(kdl_options, "default_mode") { + Some((string, entry)) => Some(InputMode::from_str(string).map_err(|_| { + kdl_parsing_error!(format!("Invalid input mode: '{}'", string), entry) + })?), + None => None, + }; + let default_layout = + kdl_property_first_arg_as_string_or_error!(kdl_options, "default_layout") + .map(|(string, _entry)| PathBuf::from(string)); + let layout_dir = kdl_property_first_arg_as_string_or_error!(kdl_options, "layout_dir") + .map(|(string, _entry)| PathBuf::from(string)); + let theme_dir = kdl_property_first_arg_as_string_or_error!(kdl_options, "theme_dir") + .map(|(string, _entry)| PathBuf::from(string)); + let mouse_mode = + kdl_property_first_arg_as_bool_or_error!(kdl_options, "mouse_mode").map(|(v, _)| v); + let scroll_buffer_size = + kdl_property_first_arg_as_i64_or_error!(kdl_options, "scroll_buffer_size") + .map(|(scroll_buffer_size, _entry)| scroll_buffer_size as usize); + let copy_command = kdl_property_first_arg_as_string_or_error!(kdl_options, "copy_command") + .map(|(copy_command, _entry)| copy_command.to_string()); + let copy_clipboard = + match kdl_property_first_arg_as_string_or_error!(kdl_options, "copy_clipboard") { + Some((string, entry)) => Some(Clipboard::from_str(string).map_err(|_| { + kdl_parsing_error!( + format!("Invalid value for copy_clipboard: '{}'", string), + entry + ) + })?), + None => None, + }; + let copy_on_select = + kdl_property_first_arg_as_bool_or_error!(kdl_options, "copy_on_select").map(|(v, _)| v); + let scrollback_editor = + kdl_property_first_arg_as_string_or_error!(kdl_options, "scrollback_editor") + .map(|(string, _entry)| PathBuf::from(string)); + let mirror_session = + kdl_property_first_arg_as_bool_or_error!(kdl_options, "mirror_session").map(|(v, _)| v); + let session_name = kdl_property_first_arg_as_string_or_error!(kdl_options, "session_name") + .map(|(session_name, _entry)| session_name.to_string()); + let attach_to_session = + kdl_property_first_arg_as_bool_or_error!(kdl_options, "attach_to_session") + .map(|(v, _)| v); + Ok(Options { + simplified_ui, + theme, + default_mode, + default_shell, + default_layout, + layout_dir, + theme_dir, + mouse_mode, + pane_frames, + mirror_session, + on_force_close, + scroll_buffer_size, + copy_command, + copy_clipboard, + copy_on_select, + scrollback_editor, + session_name, + attach_to_session, + }) + } +} + +impl RunPlugin { + pub fn from_kdl(kdl_node: &KdlNode) -> Result { + let _allow_exec_host_cmd = + kdl_get_child_entry_bool_value!(kdl_node, "_allow_exec_host_cmd").unwrap_or(false); + let string_url = kdl_get_child_entry_string_value!(kdl_node, "location").ok_or( + ConfigError::new_kdl_error( + "Plugins must have a location".into(), + kdl_node.span().offset(), + kdl_node.span().len(), + ), + )?; + let url = Url::parse(string_url).map_err(|e| { + ConfigError::new_kdl_error( + format!("Failed to parse url: {:?}", e), + kdl_node.span().offset(), + kdl_node.span().len(), + ) + })?; + let location = RunPluginLocation::try_from(url)?; + Ok(RunPlugin { + _allow_exec_host_cmd, + location, + }) + } +} +impl Layout { + pub fn from_kdl(raw_layout: &str, file_name: String) -> Result { + KdlLayoutParser::new(raw_layout).parse().map_err(|e| { + match e { + ConfigError::KdlError(kdl_error) => ConfigError::KdlError(kdl_error.add_src(file_name, String::from(raw_layout))), + ConfigError::KdlDeserializationError(kdl_error) => { + let error_message = match kdl_error.kind { + kdl::KdlErrorKind::Context("valid node terminator") => { + format!("Failed to deserialize KDL node. \nPossible reasons:\n{}\n{}\n{}\n{}", + "- Missing `;` after a node name, eg. { node; another_node; }", + "- Missing quotations (\") around an argument node eg. { first_node \"argument_node\"; }", + "- Missing an equal sign (=) between node arguments on a title line. eg. argument=\"value\"", + "- Found an extraneous equal sign (=) between node child arguments and their values. eg. { argument=\"value\" }") + }, + _ => String::from(kdl_error.help.unwrap_or("Kdl Deserialization Error")), + }; + let kdl_error = KdlError { + error_message, + src: Some(NamedSource::new(file_name, String::from(raw_layout))), + offset: Some(kdl_error.span.offset()), + len: Some(kdl_error.span.len()), + }; + ConfigError::KdlError(kdl_error) + }, + e => e + } + }) + } +} +impl EnvironmentVariables { + pub fn from_kdl(kdl_env_variables: &KdlNode) -> Result { + let mut env: HashMap = HashMap::new(); + for env_var in kdl_children_nodes_or_error!(kdl_env_variables, "empty env variable block") { + let env_var_name = kdl_name!(env_var); + let env_var_str_value = + kdl_first_entry_as_string!(env_var).map(|s| format!("{}", s.to_string())); + let env_var_int_value = + kdl_first_entry_as_i64!(env_var).map(|s| format!("{}", s.to_string())); + let env_var_value = + env_var_str_value + .or(env_var_int_value) + .ok_or(ConfigError::new_kdl_error( + format!("Failed to parse env var: {:?}", env_var_name), + env_var.span().offset(), + env_var.span().len(), + ))?; + env.insert(env_var_name.into(), env_var_value); + } + Ok(EnvironmentVariables::from_data(env)) + } +} + +impl Keybinds { + fn bind_keys_in_block( + block: &KdlNode, + input_mode_keybinds: &mut HashMap>, + ) -> Result<(), ConfigError> { + let all_nodes = kdl_children_nodes_or_error!(block, "no keybinding block for mode"); + let bind_nodes = all_nodes.iter().filter(|n| kdl_name!(n) == "bind"); + let unbind_nodes = all_nodes.iter().filter(|n| kdl_name!(n) == "unbind"); + for key_block in bind_nodes { + Keybinds::bind_actions_for_each_key(key_block, input_mode_keybinds)?; + } + // we loop a second time so that the unbinds always happen after the binds + for key_block in unbind_nodes { + Keybinds::unbind_keys(key_block, input_mode_keybinds)?; + } + for key_block in all_nodes { + if kdl_name!(key_block) != "bind" && kdl_name!(key_block) != "unbind" { + return Err(ConfigError::new_kdl_error( + format!("Unknown keybind instruction: '{}'", kdl_name!(key_block)), + key_block.span().offset(), + key_block.span().len(), + )); + } + } + Ok(()) + } + pub fn from_kdl(kdl_keybinds: &KdlNode, base_keybinds: Keybinds) -> Result { + let clear_defaults = kdl_arg_is_truthy!(kdl_keybinds, "clear-defaults"); + let mut keybinds_from_config = if clear_defaults { + Keybinds::default() + } else { + base_keybinds + }; + for block in kdl_children_nodes_or_error!(kdl_keybinds, "keybindings with no children") { + if kdl_name!(block) == "shared_except" || kdl_name!(block) == "shared" { + let mut modes_to_exclude = vec![]; + for mode_name in kdl_string_arguments!(block) { + modes_to_exclude.push(InputMode::from_str(mode_name).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid mode: '{}'", mode_name), + block.name().span().offset(), + block.name().span().len(), + ) + })?); + } + for mode in InputMode::iter() { + if modes_to_exclude.contains(&mode) { + continue; + } + let mut input_mode_keybinds = keybinds_from_config.get_input_mode_mut(&mode); + Keybinds::bind_keys_in_block(block, &mut input_mode_keybinds)?; + } + } + if kdl_name!(block) == "shared_among" { + let mut modes_to_include = vec![]; + for mode_name in kdl_string_arguments!(block) { + modes_to_include.push(InputMode::from_str(mode_name)?); + } + for mode in InputMode::iter() { + if !modes_to_include.contains(&mode) { + continue; + } + let mut input_mode_keybinds = keybinds_from_config.get_input_mode_mut(&mode); + Keybinds::bind_keys_in_block(block, &mut input_mode_keybinds)?; + } + } + } + for mode in kdl_children_nodes_or_error!(kdl_keybinds, "keybindings with no children") { + if kdl_name!(mode) == "unbind" + || kdl_name!(mode) == "shared_except" + || kdl_name!(mode) == "shared_among" + || kdl_name!(mode) == "shared" + { + continue; + } + let mut input_mode_keybinds = + Keybinds::input_mode_keybindings(mode, &mut keybinds_from_config)?; + Keybinds::bind_keys_in_block(mode, &mut input_mode_keybinds)?; + } + if let Some(global_unbind) = kdl_keybinds.children().and_then(|c| c.get("unbind")) { + Keybinds::unbind_keys_in_all_modes(global_unbind, &mut keybinds_from_config)?; + }; + Ok(keybinds_from_config) + } + fn bind_actions_for_each_key( + key_block: &KdlNode, + input_mode_keybinds: &mut HashMap>, + ) -> Result<(), ConfigError> { + let keys: Vec = keys_from_kdl!(key_block); + let actions: Vec = actions_from_kdl!(key_block); + for key in keys { + input_mode_keybinds.insert(key, actions.clone()); + } + Ok(()) + } + fn unbind_keys( + key_block: &KdlNode, + input_mode_keybinds: &mut HashMap>, + ) -> Result<(), ConfigError> { + let keys: Vec = keys_from_kdl!(key_block); + for key in keys { + input_mode_keybinds.remove(&key); + } + Ok(()) + } + fn unbind_keys_in_all_modes( + global_unbind: &KdlNode, + keybinds_from_config: &mut Keybinds, + ) -> Result<(), ConfigError> { + let keys: Vec = keys_from_kdl!(global_unbind); + for mode in keybinds_from_config.0.values_mut() { + for key in &keys { + mode.remove(&key); + } + } + Ok(()) + } + fn input_mode_keybindings<'a>( + mode: &KdlNode, + keybinds_from_config: &'a mut Keybinds, + ) -> Result<&'a mut HashMap>, ConfigError> { + let mode_name = kdl_name!(mode); + let input_mode = InputMode::from_str(mode_name).map_err(|_| { + ConfigError::new_kdl_error( + format!("Invalid mode: '{}'", mode_name), + mode.name().span().offset(), + mode.name().span().len(), + ) + })?; + let input_mode_keybinds = keybinds_from_config.get_input_mode_mut(&input_mode); + let clear_defaults_for_mode = kdl_arg_is_truthy!(mode, "clear-defaults"); + if clear_defaults_for_mode { + input_mode_keybinds.clear(); + } + Ok(input_mode_keybinds) + } +} + +impl RunCommand { + pub fn from_kdl(kdl_node: &KdlNode) -> Result { + let command = PathBuf::from(kdl_get_child_entry_string_value!(kdl_node, "cmd").ok_or( + ConfigError::new_kdl_error( + "Command must have a cmd value".into(), + kdl_node.span().offset(), + kdl_node.span().len(), + ), + )?); + let cwd = kdl_get_child_entry_string_value!(kdl_node, "cwd").map(|c| PathBuf::from(c)); + let args = match kdl_get_child!(kdl_node, "args") { + Some(kdl_args) => kdl_string_arguments!(kdl_args) + .iter() + .map(|s| String::from(*s)) + .collect(), + None => vec![], + }; + Ok(RunCommand { command, args, cwd }) + } +} + +impl Config { + pub fn from_kdl(kdl_config: &str, base_config: Option) -> Result { + let mut config = base_config.unwrap_or_else(|| Config::default()); + let kdl_config: KdlDocument = kdl_config.parse()?; + // TODO: handle cases where we have more than one of these blocks (eg. two "keybinds") + // this should give an informative parsing error + if let Some(kdl_keybinds) = kdl_config.get("keybinds") { + config.keybinds = Keybinds::from_kdl(&kdl_keybinds, config.keybinds)?; + } + let config_options = Options::from_kdl(&kdl_config)?; + config.options = config.options.merge(config_options); + if let Some(kdl_themes) = kdl_config.get("themes") { + let config_themes = Themes::from_kdl(kdl_themes)?; + config.themes = config.themes.merge(config_themes); + } + if let Some(kdl_plugin_config) = kdl_config.get("plugins") { + let config_plugins = PluginsConfig::from_kdl(kdl_plugin_config)?; + config.plugins = config.plugins.merge(config_plugins); + } + if let Some(kdl_ui_config) = kdl_config.get("ui") { + let config_ui = UiConfig::from_kdl(&kdl_ui_config)?; + config.ui = config.ui.merge(config_ui); + } + if let Some(env_config) = kdl_config.get("env") { + let config_env = EnvironmentVariables::from_kdl(&env_config)?; + config.env = config.env.merge(config_env); + } + Ok(config) + } +} + +impl PluginsConfig { + pub fn from_kdl(kdl_plugin_config: &KdlNode) -> Result { + let mut plugins: HashMap = HashMap::new(); + for plugin_config in + kdl_children_nodes_or_error!(kdl_plugin_config, "no plugin config found") + { + let plugin_name = kdl_name!(plugin_config); + let plugin_tag = PluginTag::new(plugin_name); + let path = kdl_children_property_first_arg_as_string!(plugin_config, "path") + .map(|path| PathBuf::from(path)) + .ok_or(ConfigError::new_kdl_error( + "Plugin path not found or invalid".into(), + plugin_config.span().offset(), + plugin_config.span().len(), + ))?; + let allow_exec_host_cmd = + kdl_children_property_first_arg_as_bool!(plugin_config, "_allow_exec_host_cmd") + .unwrap_or(false); + let plugin_config = PluginConfig { + path, + run: PluginType::Pane(None), + location: RunPluginLocation::Zellij(plugin_tag.clone()), + _allow_exec_host_cmd: allow_exec_host_cmd, + }; + plugins.insert(plugin_tag, plugin_config); + } + Ok(PluginsConfig(plugins)) + } +} +impl UiConfig { + pub fn from_kdl(kdl_ui_config: &KdlNode) -> Result { + let mut ui_config = UiConfig::default(); + if let Some(pane_frames) = kdl_get_child!(kdl_ui_config, "pane_frames") { + let rounded_corners = + kdl_children_property_first_arg_as_bool!(pane_frames, "rounded_corners") + .unwrap_or(false); + let frame_config = FrameConfig { rounded_corners }; + ui_config.pane_frames = frame_config; + } + Ok(ui_config) + } +} + +impl Themes { + pub fn from_kdl(themes_from_kdl: &KdlNode) -> Result { + let mut themes: HashMap = HashMap::new(); + for theme_config in kdl_children_nodes_or_error!(themes_from_kdl, "no themes found") { + let theme_name = kdl_name!(theme_config); + let theme_colors = kdl_children_or_error!(theme_config, "empty theme"); + let theme = Theme { + palette: Palette { + fg: PaletteColor::try_from(("fg", theme_colors))?, + bg: PaletteColor::try_from(("bg", theme_colors))?, + red: PaletteColor::try_from(("red", theme_colors))?, + green: PaletteColor::try_from(("green", theme_colors))?, + yellow: PaletteColor::try_from(("yellow", theme_colors))?, + blue: PaletteColor::try_from(("blue", theme_colors))?, + magenta: PaletteColor::try_from(("magenta", theme_colors))?, + orange: PaletteColor::try_from(("orange", theme_colors))?, + cyan: PaletteColor::try_from(("cyan", theme_colors))?, + black: PaletteColor::try_from(("black", theme_colors))?, + white: PaletteColor::try_from(("white", theme_colors))?, + ..Default::default() + }, + }; + themes.insert(theme_name.into(), theme); + } + let themes = Themes::from_data(themes); + Ok(themes) + } +} + +impl Theme { + pub fn from_path(path_to_theme_file: PathBuf) -> Result<(String, Self), ConfigError> { + // String is the theme name + let mut file = File::open(path_to_theme_file.clone())?; + let mut kdl_config = String::new(); + file.read_to_string(&mut kdl_config)?; + let kdl_config: KdlDocument = kdl_config.parse()?; + let kdl_themes = kdl_config.get("themes").ok_or(ConfigError::new_kdl_error( + "No theme node found in file".into(), + kdl_config.span().offset(), + kdl_config.span().len(), + ))?; + let all_themes_in_file = Themes::from_kdl(kdl_themes)?; + let theme_file_name = path_to_theme_file + .file_name() + .ok_or(ConfigError::new_kdl_error( + "Failed to find file name".into(), + kdl_config.span().offset(), + kdl_config.span().len(), + ))? + .to_string_lossy() + .to_string(); + if let Some(theme_name) = theme_file_name.strip_suffix(".kdl") { + let theme = + all_themes_in_file + .get_theme(theme_name) + .ok_or(ConfigError::new_kdl_error( + format!( + "Not theme with name {} found in file {:?}", + theme_name, path_to_theme_file + ), + kdl_config.span().offset(), + kdl_config.span().len(), + ))?; + Ok((theme_name.to_string(), theme.clone())) + } else { + Err(ConfigError::new_kdl_error( + "no theme file found".into(), + kdl_config.span().offset(), + kdl_config.span().len(), + )) + } + } +} diff --git a/zellij-utils/src/lib.rs b/zellij-utils/src/lib.rs index e871aeee..892dcbc1 100644 --- a/zellij-utils/src/lib.rs +++ b/zellij-utils/src/lib.rs @@ -4,6 +4,7 @@ pub mod data; pub mod envs; pub mod errors; pub mod input; +pub mod kdl; pub mod pane_size; pub mod position; pub mod setup; @@ -19,8 +20,6 @@ pub mod logging; // Requires log4rs #[cfg(not(target_family = "wasm"))] pub use ::{ - async_std, clap, interprocess, lazy_static, libc, nix, regex, serde, serde_yaml, signal_hook, + anyhow, async_std, clap, interprocess, lazy_static, libc, nix, regex, serde, signal_hook, tempfile, termwiz, vte, }; - -pub use anyhow; diff --git a/zellij-utils/src/pane_size.rs b/zellij-utils/src/pane_size.rs index 2a9f54c0..007cf752 100644 --- a/zellij-utils/src/pane_size.rs +++ b/zellij-utils/src/pane_size.rs @@ -83,6 +83,29 @@ impl Dimension { self.inner = inner; } + pub fn adjust_inner(&mut self, full_size: usize) -> f64 { + // returns the leftover from + // rounding if any + // TODO: elsewhere? + match self.constraint { + Constraint::Percent(percent) => { + let new_inner = (percent / 100.0) * full_size as f64; + let rounded = new_inner.floor(); + let leftover = rounded - new_inner; + self.set_inner(rounded as usize); + leftover + // self.set_inner(((percent / 100.0) * full_size as f64).round() as usize); + }, + Constraint::Fixed(fixed_size) => { + self.set_inner(fixed_size); + 0.0 + }, + } + } + pub fn increase_inner(&mut self, by: usize) { + self.inner += by; + } + pub fn is_fixed(&self) -> bool { matches!(self.constraint, Constraint::Fixed(_)) } diff --git a/zellij-utils/src/setup.rs b/zellij-utils/src/setup.rs index 9b478e05..9972915e 100644 --- a/zellij-utils/src/setup.rs +++ b/zellij-utils/src/setup.rs @@ -1,42 +1,122 @@ -use crate::consts::{SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, ZELLIJ_PROJ_DIR}; -use clap::Args; +use crate::input::theme::Theme; +use crate::{ + cli::{CliArgs, Command}, + consts::{ + FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, + ZELLIJ_PROJ_DIR, + }, + input::{ + config::{Config, ConfigError}, + layout::Layout, + options::Options, + }, +}; +use clap::{Args, IntoApp}; +use clap_complete::Shell; use directories_next::BaseDirs; use serde::{Deserialize, Serialize}; use std::{ - io::Write, - path::{Path, PathBuf}, + convert::TryFrom, fmt::Write as FmtWrite, io::Write, path::Path, path::PathBuf, process, }; const CONFIG_LOCATION: &str = ".config/zellij"; +const CONFIG_NAME: &str = "config.kdl"; +static ARROW_SEPARATOR: &str = ""; + +#[cfg(not(test))] +/// Goes through a predefined list and checks for an already +/// existing config directory, returns the first match +pub fn find_default_config_dir() -> Option { + default_config_dirs() + .into_iter() + .filter(|p| p.is_some()) + .find(|p| p.clone().unwrap().exists()) + .flatten() +} + +#[cfg(test)] +pub fn find_default_config_dir() -> Option { + None +} + +/// Order in which config directories are checked +fn default_config_dirs() -> Vec> { + vec![ + home_config_dir(), + Some(xdg_config_dir()), + Some(Path::new(SYSTEM_DEFAULT_CONFIG_DIR).to_path_buf()), + ] +} + +/// Looks for an existing dir, uses that, else returns a +/// dir matching the config spec. +pub fn get_default_data_dir() -> PathBuf { + [ + xdg_data_dir(), + Path::new(SYSTEM_DEFAULT_DATA_DIR_PREFIX).join("share/zellij"), + ] + .into_iter() + .find(|p| p.exists()) + .unwrap_or_else(xdg_data_dir) +} + +pub fn xdg_config_dir() -> PathBuf { + ZELLIJ_PROJ_DIR.config_dir().to_owned() +} + +pub fn xdg_data_dir() -> PathBuf { + ZELLIJ_PROJ_DIR.data_dir().to_owned() +} + +pub fn home_config_dir() -> Option { + if let Some(user_dirs) = BaseDirs::new() { + let config_dir = user_dirs.home_dir().join(CONFIG_LOCATION); + Some(config_dir) + } else { + None + } +} + +pub fn get_layout_dir(config_dir: Option) -> Option { + config_dir.map(|dir| dir.join("layouts")) +} + +pub fn get_theme_dir(config_dir: Option) -> Option { + config_dir.map(|dir| dir.join("themes")) +} +pub fn dump_asset(asset: &[u8]) -> std::io::Result<()> { + std::io::stdout().write_all(asset)?; + Ok(()) +} pub const DEFAULT_CONFIG: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/", - "assets/config/default.yaml" + "assets/config/default.kdl" )); pub const DEFAULT_LAYOUT: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/", - "assets/layouts/default.yaml" + "assets/layouts/default.kdl" )); pub const STRIDER_LAYOUT: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/", - "assets/layouts/strider.yaml" + "assets/layouts/strider.kdl" )); pub const NO_STATUS_LAYOUT: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/", - "assets/layouts/disable-status-bar.yaml" + "assets/layouts/disable-status-bar.kdl" )); pub const COMPACT_BAR_LAYOUT: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/", - "assets/layouts/compact.yaml" + "assets/layouts/compact.kdl" )); pub const FISH_EXTRA_COMPLETION: &[u8] = include_bytes!(concat!( @@ -63,15 +143,6 @@ pub const ZSH_AUTO_START_SCRIPT: &[u8] = include_bytes!(concat!( "assets/shell/auto-start.zsh" )); -pub fn get_theme_dir(config_dir: Option) -> Option { - config_dir.map(|dir| dir.join("themes")) -} - -pub fn dump_asset(asset: &[u8]) -> std::io::Result<()> { - std::io::stdout().write_all(asset)?; - Ok(()) -} - pub fn dump_default_config() -> std::io::Result<()> { dump_asset(DEFAULT_CONFIG) } @@ -118,504 +189,431 @@ pub struct Setup { pub generate_auto_start: Option, } -#[cfg(test)] -pub fn find_default_config_dir() -> Option { - None -} - -#[cfg(not(test))] -/// Goes through a predefined list and checks for an already -/// existing config directory, returns the first match -pub fn find_default_config_dir() -> Option { - default_config_dirs() - .into_iter() - .filter(|p| p.is_some()) - .find(|p| p.clone().unwrap().exists()) - .flatten() -} - -/// Order in which config directories are checked -#[allow(dead_code)] -fn default_config_dirs() -> Vec> { - vec![ - home_config_dir(), - Some(xdg_config_dir()), - Some(Path::new(SYSTEM_DEFAULT_CONFIG_DIR).to_path_buf()), - ] -} - -/// Looks for an existing dir, uses that, else returns a -/// dir matching the config spec. -pub fn get_default_data_dir() -> PathBuf { - [ - xdg_data_dir(), - Path::new(SYSTEM_DEFAULT_DATA_DIR_PREFIX).join("share/zellij"), - ] - .into_iter() - .find(|p| p.exists()) - .unwrap_or_else(xdg_data_dir) -} - -pub fn xdg_config_dir() -> PathBuf { - ZELLIJ_PROJ_DIR.config_dir().to_owned() -} - -pub fn xdg_data_dir() -> PathBuf { - ZELLIJ_PROJ_DIR.data_dir().to_owned() -} - -pub fn home_config_dir() -> Option { - if let Some(user_dirs) = BaseDirs::new() { - let config_dir = user_dirs.home_dir().join(CONFIG_LOCATION); - Some(config_dir) - } else { - None - } -} - -pub fn get_layout_dir(config_dir: Option) -> Option { - config_dir.map(|dir| dir.join("layouts")) -} - -#[cfg(not(target_family = "wasm"))] -pub use not_wasm::*; - -#[cfg(not(target_family = "wasm"))] -mod not_wasm { - use super::*; - use crate::{ - cli::{CliArgs, Command}, - consts::{FEATURES, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION}, - input::{ - config::{Config, ConfigError}, - layout::{LayoutFromYaml, LayoutFromYamlIntermediate}, - options::Options, - theme::ThemesFromYaml, - }, - }; - use clap::IntoApp; - use clap_complete::Shell; - use std::{convert::TryFrom, fmt::Write as FmtWrite, io::Write, path::PathBuf, process}; - - const CONFIG_NAME: &str = "config.yaml"; - static ARROW_SEPARATOR: &str = ""; - - impl Setup { - /// Entrypoint from main - /// Merges options from the config file and the command line options - /// into `[Options]`, the command line options superceeding the layout - /// file options, superceeding the config file options: - /// 1. command line options (`zellij options`) - /// 2. layout options - /// (`layout.yaml` / `zellij --layout`) - /// 3. config options (`config.yaml`) - pub fn from_options( - opts: &CliArgs, - ) -> Result<(Config, Option, Options), ConfigError> { - let clean = match &opts.command { - Some(Command::Setup(ref setup)) => setup.clean, - _ => false, +impl Setup { + /// Entrypoint from main + /// Merges options from the config file and the command line options + /// into `[Options]`, the command line options superceeding the layout + /// file options, superceeding the config file options: + /// 1. command line options (`zellij options`) + /// 2. layout options + /// (`layout.yaml` / `zellij --layout`) + /// 3. config options (`config.yaml`) + pub fn from_cli_args(cli_args: &CliArgs) -> Result<(Config, Layout, Options), ConfigError> { + let clean = cli_args.should_clean_config(); + // note that this can potentially exit the process + Setup::handle_setup_commands(cli_args); + let config = if clean { + Config::default() + } else { + Config::try_from(cli_args)? + }; + let cli_config_options: Option = + if let Some(Command::Options(options)) = cli_args.command.clone() { + Some(options.into()) + } else { + None }; + let (layout, mut config) = + Setup::parse_layout_and_override_config(cli_config_options.as_ref(), config, cli_args)?; + let config_options = match cli_config_options { + Some(cli_config_options) => config.options.merge(cli_config_options), + None => config.options.clone(), + }; - // setup functions that don't require deserialisation of the config - if let Some(Command::Setup(ref setup)) = &opts.command { - setup.from_cli().map_or_else( + if let Some(theme_dir) = config_options + .theme_dir + .clone() + .or_else(|| get_theme_dir(cli_args.config_dir.clone().or_else(find_default_config_dir))) + { + if theme_dir.is_dir() { + for entry in (theme_dir.read_dir()?).flatten() { + if let Some(extension) = entry.path().extension() { + if extension == "kdl" { + match Theme::from_path(entry.path()) { + Ok((theme_name, theme)) => { + config.themes.insert(theme_name, theme); + }, + Err(e) => { + log::error!("error loading theme file: {:?}", e); + }, + } + } + } + } + } + } + + if let Some(Command::Setup(ref setup)) = &cli_args.command { + setup + .from_cli_with_options(cli_args, &config_options) + .map_or_else( |e| { eprintln!("{:?}", e); process::exit(1); }, |_| {}, ); - }; + }; + Ok((config, layout, config_options)) + } - let mut config = if !clean { - match Config::try_from(opts) { - Ok(config) => config, - Err(e) => { - return Err(e); - }, - } - } else { - Config::default() - }; + /// General setup helpers + pub fn from_cli(&self) -> std::io::Result<()> { + if self.clean { + return Ok(()); + } - let config_options = Options::from_cli(&config.options, opts.command.clone()); + if self.dump_config { + dump_default_config()?; + std::process::exit(0); + } - let layout_dir = config_options.layout_dir.clone().or_else(|| { - get_layout_dir(opts.config_dir.clone().or_else(find_default_config_dir)) - }); - let chosen_layout = opts - .layout - .clone() - .or_else(|| config_options.default_layout.clone()); - let layout_result = LayoutFromYamlIntermediate::from_path_or_default( - chosen_layout.as_ref(), - layout_dir, + if let Some(shell) = &self.generate_completion { + Self::generate_completion(shell); + std::process::exit(0); + } + + if let Some(shell) = &self.generate_auto_start { + Self::generate_auto_start(shell); + std::process::exit(0); + } + + if let Some(layout) = &self.dump_layout { + dump_specified_layout(layout)?; + std::process::exit(0); + } + + Ok(()) + } + + /// Checks the merged configuration + pub fn from_cli_with_options( + &self, + opts: &CliArgs, + config_options: &Options, + ) -> std::io::Result<()> { + if self.check { + Setup::check_defaults_config(opts, config_options)?; + std::process::exit(0); + } + Ok(()) + } + + pub fn check_defaults_config(opts: &CliArgs, config_options: &Options) -> std::io::Result<()> { + let data_dir = opts.data_dir.clone().unwrap_or_else(get_default_data_dir); + let config_dir = opts.config_dir.clone().or_else(find_default_config_dir); + let plugin_dir = data_dir.join("plugins"); + let layout_dir = config_options + .layout_dir + .clone() + .or_else(|| get_layout_dir(config_dir.clone())); + let system_data_dir = PathBuf::from(SYSTEM_DEFAULT_DATA_DIR_PREFIX).join("share/zellij"); + let config_file = opts + .config + .clone() + .or_else(|| config_dir.clone().map(|p| p.join(CONFIG_NAME))); + + // according to + // https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda + let hyperlink_start = "\u{1b}]8;;"; + let hyperlink_mid = "\u{1b}\\"; + let hyperlink_end = "\u{1b}]8;;\u{1b}\\"; + + let mut message = String::new(); + + writeln!(&mut message, "[Version]: {:?}", VERSION).unwrap(); + if let Some(config_dir) = config_dir { + writeln!(&mut message, "[CONFIG DIR]: {:?}", config_dir).unwrap(); + } else { + message.push_str("[CONFIG DIR]: Not Found\n"); + let mut default_config_dirs = default_config_dirs() + .iter() + .filter_map(|p| p.clone()) + .collect::>(); + default_config_dirs.dedup(); + message.push_str( + " On your system zellij looks in the following config directories by default:\n", ); - let layout = match layout_result { - None => None, - Some(Ok(layout)) => Some(layout), - Some(Err(e)) => { - return Err(e); - }, - }; - - if let Some(theme_dir) = config_options - .theme_dir - .clone() - .or_else(|| get_theme_dir(opts.config_dir.clone().or_else(find_default_config_dir))) - { - if theme_dir.is_dir() { - for entry in (theme_dir.read_dir()?).flatten() { - if let Some(extension) = entry.path().extension() { - if extension == "yaml" || extension == "yml" { - if let Ok(themes) = ThemesFromYaml::from_path(&entry.path()) { - match config.themes { - Some(t) => config.themes = Some(t.merge(themes.into())), - None => config.themes = Some(themes.into()), - } - } - } - } - } - } + for dir in default_config_dirs { + writeln!(&mut message, " {:?}", dir).unwrap(); } - - if let Some(Command::Setup(ref setup)) = &opts.command { - setup - .from_cli_with_options(opts, &config_options) - .map_or_else( - |e| { - eprintln!("{:?}", e); - process::exit(1); - }, - |_| {}, - ); - }; - - Setup::merge_config_with_layout(config, layout, config_options) } - - /// General setup helpers - pub fn from_cli(&self) -> std::io::Result<()> { - if self.clean { - return Ok(()); + if let Some(config_file) = config_file { + writeln!(&mut message, "[CONFIG FILE]: {:?}", config_file).unwrap(); + // match Config::new(&config_file) { + match Config::from_path(&config_file, None) { + Ok(_) => message.push_str("[CONFIG FILE]: Well defined.\n"), + Err(e) => writeln!(&mut message, "[CONFIG ERROR]: {}", e).unwrap(), } - - if self.dump_config { - dump_default_config()?; - std::process::exit(0); - } - - if let Some(shell) = &self.generate_completion { - Self::generate_completion(shell); - std::process::exit(0); - } - - if let Some(shell) = &self.generate_auto_start { - Self::generate_auto_start(shell); - std::process::exit(0); - } - - if let Some(layout) = &self.dump_layout { - dump_specified_layout(layout)?; - std::process::exit(0); - } - - Ok(()) - } - - /// Checks the merged configuration - pub fn from_cli_with_options( - &self, - opts: &CliArgs, - config_options: &Options, - ) -> std::io::Result<()> { - if self.check { - Setup::check_defaults_config(opts, config_options)?; - std::process::exit(0); - } - Ok(()) - } - - fn merge_config_with_layout( - config: Config, - layout: Option, - config_options: Options, - ) -> Result<(Config, Option, Options), ConfigError> { - let (layout, layout_config) = match layout.map(|l| l.to_layout_and_config()) { - None => (None, None), - Some((layout, layout_config)) => (Some(layout), layout_config), - }; - - let (config, config_options) = if let Some(layout_config) = layout_config { - let config_options = if let Some(options) = layout_config.options.clone() { - config_options.merge(options) - } else { - config_options - }; - let config = config.merge(layout_config.try_into()?); - (config, config_options) - } else { - (config, config_options) - }; - Ok((config, layout, config_options)) - } - - pub fn check_defaults_config( - opts: &CliArgs, - config_options: &Options, - ) -> std::io::Result<()> { - let data_dir = opts.data_dir.clone().unwrap_or_else(get_default_data_dir); - let config_dir = opts.config_dir.clone().or_else(find_default_config_dir); - let plugin_dir = data_dir.join("plugins"); - let layout_dir = config_options - .layout_dir - .clone() - .or_else(|| get_layout_dir(config_dir.clone())); - let theme_dir = config_options - .theme_dir - .clone() - .or_else(|| get_theme_dir(config_dir.clone())); - let system_data_dir = - PathBuf::from(SYSTEM_DEFAULT_DATA_DIR_PREFIX).join("share/zellij"); - let config_file = opts - .config - .clone() - .or_else(|| config_dir.clone().map(|p| p.join(CONFIG_NAME))); - - // according to - // https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda - let hyperlink_start = "\u{1b}]8;;"; - let hyperlink_mid = "\u{1b}\\"; - let hyperlink_end = "\u{1b}]8;;\u{1b}\\"; - - let mut message = String::new(); - - writeln!(&mut message, "[Version]: {:?}", VERSION).unwrap(); - if let Some(config_dir) = config_dir { - writeln!(&mut message, "[CONFIG DIR]: {:?}", config_dir).unwrap(); - } else { - message.push_str("[CONFIG DIR]: Not Found\n"); - let mut default_config_dirs = default_config_dirs() - .iter() - .filter_map(|p| p.clone()) - .collect::>(); - default_config_dirs.dedup(); - message.push_str( - " On your system zellij looks in the following config directories by default:\n", - ); - for dir in default_config_dirs { - writeln!(&mut message, " {:?}", dir).unwrap(); - } - } - if let Some(config_file) = config_file { - writeln!(&mut message, "[CONFIG FILE]: {:?}", config_file).unwrap(); - match Config::new(&config_file) { - Ok(_) => message.push_str("[CONFIG FILE]: Well defined.\n"), - Err(e) => writeln!(&mut message, "[CONFIG ERROR]: {}", e).unwrap(), - } - } else { - message.push_str("[CONFIG FILE]: Not Found\n"); - writeln!( - &mut message, - " By default zellij looks for a file called [{}] in the configuration directory", - CONFIG_NAME - ) - .unwrap(); - } - writeln!(&mut message, "[DATA DIR]: {:?}", data_dir).unwrap(); - message.push_str(&format!("[PLUGIN DIR]: {:?}\n", plugin_dir)); - if let Some(layout_dir) = layout_dir { - writeln!(&mut message, "[LAYOUT DIR]: {:?}", layout_dir).unwrap(); - } else { - message.push_str("[LAYOUT DIR]: Not Found\n"); - } - if let Some(theme_dir) = theme_dir { - writeln!(&mut message, "[THEME DIR]: {:?}", theme_dir).unwrap(); - } else { - message.push_str("[THEME DIR]: Not Found\n"); - } - writeln!(&mut message, "[SYSTEM DATA DIR]: {:?}", system_data_dir).unwrap(); - - writeln!(&mut message, "[ARROW SEPARATOR]: {}", ARROW_SEPARATOR).unwrap(); - message.push_str(" Is the [ARROW_SEPARATOR] displayed correctly?\n"); - message.push_str(" If not you may want to either start zellij with a compatible mode: 'zellij options --simplified-ui true'\n"); - let mut hyperlink_compat = String::new(); - hyperlink_compat.push_str(hyperlink_start); - hyperlink_compat.push_str("https://zellij.dev/documentation/compatibility.html#the-status-bar-fonts-dont-render-correctly"); - hyperlink_compat.push_str(hyperlink_mid); - hyperlink_compat.push_str("https://zellij.dev/documentation/compatibility.html#the-status-bar-fonts-dont-render-correctly"); - hyperlink_compat.push_str(hyperlink_end); - write!( + } else { + message.push_str("[CONFIG FILE]: Not Found\n"); + writeln!( &mut message, - " Or check the font that is in use:\n {}\n", - hyperlink_compat + " By default zellij looks for a file called [{}] in the configuration directory", + CONFIG_NAME ) .unwrap(); - message.push_str("[MOUSE INTERACTION]: \n"); - message.push_str(" Can be temporarily disabled through pressing the [SHIFT] key.\n"); - message.push_str(" If that doesn't fix any issues consider to disable the mouse handling of zellij: 'zellij options --disable-mouse-mode'\n"); - - let default_editor = std::env::var("EDITOR") - .or_else(|_| std::env::var("VISUAL")) - .unwrap_or_else(|_| String::from("Not set, checked $EDITOR and $VISUAL")); - writeln!(&mut message, "[DEFAULT EDITOR]: {}", default_editor).unwrap(); - writeln!(&mut message, "[FEATURES]: {:?}", FEATURES).unwrap(); - let mut hyperlink = String::new(); - hyperlink.push_str(hyperlink_start); - hyperlink.push_str("https://www.zellij.dev/documentation/"); - hyperlink.push_str(hyperlink_mid); - hyperlink.push_str("zellij.dev/documentation"); - hyperlink.push_str(hyperlink_end); - writeln!(&mut message, "[DOCUMENTATION]: {}", hyperlink).unwrap(); - //printf '\e]8;;http://example.com\e\\This is a link\e]8;;\e\\\n' - - std::io::stdout().write_all(message.as_bytes())?; - - Ok(()) } - fn generate_completion(shell: &str) { - let shell: Shell = match shell.to_lowercase().parse() { - Ok(shell) => shell, - _ => { - eprintln!("Unsupported shell: {}", shell); - std::process::exit(1); - }, - }; - let mut out = std::io::stdout(); - clap_complete::generate(shell, &mut CliArgs::command(), "zellij", &mut out); - // add shell dependent extra completion - match shell { - Shell::Bash => {}, - Shell::Elvish => {}, - Shell::Fish => { - let _ = out.write_all(FISH_EXTRA_COMPLETION); - }, - Shell::PowerShell => {}, - Shell::Zsh => {}, - _ => {}, - }; + writeln!(&mut message, "[DATA DIR]: {:?}", data_dir).unwrap(); + message.push_str(&format!("[PLUGIN DIR]: {:?}\n", plugin_dir)); + if let Some(layout_dir) = layout_dir { + writeln!(&mut message, "[LAYOUT DIR]: {:?}", layout_dir).unwrap(); + } else { + message.push_str("[LAYOUT DIR]: Not Found\n"); } + writeln!(&mut message, "[SYSTEM DATA DIR]: {:?}", system_data_dir).unwrap(); - fn generate_auto_start(shell: &str) { - let shell: Shell = match shell.to_lowercase().parse() { - Ok(shell) => shell, - _ => { - eprintln!("Unsupported shell: {}", shell); - std::process::exit(1); - }, - }; + writeln!(&mut message, "[ARROW SEPARATOR]: {}", ARROW_SEPARATOR).unwrap(); + message.push_str(" Is the [ARROW_SEPARATOR] displayed correctly?\n"); + message.push_str(" If not you may want to either start zellij with a compatible mode: 'zellij options --simplified-ui true'\n"); + let mut hyperlink_compat = String::new(); + hyperlink_compat.push_str(hyperlink_start); + hyperlink_compat.push_str("https://zellij.dev/documentation/compatibility.html#the-status-bar-fonts-dont-render-correctly"); + hyperlink_compat.push_str(hyperlink_mid); + hyperlink_compat.push_str("https://zellij.dev/documentation/compatibility.html#the-status-bar-fonts-dont-render-correctly"); + hyperlink_compat.push_str(hyperlink_end); + write!( + &mut message, + " Or check the font that is in use:\n {}\n", + hyperlink_compat + ) + .unwrap(); + message.push_str("[MOUSE INTERACTION]: \n"); + message.push_str(" Can be temporarily disabled through pressing the [SHIFT] key.\n"); + message.push_str(" If that doesn't fix any issues consider to disable the mouse handling of zellij: 'zellij options --disable-mouse-mode'\n"); - let mut out = std::io::stdout(); - match shell { - Shell::Bash => { - let _ = out.write_all(BASH_AUTO_START_SCRIPT); - }, - Shell::Fish => { - let _ = out.write_all(FISH_AUTO_START_SCRIPT); - }, - Shell::Zsh => { - let _ = out.write_all(ZSH_AUTO_START_SCRIPT); - }, - _ => {}, - } - } + let default_editor = std::env::var("EDITOR") + .or_else(|_| std::env::var("VISUAL")) + .unwrap_or_else(|_| String::from("Not set, checked $EDITOR and $VISUAL")); + writeln!(&mut message, "[DEFAULT EDITOR]: {}", default_editor).unwrap(); + writeln!(&mut message, "[FEATURES]: {:?}", FEATURES).unwrap(); + let mut hyperlink = String::new(); + hyperlink.push_str(hyperlink_start); + hyperlink.push_str("https://www.zellij.dev/documentation/"); + hyperlink.push_str(hyperlink_mid); + hyperlink.push_str("zellij.dev/documentation"); + hyperlink.push_str(hyperlink_end); + writeln!(&mut message, "[DOCUMENTATION]: {}", hyperlink).unwrap(); + //printf '\e]8;;http://example.com\e\\This is a link\e]8;;\e\\\n' + + std::io::stdout().write_all(message.as_bytes())?; + + Ok(()) + } + fn generate_completion(shell: &str) { + let shell: Shell = match shell.to_lowercase().parse() { + Ok(shell) => shell, + _ => { + eprintln!("Unsupported shell: {}", shell); + std::process::exit(1); + }, + }; + let mut out = std::io::stdout(); + clap_complete::generate(shell, &mut CliArgs::command(), "zellij", &mut out); + // add shell dependent extra completion + match shell { + Shell::Bash => {}, + Shell::Elvish => {}, + Shell::Fish => { + let _ = out.write_all(FISH_EXTRA_COMPLETION); + }, + Shell::PowerShell => {}, + Shell::Zsh => {}, + _ => {}, + }; } - #[cfg(test)] - mod setup_test { - use super::Setup; - use crate::data::InputMode; - use crate::input::{ - config::{Config, ConfigError}, - layout::LayoutFromYamlIntermediate, - options::Options, + fn generate_auto_start(shell: &str) { + let shell: Shell = match shell.to_lowercase().parse() { + Ok(shell) => shell, + _ => { + eprintln!("Unsupported shell: {}", shell); + std::process::exit(1); + }, }; - fn deserialise_config_and_layout( - config: &str, - layout: &str, - ) -> Result<(Config, LayoutFromYamlIntermediate), ConfigError> { - let config = Config::from_yaml(config)?; - let layout = LayoutFromYamlIntermediate::from_yaml(layout)?; - Ok((config, layout)) - } - - #[test] - fn empty_config_empty_layout() { - let goal = Config::default(); - let config = r""; - let layout = r""; - let config_layout_result = deserialise_config_and_layout(config, layout); - let (config, layout) = config_layout_result.unwrap(); - let config_options = Options::default(); - let (config, _layout, _config_options) = - Setup::merge_config_with_layout(config, Some(layout), config_options).unwrap(); - assert_eq!(config, goal); - } - - #[test] - fn config_empty_layout() { - let mut goal = Config::default(); - goal.options.default_shell = Some(std::path::PathBuf::from("fish")); - let config = r"--- - default_shell: fish"; - let layout = r""; - let config_layout_result = deserialise_config_and_layout(config, layout); - let (config, layout) = config_layout_result.unwrap(); - let config_options = Options::default(); - let (config, _layout, _config_options) = - Setup::merge_config_with_layout(config, Some(layout), config_options).unwrap(); - assert_eq!(config, goal); - } - - #[test] - fn layout_overwrites_config() { - let mut goal = Config::default(); - goal.options.default_shell = Some(std::path::PathBuf::from("bash")); - let config = r"--- - default_shell: fish"; - let layout = r"--- - default_shell: bash"; - let config_layout_result = deserialise_config_and_layout(config, layout); - let (config, layout) = config_layout_result.unwrap(); - let config_options = Options::default(); - let (config, _layout, _config_options) = - Setup::merge_config_with_layout(config, Some(layout), config_options).unwrap(); - assert_eq!(config, goal); - } - - #[test] - fn empty_config_nonempty_layout() { - let mut goal = Config::default(); - goal.options.default_shell = Some(std::path::PathBuf::from("bash")); - let config = r""; - let layout = r"--- - default_shell: bash"; - let config_layout_result = deserialise_config_and_layout(config, layout); - let (config, layout) = config_layout_result.unwrap(); - let config_options = Options::default(); - let (config, _layout, _config_options) = - Setup::merge_config_with_layout(config, Some(layout), config_options).unwrap(); - assert_eq!(config, goal); - } - - #[test] - fn nonempty_config_nonempty_layout() { - let mut goal = Config::default(); - goal.options.default_shell = Some(std::path::PathBuf::from("bash")); - goal.options.default_mode = Some(InputMode::Locked); - let config = r"--- - default_mode: locked"; - let layout = r"--- - default_shell: bash"; - let config_layout_result = deserialise_config_and_layout(config, layout); - let (config, layout) = config_layout_result.unwrap(); - let config_options = Options::default(); - let (config, _layout, _config_options) = - Setup::merge_config_with_layout(config, Some(layout), config_options).unwrap(); - assert_eq!(config, goal); + let mut out = std::io::stdout(); + match shell { + Shell::Bash => { + let _ = out.write_all(BASH_AUTO_START_SCRIPT); + }, + Shell::Fish => { + let _ = out.write_all(FISH_AUTO_START_SCRIPT); + }, + Shell::Zsh => { + let _ = out.write_all(ZSH_AUTO_START_SCRIPT); + }, + _ => {}, } } + fn parse_layout_and_override_config( + cli_config_options: Option<&Options>, + config: Config, + cli_args: &CliArgs, + ) -> Result<(Layout, Config), ConfigError> { + // find the layout folder relative to which we'll look for our layout + let layout_dir = cli_config_options + .as_ref() + .and_then(|cli_options| cli_options.layout_dir.clone()) + .or_else(|| config.options.layout_dir.clone()) + .or_else(|| { + get_layout_dir(cli_args.config_dir.clone().or_else(find_default_config_dir)) + }); + // the chosen layout can either be a path relative to the layout_dir or a name of one + // of our assets, this distinction is made when parsing the layout - TODO: ideally, this + // logic should not be split up and all the decisions should happen here + let chosen_layout = cli_args + .layout + .clone() + .or_else(|| { + cli_config_options + .as_ref() + .and_then(|cli_options| cli_options.default_layout.clone()) + }) + .or_else(|| config.options.default_layout.clone()); + // we merge-override the config here because the layout might contain configuration + // that needs to take precedence + Layout::from_path_or_default(chosen_layout.as_ref(), layout_dir.clone(), config) + } + fn handle_setup_commands(cli_args: &CliArgs) { + if let Some(Command::Setup(ref setup)) = &cli_args.command { + setup.from_cli().map_or_else( + |e| { + eprintln!("{:?}", e); + process::exit(1); + }, + |_| {}, + ); + }; + } +} + +#[cfg(test)] +mod setup_test { + use super::Setup; + use crate::cli::{CliArgs, Command}; + use crate::input::options::{CliOptions, Options}; + use insta::assert_snapshot; + use std::path::PathBuf; + + #[test] + fn default_config_with_no_cli_arguments() { + let cli_args = CliArgs::default(); + let (config, layout, options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", config)); + assert_snapshot!(format!("{:#?}", layout)); + assert_snapshot!(format!("{:#?}", options)); + } + #[test] + fn cli_arguments_override_config_options() { + let mut cli_args = CliArgs::default(); + cli_args.command = Some(Command::Options(CliOptions { + options: Options { + simplified_ui: Some(true), + ..Default::default() + }, + ..Default::default() + })); + let (_config, _layout, options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", options)); + } + #[test] + fn layout_options_override_config_options() { + let mut cli_args = CliArgs::default(); + cli_args.layout = Some(PathBuf::from(format!( + "{}/src/test-fixtures/layout-with-options.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + let (_config, layout, options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", options)); + assert_snapshot!(format!("{:#?}", layout)); + } + #[test] + fn cli_arguments_override_layout_options() { + let mut cli_args = CliArgs::default(); + cli_args.layout = Some(PathBuf::from(format!( + "{}/src/test-fixtures/layout-with-options.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + cli_args.command = Some(Command::Options(CliOptions { + options: Options { + pane_frames: Some(true), + ..Default::default() + }, + ..Default::default() + })); + let (_config, layout, options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", options)); + assert_snapshot!(format!("{:#?}", layout)); + } + #[test] + fn layout_env_vars_override_config_env_vars() { + let mut cli_args = CliArgs::default(); + cli_args.config = Some(PathBuf::from(format!( + "{}/src/test-fixtures/config-with-env-vars.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + cli_args.layout = Some(PathBuf::from(format!( + "{}/src/test-fixtures/layout-with-env-vars.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + let (config, _layout, _options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", config)); + } + #[test] + fn layout_ui_config_overrides_config_ui_config() { + let mut cli_args = CliArgs::default(); + cli_args.config = Some(PathBuf::from(format!( + "{}/src/test-fixtures/config-with-ui-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + cli_args.layout = Some(PathBuf::from(format!( + "{}/src/test-fixtures/layout-with-ui-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + let (config, _layout, _options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", config)); + } + #[test] + fn layout_plugins_override_config_plugins() { + let mut cli_args = CliArgs::default(); + cli_args.config = Some(PathBuf::from(format!( + "{}/src/test-fixtures/config-with-plugins-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + cli_args.layout = Some(PathBuf::from(format!( + "{}/src/test-fixtures/layout-with-plugins-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + let (config, _layout, _options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", config)); + } + #[test] + fn layout_themes_override_config_themes() { + let mut cli_args = CliArgs::default(); + cli_args.config = Some(PathBuf::from(format!( + "{}/src/test-fixtures/config-with-themes-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + cli_args.layout = Some(PathBuf::from(format!( + "{}/src/test-fixtures/layout-with-themes-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + let (config, _layout, _options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", config)); + } + #[test] + fn layout_keybinds_override_config_keybinds() { + let mut cli_args = CliArgs::default(); + cli_args.config = Some(PathBuf::from(format!( + "{}/src/test-fixtures/config-with-keybindings-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + cli_args.layout = Some(PathBuf::from(format!( + "{}/src/test-fixtures/layout-with-keybindings-config.kdl", + env!("CARGO_MANIFEST_DIR") + ))); + let (config, _layout, _options) = Setup::from_cli_args(&cli_args).unwrap(); + assert_snapshot!(format!("{:#?}", config)); + } } diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap new file mode 100644 index 00000000..00801403 --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap @@ -0,0 +1,27 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 561 +expression: "format!(\"{:#?}\", options)" +--- +Options { + simplified_ui: Some( + true, + ), + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap new file mode 100644 index 00000000..263f3c60 --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap @@ -0,0 +1,21 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 509 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap new file mode 100644 index 00000000..a36a7543 --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap @@ -0,0 +1,27 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 584 +expression: "format!(\"{:#?}\", options)" +--- +Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: Some( + true, + ), + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap new file mode 100644 index 00000000..d4ea72ea --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap @@ -0,0 +1,82 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 492 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: Some( + Fixed( + 1, + ), + ), + run: Some( + Plugin( + RunPlugin { + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "tab-bar", + ), + ), + }, + ), + ), + borderless: true, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: Some( + Fixed( + 2, + ), + ), + run: Some( + Plugin( + RunPlugin { + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "status-bar", + ), + ), + }, + ), + ), + borderless: true, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap new file mode 100644 index 00000000..e23c0d24 --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap @@ -0,0 +1,25 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 546 +expression: "format!(\"{:#?}\", options)" +--- +Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap new file mode 100644 index 00000000..35cd5f7e --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap @@ -0,0 +1,3363 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 491 +expression: "format!(\"{:#?}\", config)" +--- +Config { + keybinds: { + Normal: { + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + }, + Locked: { + Ctrl( + 'g', + ): [ + SwitchToMode( + Normal, + ), + ], + }, + Resize: { + Left: [ + Resize( + Left, + ), + ], + Down: [ + Resize( + Down, + ), + ], + Up: [ + Resize( + Up, + ), + ], + Right: [ + Resize( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '+', + ): [ + Resize( + Increase, + ), + ], + Char( + '-', + ): [ + Resize( + Decrease, + ), + ], + Char( + '=', + ): [ + Resize( + Increase, + ), + ], + Char( + 'h', + ): [ + Resize( + Left, + ), + ], + Char( + 'j', + ): [ + Resize( + Down, + ), + ], + Char( + 'k', + ): [ + Resize( + Up, + ), + ], + Char( + 'l', + ): [ + Resize( + Right, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Pane: { + Left: [ + MoveFocus( + Left, + ), + ], + Down: [ + MoveFocus( + Down, + ), + ], + Up: [ + MoveFocus( + Up, + ), + ], + Right: [ + MoveFocus( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SwitchToMode( + RenamePane, + ), + PaneNameInput( + [ + 0, + ], + ), + ], + Char( + 'd', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'e', + ): [ + TogglePaneEmbedOrFloating, + SwitchToMode( + Normal, + ), + ], + Char( + 'f', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + ], + Char( + 'n', + ): [ + NewPane( + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'p', + ): [ + SwitchFocus, + ], + Char( + 'r', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'w', + ): [ + ToggleFloatingPanes, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseFocus, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + TogglePaneFrames, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tab: { + Left: [ + GoToPreviousTab, + ], + Down: [ + GoToNextTab, + ], + Up: [ + GoToPreviousTab, + ], + Right: [ + GoToNextTab, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '1', + ): [ + GoToTab( + 1, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '2', + ): [ + GoToTab( + 2, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '3', + ): [ + GoToTab( + 3, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '4', + ): [ + GoToTab( + 4, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '5', + ): [ + GoToTab( + 5, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '6', + ): [ + GoToTab( + 6, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '7', + ): [ + GoToTab( + 7, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '8', + ): [ + GoToTab( + 8, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '9', + ): [ + GoToTab( + 9, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + GoToPreviousTab, + ], + Char( + 'j', + ): [ + GoToNextTab, + ], + Char( + 'k', + ): [ + GoToPreviousTab, + ], + Char( + 'l', + ): [ + GoToNextTab, + ], + Char( + 'n', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'r', + ): [ + SwitchToMode( + RenameTab, + ), + TabNameInput( + [ + 0, + ], + ), + ], + Char( + 's', + ): [ + ToggleActiveSyncTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseTab, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Normal, + ), + ], + BackTab: [ + ToggleTab, + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Scroll: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'e', + ): [ + EditScrollback, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 's', + ): [ + SwitchToMode( + EnterSearch, + ), + SearchInput( + [ + 0, + ], + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + EnterSearch: { + Char( + '\n', + ): [ + SwitchToMode( + Search, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Scroll, + ), + ], + }, + Search: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SearchToggleOption( + CaseSensitivity, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 'n', + ): [ + Search( + Down, + ), + ], + Char( + 'o', + ): [ + SearchToggleOption( + WholeWord, + ), + ], + Char( + 'p', + ): [ + Search( + Up, + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Char( + 'w', + ): [ + SearchToggleOption( + Wrap, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + RenameTab: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenameTab, + SwitchToMode( + Tab, + ), + ], + }, + RenamePane: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenamePane, + SwitchToMode( + Pane, + ), + ], + }, + Session: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Move: { + Left: [ + MovePane( + Some( + Left, + ), + ), + ], + Down: [ + MovePane( + Some( + Down, + ), + ), + ], + Up: [ + MovePane( + Some( + Up, + ), + ), + ], + Right: [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MovePane( + Some( + Left, + ), + ), + ], + Char( + 'j', + ): [ + MovePane( + Some( + Down, + ), + ), + ], + Char( + 'k', + ): [ + MovePane( + Some( + Up, + ), + ), + ], + Char( + 'l', + ): [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + 'n', + ): [ + MovePane( + None, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + BackTab: [ + MovePane( + None, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Prompt: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tmux: { + Left: [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Down: [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Up: [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Right: [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '"', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + '%', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + ',', + ): [ + SwitchToMode( + RenameTab, + ), + ], + Char( + '[', + ): [ + SwitchToMode( + Scroll, + ), + ], + Char( + 'c', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'n', + ): [ + GoToNextTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'o', + ): [ + FocusNextPane, + ], + Char( + 'p', + ): [ + GoToPreviousTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + Write( + [ + 2, + ], + ), + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + }, + options: Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, + }, + themes: {}, + plugins: { + PluginTag( + "compact-bar", + ): PluginConfig { + path: "compact-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "compact-bar", + ), + ), + }, + PluginTag( + "status-bar", + ): PluginConfig { + path: "status-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "status-bar", + ), + ), + }, + PluginTag( + "strider", + ): PluginConfig { + path: "strider", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "strider", + ), + ), + }, + PluginTag( + "tab-bar", + ): PluginConfig { + path: "tab-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "tab-bar", + ), + ), + }, + }, + ui: UiConfig { + pane_frames: FrameConfig { + rounded_corners: false, + }, + }, + env: {}, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap new file mode 100644 index 00000000..07c91c5a --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap @@ -0,0 +1,3367 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 541 +expression: "format!(\"{:#?}\", config)" +--- +Config { + keybinds: { + Normal: { + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + }, + Locked: { + Ctrl( + 'g', + ): [ + SwitchToMode( + Normal, + ), + ], + }, + Resize: { + Left: [ + Resize( + Left, + ), + ], + Down: [ + Resize( + Down, + ), + ], + Up: [ + Resize( + Up, + ), + ], + Right: [ + Resize( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '+', + ): [ + Resize( + Increase, + ), + ], + Char( + '-', + ): [ + Resize( + Decrease, + ), + ], + Char( + '=', + ): [ + Resize( + Increase, + ), + ], + Char( + 'h', + ): [ + Resize( + Left, + ), + ], + Char( + 'j', + ): [ + Resize( + Down, + ), + ], + Char( + 'k', + ): [ + Resize( + Up, + ), + ], + Char( + 'l', + ): [ + Resize( + Right, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Pane: { + Left: [ + MoveFocus( + Left, + ), + ], + Down: [ + MoveFocus( + Down, + ), + ], + Up: [ + MoveFocus( + Up, + ), + ], + Right: [ + MoveFocus( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SwitchToMode( + RenamePane, + ), + PaneNameInput( + [ + 0, + ], + ), + ], + Char( + 'd', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'e', + ): [ + TogglePaneEmbedOrFloating, + SwitchToMode( + Normal, + ), + ], + Char( + 'f', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + ], + Char( + 'n', + ): [ + NewPane( + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'p', + ): [ + SwitchFocus, + ], + Char( + 'r', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'w', + ): [ + ToggleFloatingPanes, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseFocus, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + TogglePaneFrames, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tab: { + Left: [ + GoToPreviousTab, + ], + Down: [ + GoToNextTab, + ], + Up: [ + GoToPreviousTab, + ], + Right: [ + GoToNextTab, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '1', + ): [ + GoToTab( + 1, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '2', + ): [ + GoToTab( + 2, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '3', + ): [ + GoToTab( + 3, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '4', + ): [ + GoToTab( + 4, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '5', + ): [ + GoToTab( + 5, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '6', + ): [ + GoToTab( + 6, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '7', + ): [ + GoToTab( + 7, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '8', + ): [ + GoToTab( + 8, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '9', + ): [ + GoToTab( + 9, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + GoToPreviousTab, + ], + Char( + 'j', + ): [ + GoToNextTab, + ], + Char( + 'k', + ): [ + GoToPreviousTab, + ], + Char( + 'l', + ): [ + GoToNextTab, + ], + Char( + 'n', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'r', + ): [ + SwitchToMode( + RenameTab, + ), + TabNameInput( + [ + 0, + ], + ), + ], + Char( + 's', + ): [ + ToggleActiveSyncTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseTab, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Normal, + ), + ], + BackTab: [ + ToggleTab, + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Scroll: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'e', + ): [ + EditScrollback, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 's', + ): [ + SwitchToMode( + EnterSearch, + ), + SearchInput( + [ + 0, + ], + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + EnterSearch: { + Char( + '\n', + ): [ + SwitchToMode( + Search, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Scroll, + ), + ], + }, + Search: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SearchToggleOption( + CaseSensitivity, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 'n', + ): [ + Search( + Down, + ), + ], + Char( + 'o', + ): [ + SearchToggleOption( + WholeWord, + ), + ], + Char( + 'p', + ): [ + Search( + Up, + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Char( + 'w', + ): [ + SearchToggleOption( + Wrap, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + RenameTab: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenameTab, + SwitchToMode( + Tab, + ), + ], + }, + RenamePane: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenamePane, + SwitchToMode( + Pane, + ), + ], + }, + Session: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Move: { + Left: [ + MovePane( + Some( + Left, + ), + ), + ], + Down: [ + MovePane( + Some( + Down, + ), + ), + ], + Up: [ + MovePane( + Some( + Up, + ), + ), + ], + Right: [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MovePane( + Some( + Left, + ), + ), + ], + Char( + 'j', + ): [ + MovePane( + Some( + Down, + ), + ), + ], + Char( + 'k', + ): [ + MovePane( + Some( + Up, + ), + ), + ], + Char( + 'l', + ): [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + 'n', + ): [ + MovePane( + None, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + BackTab: [ + MovePane( + None, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Prompt: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tmux: { + Left: [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Down: [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Up: [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Right: [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '"', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + '%', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + ',', + ): [ + SwitchToMode( + RenameTab, + ), + ], + Char( + '[', + ): [ + SwitchToMode( + Scroll, + ), + ], + Char( + 'c', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'n', + ): [ + GoToNextTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'o', + ): [ + FocusNextPane, + ], + Char( + 'p', + ): [ + GoToPreviousTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + Write( + [ + 2, + ], + ), + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + }, + options: Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, + }, + themes: {}, + plugins: { + PluginTag( + "compact-bar", + ): PluginConfig { + path: "compact-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "compact-bar", + ), + ), + }, + PluginTag( + "status-bar", + ): PluginConfig { + path: "status-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "status-bar", + ), + ), + }, + PluginTag( + "strider", + ): PluginConfig { + path: "strider", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "strider", + ), + ), + }, + PluginTag( + "tab-bar", + ): PluginConfig { + path: "tab-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "tab-bar", + ), + ), + }, + }, + ui: UiConfig { + pane_frames: FrameConfig { + rounded_corners: false, + }, + }, + env: { + "CONFIG_ENV_VAR": "do not override me", + "LAYOUT_ENV_VAR": "make sure I'm also here", + "MY_ENV_VAR": "from layout", + }, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap new file mode 100644 index 00000000..fd8007af --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap @@ -0,0 +1,149 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 625 +expression: "format!(\"{:#?}\", config)" +--- +Config { + keybinds: { + Normal: { + Char( + 'b', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Resize, + ), + ], + }, + Resize: { + Char( + 'b', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Resize, + ), + ], + }, + Scroll: { + Char( + 'b', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Resize, + ), + ], + }, + }, + options: Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, + }, + themes: {}, + plugins: { + PluginTag( + "compact-bar", + ): PluginConfig { + path: "compact-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "compact-bar", + ), + ), + }, + PluginTag( + "status-bar", + ): PluginConfig { + path: "status-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "status-bar", + ), + ), + }, + PluginTag( + "strider", + ): PluginConfig { + path: "strider", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "strider", + ), + ), + }, + PluginTag( + "tab-bar", + ): PluginConfig { + path: "tab-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "tab-bar", + ), + ), + }, + }, + ui: UiConfig { + pane_frames: FrameConfig { + rounded_corners: false, + }, + }, + env: {}, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap new file mode 100644 index 00000000..3a4e696d --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap @@ -0,0 +1,21 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 492 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap new file mode 100644 index 00000000..d8fc7879 --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap @@ -0,0 +1,27 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 567 +expression: "format!(\"{:#?}\", options)" +--- +Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: Some( + false, + ), + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap new file mode 100644 index 00000000..5a71f06a --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap @@ -0,0 +1,3377 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 557 +expression: "format!(\"{:#?}\", config)" +--- +Config { + keybinds: { + Normal: { + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + }, + Locked: { + Ctrl( + 'g', + ): [ + SwitchToMode( + Normal, + ), + ], + }, + Resize: { + Left: [ + Resize( + Left, + ), + ], + Down: [ + Resize( + Down, + ), + ], + Up: [ + Resize( + Up, + ), + ], + Right: [ + Resize( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '+', + ): [ + Resize( + Increase, + ), + ], + Char( + '-', + ): [ + Resize( + Decrease, + ), + ], + Char( + '=', + ): [ + Resize( + Increase, + ), + ], + Char( + 'h', + ): [ + Resize( + Left, + ), + ], + Char( + 'j', + ): [ + Resize( + Down, + ), + ], + Char( + 'k', + ): [ + Resize( + Up, + ), + ], + Char( + 'l', + ): [ + Resize( + Right, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Pane: { + Left: [ + MoveFocus( + Left, + ), + ], + Down: [ + MoveFocus( + Down, + ), + ], + Up: [ + MoveFocus( + Up, + ), + ], + Right: [ + MoveFocus( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SwitchToMode( + RenamePane, + ), + PaneNameInput( + [ + 0, + ], + ), + ], + Char( + 'd', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'e', + ): [ + TogglePaneEmbedOrFloating, + SwitchToMode( + Normal, + ), + ], + Char( + 'f', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + ], + Char( + 'n', + ): [ + NewPane( + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'p', + ): [ + SwitchFocus, + ], + Char( + 'r', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'w', + ): [ + ToggleFloatingPanes, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseFocus, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + TogglePaneFrames, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tab: { + Left: [ + GoToPreviousTab, + ], + Down: [ + GoToNextTab, + ], + Up: [ + GoToPreviousTab, + ], + Right: [ + GoToNextTab, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '1', + ): [ + GoToTab( + 1, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '2', + ): [ + GoToTab( + 2, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '3', + ): [ + GoToTab( + 3, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '4', + ): [ + GoToTab( + 4, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '5', + ): [ + GoToTab( + 5, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '6', + ): [ + GoToTab( + 6, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '7', + ): [ + GoToTab( + 7, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '8', + ): [ + GoToTab( + 8, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '9', + ): [ + GoToTab( + 9, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + GoToPreviousTab, + ], + Char( + 'j', + ): [ + GoToNextTab, + ], + Char( + 'k', + ): [ + GoToPreviousTab, + ], + Char( + 'l', + ): [ + GoToNextTab, + ], + Char( + 'n', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'r', + ): [ + SwitchToMode( + RenameTab, + ), + TabNameInput( + [ + 0, + ], + ), + ], + Char( + 's', + ): [ + ToggleActiveSyncTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseTab, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Normal, + ), + ], + BackTab: [ + ToggleTab, + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Scroll: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'e', + ): [ + EditScrollback, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 's', + ): [ + SwitchToMode( + EnterSearch, + ), + SearchInput( + [ + 0, + ], + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + EnterSearch: { + Char( + '\n', + ): [ + SwitchToMode( + Search, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Scroll, + ), + ], + }, + Search: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SearchToggleOption( + CaseSensitivity, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 'n', + ): [ + Search( + Down, + ), + ], + Char( + 'o', + ): [ + SearchToggleOption( + WholeWord, + ), + ], + Char( + 'p', + ): [ + Search( + Up, + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Char( + 'w', + ): [ + SearchToggleOption( + Wrap, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + RenameTab: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenameTab, + SwitchToMode( + Tab, + ), + ], + }, + RenamePane: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenamePane, + SwitchToMode( + Pane, + ), + ], + }, + Session: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Move: { + Left: [ + MovePane( + Some( + Left, + ), + ), + ], + Down: [ + MovePane( + Some( + Down, + ), + ), + ], + Up: [ + MovePane( + Some( + Up, + ), + ), + ], + Right: [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MovePane( + Some( + Left, + ), + ), + ], + Char( + 'j', + ): [ + MovePane( + Some( + Down, + ), + ), + ], + Char( + 'k', + ): [ + MovePane( + Some( + Up, + ), + ), + ], + Char( + 'l', + ): [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + 'n', + ): [ + MovePane( + None, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + BackTab: [ + MovePane( + None, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Prompt: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tmux: { + Left: [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Down: [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Up: [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Right: [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '"', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + '%', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + ',', + ): [ + SwitchToMode( + RenameTab, + ), + ], + Char( + '[', + ): [ + SwitchToMode( + Scroll, + ), + ], + Char( + 'c', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'n', + ): [ + GoToNextTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'o', + ): [ + FocusNextPane, + ], + Char( + 'p', + ): [ + GoToPreviousTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + Write( + [ + 2, + ], + ), + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + }, + options: Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, + }, + themes: {}, + plugins: { + PluginTag( + "compact-bar", + ): PluginConfig { + path: "compact-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "compact-bar", + ), + ), + }, + PluginTag( + "some-other-plugin", + ): PluginConfig { + path: "i-am-defined-in-the-layout", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "some-other-plugin", + ), + ), + }, + PluginTag( + "status-bar", + ): PluginConfig { + path: "status-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "status-bar", + ), + ), + }, + PluginTag( + "strider", + ): PluginConfig { + path: "strider", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "strider", + ), + ), + }, + PluginTag( + "tab-bar", + ): PluginConfig { + path: "tab-bar-from-layout", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "tab-bar", + ), + ), + }, + }, + ui: UiConfig { + pane_frames: FrameConfig { + rounded_corners: false, + }, + }, + env: {}, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap new file mode 100644 index 00000000..1af931ce --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap @@ -0,0 +1,3667 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 565 +expression: "format!(\"{:#?}\", config)" +--- +Config { + keybinds: { + Normal: { + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + }, + Locked: { + Ctrl( + 'g', + ): [ + SwitchToMode( + Normal, + ), + ], + }, + Resize: { + Left: [ + Resize( + Left, + ), + ], + Down: [ + Resize( + Down, + ), + ], + Up: [ + Resize( + Up, + ), + ], + Right: [ + Resize( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '+', + ): [ + Resize( + Increase, + ), + ], + Char( + '-', + ): [ + Resize( + Decrease, + ), + ], + Char( + '=', + ): [ + Resize( + Increase, + ), + ], + Char( + 'h', + ): [ + Resize( + Left, + ), + ], + Char( + 'j', + ): [ + Resize( + Down, + ), + ], + Char( + 'k', + ): [ + Resize( + Up, + ), + ], + Char( + 'l', + ): [ + Resize( + Right, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Pane: { + Left: [ + MoveFocus( + Left, + ), + ], + Down: [ + MoveFocus( + Down, + ), + ], + Up: [ + MoveFocus( + Up, + ), + ], + Right: [ + MoveFocus( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SwitchToMode( + RenamePane, + ), + PaneNameInput( + [ + 0, + ], + ), + ], + Char( + 'd', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'e', + ): [ + TogglePaneEmbedOrFloating, + SwitchToMode( + Normal, + ), + ], + Char( + 'f', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + ], + Char( + 'n', + ): [ + NewPane( + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'p', + ): [ + SwitchFocus, + ], + Char( + 'r', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'w', + ): [ + ToggleFloatingPanes, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseFocus, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + TogglePaneFrames, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tab: { + Left: [ + GoToPreviousTab, + ], + Down: [ + GoToNextTab, + ], + Up: [ + GoToPreviousTab, + ], + Right: [ + GoToNextTab, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '1', + ): [ + GoToTab( + 1, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '2', + ): [ + GoToTab( + 2, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '3', + ): [ + GoToTab( + 3, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '4', + ): [ + GoToTab( + 4, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '5', + ): [ + GoToTab( + 5, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '6', + ): [ + GoToTab( + 6, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '7', + ): [ + GoToTab( + 7, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '8', + ): [ + GoToTab( + 8, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '9', + ): [ + GoToTab( + 9, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + GoToPreviousTab, + ], + Char( + 'j', + ): [ + GoToNextTab, + ], + Char( + 'k', + ): [ + GoToPreviousTab, + ], + Char( + 'l', + ): [ + GoToNextTab, + ], + Char( + 'n', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'r', + ): [ + SwitchToMode( + RenameTab, + ), + TabNameInput( + [ + 0, + ], + ), + ], + Char( + 's', + ): [ + ToggleActiveSyncTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseTab, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Normal, + ), + ], + BackTab: [ + ToggleTab, + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Scroll: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'e', + ): [ + EditScrollback, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 's', + ): [ + SwitchToMode( + EnterSearch, + ), + SearchInput( + [ + 0, + ], + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + EnterSearch: { + Char( + '\n', + ): [ + SwitchToMode( + Search, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Scroll, + ), + ], + }, + Search: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SearchToggleOption( + CaseSensitivity, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 'n', + ): [ + Search( + Down, + ), + ], + Char( + 'o', + ): [ + SearchToggleOption( + WholeWord, + ), + ], + Char( + 'p', + ): [ + Search( + Up, + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Char( + 'w', + ): [ + SearchToggleOption( + Wrap, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + RenameTab: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenameTab, + SwitchToMode( + Tab, + ), + ], + }, + RenamePane: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenamePane, + SwitchToMode( + Pane, + ), + ], + }, + Session: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Move: { + Left: [ + MovePane( + Some( + Left, + ), + ), + ], + Down: [ + MovePane( + Some( + Down, + ), + ), + ], + Up: [ + MovePane( + Some( + Up, + ), + ), + ], + Right: [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MovePane( + Some( + Left, + ), + ), + ], + Char( + 'j', + ): [ + MovePane( + Some( + Down, + ), + ), + ], + Char( + 'k', + ): [ + MovePane( + Some( + Up, + ), + ), + ], + Char( + 'l', + ): [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + 'n', + ): [ + MovePane( + None, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + BackTab: [ + MovePane( + None, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Prompt: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tmux: { + Left: [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Down: [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Up: [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Right: [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '"', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + '%', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + ',', + ): [ + SwitchToMode( + RenameTab, + ), + ], + Char( + '[', + ): [ + SwitchToMode( + Scroll, + ), + ], + Char( + 'c', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'n', + ): [ + GoToNextTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'o', + ): [ + FocusNextPane, + ], + Char( + 'p', + ): [ + GoToPreviousTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + Write( + [ + 2, + ], + ), + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + }, + options: Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, + }, + themes: { + "other-theme-from-config": Theme { + palette: Palette { + source: Default, + theme_hue: Dark, + fg: Rgb( + ( + 2, + 2, + 2, + ), + ), + bg: Rgb( + ( + 2, + 2, + 2, + ), + ), + black: Rgb( + ( + 2, + 2, + 2, + ), + ), + red: Rgb( + ( + 2, + 2, + 2, + ), + ), + green: Rgb( + ( + 2, + 2, + 2, + ), + ), + yellow: Rgb( + ( + 2, + 2, + 2, + ), + ), + blue: Rgb( + ( + 2, + 2, + 2, + ), + ), + magenta: Rgb( + ( + 2, + 2, + 2, + ), + ), + cyan: Rgb( + ( + 2, + 2, + 2, + ), + ), + white: Rgb( + ( + 2, + 2, + 2, + ), + ), + orange: Rgb( + ( + 2, + 2, + 2, + ), + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + }, + "theme-from-config": Theme { + palette: Palette { + source: Default, + theme_hue: Dark, + fg: Rgb( + ( + 1, + 1, + 1, + ), + ), + bg: Rgb( + ( + 1, + 1, + 1, + ), + ), + black: Rgb( + ( + 1, + 1, + 1, + ), + ), + red: Rgb( + ( + 1, + 1, + 1, + ), + ), + green: Rgb( + ( + 1, + 1, + 1, + ), + ), + yellow: Rgb( + ( + 1, + 1, + 1, + ), + ), + blue: Rgb( + ( + 1, + 1, + 1, + ), + ), + magenta: Rgb( + ( + 1, + 1, + 1, + ), + ), + cyan: Rgb( + ( + 1, + 1, + 1, + ), + ), + white: Rgb( + ( + 1, + 1, + 1, + ), + ), + orange: Rgb( + ( + 1, + 1, + 1, + ), + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + }, + "theme-from-layout": Theme { + palette: Palette { + source: Default, + theme_hue: Dark, + fg: Rgb( + ( + 1, + 1, + 1, + ), + ), + bg: Rgb( + ( + 1, + 1, + 1, + ), + ), + black: Rgb( + ( + 1, + 1, + 1, + ), + ), + red: Rgb( + ( + 1, + 1, + 1, + ), + ), + green: Rgb( + ( + 1, + 1, + 1, + ), + ), + yellow: Rgb( + ( + 1, + 1, + 1, + ), + ), + blue: Rgb( + ( + 1, + 1, + 1, + ), + ), + magenta: Rgb( + ( + 1, + 1, + 1, + ), + ), + cyan: Rgb( + ( + 1, + 1, + 1, + ), + ), + white: Rgb( + ( + 1, + 1, + 1, + ), + ), + orange: Rgb( + ( + 1, + 1, + 1, + ), + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + }, + }, + plugins: { + PluginTag( + "compact-bar", + ): PluginConfig { + path: "compact-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "compact-bar", + ), + ), + }, + PluginTag( + "status-bar", + ): PluginConfig { + path: "status-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "status-bar", + ), + ), + }, + PluginTag( + "strider", + ): PluginConfig { + path: "strider", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "strider", + ), + ), + }, + PluginTag( + "tab-bar", + ): PluginConfig { + path: "tab-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "tab-bar", + ), + ), + }, + }, + ui: UiConfig { + pane_frames: FrameConfig { + rounded_corners: false, + }, + }, + env: {}, +} diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap new file mode 100644 index 00000000..1e19ab48 --- /dev/null +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap @@ -0,0 +1,3363 @@ +--- +source: zellij-utils/src/setup.rs +assertion_line: 549 +expression: "format!(\"{:#?}\", config)" +--- +Config { + keybinds: { + Normal: { + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + }, + Locked: { + Ctrl( + 'g', + ): [ + SwitchToMode( + Normal, + ), + ], + }, + Resize: { + Left: [ + Resize( + Left, + ), + ], + Down: [ + Resize( + Down, + ), + ], + Up: [ + Resize( + Up, + ), + ], + Right: [ + Resize( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '+', + ): [ + Resize( + Increase, + ), + ], + Char( + '-', + ): [ + Resize( + Decrease, + ), + ], + Char( + '=', + ): [ + Resize( + Increase, + ), + ], + Char( + 'h', + ): [ + Resize( + Left, + ), + ], + Char( + 'j', + ): [ + Resize( + Down, + ), + ], + Char( + 'k', + ): [ + Resize( + Up, + ), + ], + Char( + 'l', + ): [ + Resize( + Right, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Pane: { + Left: [ + MoveFocus( + Left, + ), + ], + Down: [ + MoveFocus( + Down, + ), + ], + Up: [ + MoveFocus( + Up, + ), + ], + Right: [ + MoveFocus( + Right, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SwitchToMode( + RenamePane, + ), + PaneNameInput( + [ + 0, + ], + ), + ], + Char( + 'd', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'e', + ): [ + TogglePaneEmbedOrFloating, + SwitchToMode( + Normal, + ), + ], + Char( + 'f', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + ], + Char( + 'n', + ): [ + NewPane( + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'p', + ): [ + SwitchFocus, + ], + Char( + 'r', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'w', + ): [ + ToggleFloatingPanes, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseFocus, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + TogglePaneFrames, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tab: { + Left: [ + GoToPreviousTab, + ], + Down: [ + GoToNextTab, + ], + Up: [ + GoToPreviousTab, + ], + Right: [ + GoToNextTab, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '1', + ): [ + GoToTab( + 1, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '2', + ): [ + GoToTab( + 2, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '3', + ): [ + GoToTab( + 3, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '4', + ): [ + GoToTab( + 4, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '5', + ): [ + GoToTab( + 5, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '6', + ): [ + GoToTab( + 6, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '7', + ): [ + GoToTab( + 7, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '8', + ): [ + GoToTab( + 8, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '9', + ): [ + GoToTab( + 9, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + GoToPreviousTab, + ], + Char( + 'j', + ): [ + GoToNextTab, + ], + Char( + 'k', + ): [ + GoToPreviousTab, + ], + Char( + 'l', + ): [ + GoToNextTab, + ], + Char( + 'n', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'r', + ): [ + SwitchToMode( + RenameTab, + ), + TabNameInput( + [ + 0, + ], + ), + ], + Char( + 's', + ): [ + ToggleActiveSyncTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'x', + ): [ + CloseTab, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Normal, + ), + ], + BackTab: [ + ToggleTab, + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Scroll: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'e', + ): [ + EditScrollback, + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 's', + ): [ + SwitchToMode( + EnterSearch, + ), + SearchInput( + [ + 0, + ], + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + EnterSearch: { + Char( + '\n', + ): [ + SwitchToMode( + Search, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Scroll, + ), + ], + }, + Search: { + PageDown: [ + PageScrollDown, + ], + PageUp: [ + PageScrollUp, + ], + Left: [ + PageScrollUp, + ], + Down: [ + ScrollDown, + ], + Up: [ + ScrollUp, + ], + Right: [ + PageScrollDown, + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'c', + ): [ + SearchToggleOption( + CaseSensitivity, + ), + ], + Char( + 'd', + ): [ + HalfPageScrollDown, + ], + Char( + 'h', + ): [ + PageScrollUp, + ], + Char( + 'j', + ): [ + ScrollDown, + ], + Char( + 'k', + ): [ + ScrollUp, + ], + Char( + 'l', + ): [ + PageScrollDown, + ], + Char( + 'n', + ): [ + Search( + Down, + ), + ], + Char( + 'o', + ): [ + SearchToggleOption( + WholeWord, + ), + ], + Char( + 'p', + ): [ + Search( + Up, + ), + ], + Char( + 'u', + ): [ + HalfPageScrollUp, + ], + Char( + 'w', + ): [ + SearchToggleOption( + Wrap, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + PageScrollUp, + ], + Ctrl( + 'c', + ): [ + ScrollToBottom, + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'f', + ): [ + PageScrollDown, + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + RenameTab: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenameTab, + SwitchToMode( + Tab, + ), + ], + }, + RenamePane: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'c', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + UndoRenamePane, + SwitchToMode( + Pane, + ), + ], + }, + Session: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Move: { + Left: [ + MovePane( + Some( + Left, + ), + ), + ], + Down: [ + MovePane( + Some( + Down, + ), + ), + ], + Up: [ + MovePane( + Some( + Up, + ), + ), + ], + Right: [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + 'h', + ): [ + MovePane( + Some( + Left, + ), + ), + ], + Char( + 'j', + ): [ + MovePane( + Some( + Down, + ), + ), + ], + Char( + 'k', + ): [ + MovePane( + Some( + Up, + ), + ), + ], + Char( + 'l', + ): [ + MovePane( + Some( + Right, + ), + ), + ], + Char( + 'n', + ): [ + MovePane( + None, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + BackTab: [ + MovePane( + None, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Prompt: { + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + SwitchToMode( + Tmux, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + Tmux: { + Left: [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Down: [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Up: [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Right: [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + '\n', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + ' ', + ): [ + SwitchToMode( + Normal, + ), + ], + Char( + '"', + ): [ + NewPane( + Some( + Down, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + '%', + ): [ + NewPane( + Some( + Right, + ), + ), + SwitchToMode( + Normal, + ), + ], + Char( + ',', + ): [ + SwitchToMode( + RenameTab, + ), + ], + Char( + '[', + ): [ + SwitchToMode( + Scroll, + ), + ], + Char( + 'c', + ): [ + NewTab( + None, + None, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'd', + ): [ + Detach, + ], + Char( + 'h', + ): [ + MoveFocus( + Left, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'j', + ): [ + MoveFocus( + Down, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'k', + ): [ + MoveFocus( + Up, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'l', + ): [ + MoveFocus( + Right, + ), + SwitchToMode( + Normal, + ), + ], + Char( + 'n', + ): [ + GoToNextTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'o', + ): [ + FocusNextPane, + ], + Char( + 'p', + ): [ + GoToPreviousTab, + SwitchToMode( + Normal, + ), + ], + Char( + 'z', + ): [ + ToggleFocusFullscreen, + SwitchToMode( + Normal, + ), + ], + Alt( + Char( + '+', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + '-', + ), + ): [ + Resize( + Decrease, + ), + ], + Alt( + Char( + '=', + ), + ): [ + Resize( + Increase, + ), + ], + Alt( + Char( + 'h', + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Char( + 'j', + ), + ): [ + MoveFocus( + Down, + ), + ], + Alt( + Char( + 'k', + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Char( + 'l', + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Char( + 'n', + ), + ): [ + NewPane( + None, + ), + ], + Alt( + Direction( + Left, + ), + ): [ + MoveFocusOrTab( + Left, + ), + ], + Alt( + Direction( + Right, + ), + ): [ + MoveFocusOrTab( + Right, + ), + ], + Alt( + Direction( + Up, + ), + ): [ + MoveFocus( + Up, + ), + ], + Alt( + Direction( + Down, + ), + ): [ + MoveFocus( + Down, + ), + ], + Ctrl( + 'b', + ): [ + Write( + [ + 2, + ], + ), + SwitchToMode( + Normal, + ), + ], + Ctrl( + 'g', + ): [ + SwitchToMode( + Locked, + ), + ], + Ctrl( + 'h', + ): [ + SwitchToMode( + Move, + ), + ], + Ctrl( + 'n', + ): [ + SwitchToMode( + Resize, + ), + ], + Ctrl( + 'o', + ): [ + SwitchToMode( + Session, + ), + ], + Ctrl( + 'p', + ): [ + SwitchToMode( + Pane, + ), + ], + Ctrl( + 'q', + ): [ + Quit, + ], + Ctrl( + 's', + ): [ + SwitchToMode( + Scroll, + ), + ], + Ctrl( + 't', + ): [ + SwitchToMode( + Tab, + ), + ], + Esc: [ + SwitchToMode( + Normal, + ), + ], + }, + }, + options: Options { + simplified_ui: None, + theme: None, + default_mode: None, + default_shell: None, + default_layout: None, + layout_dir: None, + theme_dir: None, + mouse_mode: None, + pane_frames: None, + mirror_session: None, + on_force_close: None, + scroll_buffer_size: None, + copy_command: None, + copy_clipboard: None, + copy_on_select: None, + scrollback_editor: None, + session_name: None, + attach_to_session: None, + }, + themes: {}, + plugins: { + PluginTag( + "compact-bar", + ): PluginConfig { + path: "compact-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "compact-bar", + ), + ), + }, + PluginTag( + "status-bar", + ): PluginConfig { + path: "status-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "status-bar", + ), + ), + }, + PluginTag( + "strider", + ): PluginConfig { + path: "strider", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "strider", + ), + ), + }, + PluginTag( + "tab-bar", + ): PluginConfig { + path: "tab-bar", + run: Pane( + None, + ), + _allow_exec_host_cmd: false, + location: Zellij( + PluginTag( + "tab-bar", + ), + ), + }, + }, + ui: UiConfig { + pane_frames: FrameConfig { + rounded_corners: true, + }, + }, + env: {}, +} diff --git a/zellij-utils/src/test-fixtures/config-with-env-vars.kdl b/zellij-utils/src/test-fixtures/config-with-env-vars.kdl new file mode 100644 index 00000000..87c94e6c --- /dev/null +++ b/zellij-utils/src/test-fixtures/config-with-env-vars.kdl @@ -0,0 +1,4 @@ +env { + CONFIG_ENV_VAR "do not override me" + MY_ENV_VAR "from config" +} diff --git a/zellij-utils/src/test-fixtures/config-with-keybindings-config.kdl b/zellij-utils/src/test-fixtures/config-with-keybindings-config.kdl new file mode 100644 index 00000000..84f98de5 --- /dev/null +++ b/zellij-utils/src/test-fixtures/config-with-keybindings-config.kdl @@ -0,0 +1,11 @@ +layout +keybinds clear-defaults=true { + normal { + bind "b" { SwitchToMode "Locked"; } + bind "Ctrl c" { SwitchToMode "Resize"; } + } + resize { + bind "b" { SwitchToMode "Locked"; } + bind "Ctrl c" { SwitchToMode "Resize"; } + } +} diff --git a/zellij-utils/src/test-fixtures/config-with-plugins-config.kdl b/zellij-utils/src/test-fixtures/config-with-plugins-config.kdl new file mode 100644 index 00000000..513e4de0 --- /dev/null +++ b/zellij-utils/src/test-fixtures/config-with-plugins-config.kdl @@ -0,0 +1,6 @@ +plugins { + tab-bar { path "tab-bar"; } + status-bar { path "status-bar"; } + strider { path "strider"; } + compact-bar { path "compact-bar"; } +} diff --git a/zellij-utils/src/test-fixtures/config-with-themes-config.kdl b/zellij-utils/src/test-fixtures/config-with-themes-config.kdl new file mode 100644 index 00000000..e0ed0aa3 --- /dev/null +++ b/zellij-utils/src/test-fixtures/config-with-themes-config.kdl @@ -0,0 +1,28 @@ +themes { + other-theme-from-config { + bg 2 2 2 + red 2 2 2 + green 2 2 2 + yellow 2 2 2 + blue 2 2 2 + magenta 2 2 2 + orange 2 2 2 + fg 2 2 2 + cyan 2 2 2 + black 2 2 2 + white 2 2 2 + } + theme-from-config { + bg 2 2 2 + red 2 2 2 + green 2 2 2 + yellow 2 2 2 + blue 2 2 2 + magenta 2 2 2 + orange 2 2 2 + fg 2 2 2 + cyan 2 2 2 + black 2 2 2 + white 2 2 2 + } +} diff --git a/zellij-utils/src/test-fixtures/config-with-ui-config.kdl b/zellij-utils/src/test-fixtures/config-with-ui-config.kdl new file mode 100644 index 00000000..fbd518fa --- /dev/null +++ b/zellij-utils/src/test-fixtures/config-with-ui-config.kdl @@ -0,0 +1,5 @@ +ui { + pane_frames { + rounded_corners false + } +} diff --git a/zellij-utils/src/test-fixtures/layout-with-env-vars.kdl b/zellij-utils/src/test-fixtures/layout-with-env-vars.kdl new file mode 100644 index 00000000..0ef6721a --- /dev/null +++ b/zellij-utils/src/test-fixtures/layout-with-env-vars.kdl @@ -0,0 +1,5 @@ +layout +env { + LAYOUT_ENV_VAR "make sure I'm also here" + MY_ENV_VAR "from layout" +} diff --git a/zellij-utils/src/test-fixtures/layout-with-keybindings-config.kdl b/zellij-utils/src/test-fixtures/layout-with-keybindings-config.kdl new file mode 100644 index 00000000..62c5cd8b --- /dev/null +++ b/zellij-utils/src/test-fixtures/layout-with-keybindings-config.kdl @@ -0,0 +1,11 @@ +layout +keybinds { + normal { + bind "b" { SwitchToMode "Session"; } + bind "Ctrl b" { SwitchToMode "Resize"; } + } + scroll { + bind "b" { SwitchToMode "Locked"; } + bind "Ctrl c" { SwitchToMode "Resize"; } + } +} diff --git a/zellij-utils/src/test-fixtures/layout-with-options.kdl b/zellij-utils/src/test-fixtures/layout-with-options.kdl new file mode 100644 index 00000000..408003b1 --- /dev/null +++ b/zellij-utils/src/test-fixtures/layout-with-options.kdl @@ -0,0 +1,2 @@ +layout +pane_frames false diff --git a/zellij-utils/src/test-fixtures/layout-with-plugins-config.kdl b/zellij-utils/src/test-fixtures/layout-with-plugins-config.kdl new file mode 100644 index 00000000..95b177ab --- /dev/null +++ b/zellij-utils/src/test-fixtures/layout-with-plugins-config.kdl @@ -0,0 +1,5 @@ +layout +plugins { + some-other-plugin { path "i-am-defined-in-the-layout"; } + tab-bar { path "tab-bar-from-layout"; } +} diff --git a/zellij-utils/src/test-fixtures/layout-with-themes-config.kdl b/zellij-utils/src/test-fixtures/layout-with-themes-config.kdl new file mode 100644 index 00000000..7fc57aa0 --- /dev/null +++ b/zellij-utils/src/test-fixtures/layout-with-themes-config.kdl @@ -0,0 +1,30 @@ +layout +themes { + theme-from-config { + bg 1 1 1 + red 1 1 1 + green 1 1 1 + yellow 1 1 1 + blue 1 1 1 + magenta 1 1 1 + orange 1 1 1 + fg 1 1 1 + cyan 1 1 1 + black 1 1 1 + white 1 1 1 + } + theme-from-layout { + bg 1 1 1 + red 1 1 1 + green 1 1 1 + yellow 1 1 1 + blue 1 1 1 + magenta 1 1 1 + orange 1 1 1 + fg 1 1 1 + cyan 1 1 1 + black 1 1 1 + white 1 1 1 + } +} + diff --git a/zellij-utils/src/test-fixtures/layout-with-ui-config.kdl b/zellij-utils/src/test-fixtures/layout-with-ui-config.kdl new file mode 100644 index 00000000..dfaeee91 --- /dev/null +++ b/zellij-utils/src/test-fixtures/layout-with-ui-config.kdl @@ -0,0 +1,6 @@ +layout +ui { + pane_frames { + rounded_corners true + } +}