diff options
| author | Aram Drevekenin <aram@poor.dev> | 2024-08-16 14:00:01 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-16 14:00:01 +0200 |
| commit | 056537d3eef06cddc60dc13b715a41766bb1fe9d (patch) | |
| tree | ff7e107e992e4c98ac60ac88da7215cb0beb668a /zellij-utils/src/kdl | |
| parent | docs(changelog): CommandPaneReRun plugin event (diff) | |
| download | sl0ppij-056537d3eef06cddc60dc13b715a41766bb1fe9d.tar.gz sl0ppij-056537d3eef06cddc60dc13b715a41766bb1fe9d.tar.xz sl0ppij-056537d3eef06cddc60dc13b715a41766bb1fe9d.zip | |
feat(ux): first run setup-wizard (#3556)
* separate saved/runtime structure, kind of working
* serializing config
* work
* work
* save config through the configuration screen
* work
* startup wizard
* style(code): cleanups
* fix(session): reload config from disk when switching sessions
* style(fmt): rustfmt
* fix(config): propagate cli config options to screen
* style(fmt): rustfmt
Diffstat (limited to 'zellij-utils/src/kdl')
22 files changed, 3896 insertions, 10 deletions
diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index 37d02081..bfb01c78 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -1,25 +1,27 @@ mod kdl_layout_parser; use crate::data::{ - Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier, LayoutInfo, Palette, + BareKey, Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier, LayoutInfo, Palette, PaletteColor, PaneInfo, PaneManifest, PermissionType, Resize, SessionInfo, TabInfo, }; use crate::envs::EnvironmentVariables; use crate::home::{find_default_config_dir, get_layout_dir}; use crate::input::config::{Config, ConfigError, KdlError}; use crate::input::keybinds::Keybinds; -use crate::input::layout::{Layout, RunPlugin, RunPluginOrAlias}; +use crate::input::layout::{ + Layout, PluginUserConfiguration, RunPlugin, RunPluginOrAlias, SplitSize, +}; use crate::input::options::{Clipboard, OnForceClose, Options}; use crate::input::permission::{GrantedPermission, PermissionCache}; use crate::input::plugins::PluginAliases; use crate::input::theme::{FrameConfig, Theme, Themes, UiConfig}; use kdl_layout_parser::KdlLayoutParser; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use strum::IntoEnumIterator; use uuid::Uuid; use miette::NamedSource; -use kdl::{KdlDocument, KdlEntry, KdlNode}; +use kdl::{KdlDocument, KdlEntry, KdlNode, KdlValue}; use std::path::PathBuf; use std::str::FromStr; @@ -548,6 +550,526 @@ impl Action { )), } } + pub fn to_kdl(&self) -> Option<KdlNode> { + match self { + Action::Quit => Some(KdlNode::new("Quit")), + Action::Write(_key, bytes, _is_kitty) => { + let mut node = KdlNode::new("Write"); + for byte in bytes { + node.push(KdlValue::Base10(*byte as i64)); + } + Some(node) + }, + Action::WriteChars(string) => { + let mut node = KdlNode::new("WriteChars"); + node.push(string.clone()); + Some(node) + }, + Action::SwitchToMode(input_mode) => { + let mut node = KdlNode::new("SwitchToMode"); + node.push(format!("{:?}", input_mode).to_lowercase()); + Some(node) + }, + Action::Resize(resize, resize_direction) => { + let mut node = KdlNode::new("Resize"); + let resize = match resize { + Resize::Increase => "Increase", + Resize::Decrease => "Decrease", + }; + if let Some(resize_direction) = resize_direction { + let resize_direction = match resize_direction { + Direction::Left => "left", + Direction::Right => "right", + Direction::Up => "up", + Direction::Down => "down", + }; + node.push(format!("{} {}", resize, resize_direction)); + } else { + node.push(format!("{}", resize)); + } + Some(node) + }, + Action::FocusNextPane => Some(KdlNode::new("FocusNextPane")), + Action::FocusPreviousPane => Some(KdlNode::new("FocusPreviousPane")), + Action::SwitchFocus => Some(KdlNode::new("SwitchFocus")), + Action::MoveFocus(direction) => { + let mut node = KdlNode::new("MoveFocus"); + let direction = match direction { + Direction::Left => "left", + Direction::Right => "right", + Direction::Up => "up", + Direction::Down => "down", + }; + node.push(direction); + Some(node) + }, + Action::MoveFocusOrTab(direction) => { + let mut node = KdlNode::new("MoveFocusOrTab"); + let direction = match direction { + Direction::Left => "left", + Direction::Right => "right", + Direction::Up => "up", + Direction::Down => "down", + }; + node.push(direction); + Some(node) + }, + Action::MovePane(direction) => { + let mut node = KdlNode::new("MovePane"); + if let Some(direction) = direction { + let direction = match direction { + Direction::Left => "left", + Direction::Right => "right", + Direction::Up => "up", + Direction::Down => "down", + }; + node.push(direction); + } + Some(node) + }, + Action::MovePaneBackwards => Some(KdlNode::new("MovePaneBackwards")), + Action::DumpScreen(file, _) => { + let mut node = KdlNode::new("DumpScreen"); + node.push(file.clone()); + Some(node) + }, + Action::DumpLayout => Some(KdlNode::new("DumpLayout")), + Action::EditScrollback => Some(KdlNode::new("EditScrollback")), + Action::ScrollUp => Some(KdlNode::new("ScrollUp")), + Action::ScrollDown => Some(KdlNode::new("ScrollDown")), + Action::ScrollToBottom => Some(KdlNode::new("ScrollToBottom")), + Action::ScrollToTop => Some(KdlNode::new("ScrollToTop")), + Action::PageScrollUp => Some(KdlNode::new("PageScrollUp")), + Action::PageScrollDown => Some(KdlNode::new("PageScrollDown")), + Action::HalfPageScrollUp => Some(KdlNode::new("HalfPageScrollUp")), + Action::HalfPageScrollDown => Some(KdlNode::new("HalfPageScrollDown")), + Action::ToggleFocusFullscreen => Some(KdlNode::new("ToggleFocusFullscreen")), + Action::TogglePaneFrames => Some(KdlNode::new("TogglePaneFrames")), + Action::ToggleActiveSyncTab => Some(KdlNode::new("ToggleActiveSyncTab")), + Action::NewPane(direction, _, _) => { + let mut node = KdlNode::new("NewPane"); + if let Some(direction) = direction { + let direction = match direction { + Direction::Left => "left", + Direction::Right => "right", + Direction::Up => "up", + Direction::Down => "down", + }; + node.push(direction); + } + Some(node) + }, + Action::TogglePaneEmbedOrFloating => Some(KdlNode::new("TogglePaneEmbedOrFloating")), + Action::ToggleFloatingPanes => Some(KdlNode::new("ToggleFloatingPanes")), + Action::CloseFocus => Some(KdlNode::new("CloseFocus")), + Action::PaneNameInput(bytes) => { + let mut node = KdlNode::new("PaneNameInput"); + for byte in bytes { + node.push(KdlValue::Base10(*byte as i64)); + } + Some(node) + }, + Action::UndoRenamePane => Some(KdlNode::new("UndoRenamePane")), + Action::NewTab(_, _, _, _, name) => { + log::warn!("Converting new tab action without arguments, original action saved to .bak.kdl file"); + let mut node = KdlNode::new("NewTab"); + if let Some(name) = name { + let mut children = KdlDocument::new(); + let mut name_node = KdlNode::new("name"); + name_node.push(name.clone()); + children.nodes_mut().push(name_node); + node.set_children(children); + } + Some(node) + }, + Action::GoToNextTab => Some(KdlNode::new("GoToNextTab")), + Action::GoToPreviousTab => Some(KdlNode::new("GoToPreviousTab")), + Action::CloseTab => Some(KdlNode::new("CloseTab")), + Action::GoToTab(index) => { + let mut node = KdlNode::new("GoToTab"); + node.push(KdlValue::Base10(*index as i64)); + Some(node) + }, + Action::ToggleTab => Some(KdlNode::new("ToggleTab")), + Action::TabNameInput(bytes) => { + let mut node = KdlNode::new("TabNameInput"); + for byte in bytes { + node.push(KdlValue::Base10(*byte as i64)); + } + Some(node) + }, + Action::UndoRenameTab => Some(KdlNode::new("UndoRenameTab")), + Action::MoveTab(direction) => { + let mut node = KdlNode::new("MoveTab"); + let direction = match direction { + Direction::Left => "left", + Direction::Right => "right", + Direction::Up => "up", + Direction::Down => "down", + }; + node.push(direction); + Some(node) + }, + Action::NewTiledPane(direction, run_command_action, name) => { + let mut node = KdlNode::new("Run"); + let mut node_children = KdlDocument::new(); + if let Some(run_command_action) = run_command_action { + node.push(run_command_action.command.display().to_string()); + for arg in &run_command_action.args { + node.push(arg.clone()); + } + if let Some(cwd) = &run_command_action.cwd { + let mut cwd_node = KdlNode::new("cwd"); + cwd_node.push(cwd.display().to_string()); + node_children.nodes_mut().push(cwd_node); + } + if run_command_action.hold_on_start { + let mut hos_node = KdlNode::new("hold_on_start"); + hos_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(hos_node); + } + if !run_command_action.hold_on_close { + let mut hoc_node = KdlNode::new("hold_on_close"); + hoc_node.push(KdlValue::Bool(false)); + node_children.nodes_mut().push(hoc_node); + } + } + if let Some(name) = name { + let mut name_node = KdlNode::new("name"); + name_node.push(name.clone()); + node_children.nodes_mut().push(name_node); + } + if let Some(direction) = direction { + let mut direction_node = KdlNode::new("direction"); + let direction = match direction { + Direction::Left => "left", + Direction::Right => "right", + Direction::Up => "up", + Direction::Down => "down", + }; + direction_node.push(direction); + node_children.nodes_mut().push(direction_node); + } + if !node_children.nodes().is_empty() { + node.set_children(node_children); + } + Some(node) + }, + Action::NewFloatingPane(run_command_action, name, floating_pane_coordinates) => { + let mut node = KdlNode::new("Run"); + let mut node_children = KdlDocument::new(); + let mut floating_pane = KdlNode::new("floating"); + floating_pane.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(floating_pane); + if let Some(run_command_action) = run_command_action { + node.push(run_command_action.command.display().to_string()); + for arg in &run_command_action.args { + node.push(arg.clone()); + } + if let Some(cwd) = &run_command_action.cwd { + let mut cwd_node = KdlNode::new("cwd"); + cwd_node.push(cwd.display().to_string()); + node_children.nodes_mut().push(cwd_node); + } + if run_command_action.hold_on_start { + let mut hos_node = KdlNode::new("hold_on_start"); + hos_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(hos_node); + } + if !run_command_action.hold_on_close { + let mut hoc_node = KdlNode::new("hold_on_close"); + hoc_node.push(KdlValue::Bool(false)); + node_children.nodes_mut().push(hoc_node); + } + } + if let Some(floating_pane_coordinates) = floating_pane_coordinates { + if let Some(x) = floating_pane_coordinates.x { + let mut x_node = KdlNode::new("x"); + match x { + SplitSize::Percent(x) => { + x_node.push(format!("{}%", x)); + }, + SplitSize::Fixed(x) => { + x_node.push(KdlValue::Base10(x as i64)); + }, + }; + node_children.nodes_mut().push(x_node); + } + if let Some(y) = floating_pane_coordinates.y { + let mut y_node = KdlNode::new("y"); + match y { + SplitSize::Percent(y) => { + y_node.push(format!("{}%", y)); + }, + SplitSize::Fixed(y) => { + y_node.push(KdlValue::Base10(y as i64)); + }, + }; + node_children.nodes_mut().push(y_node); + } + if let Some(width) = floating_pane_coordinates.width { + let mut width_node = KdlNode::new("width"); + match width { + SplitSize::Percent(width) => { + width_node.push(format!("{}%", width)); + }, + SplitSize::Fixed(width) => { + width_node.push(KdlValue::Base10(width as i64)); + }, + }; + node_children.nodes_mut().push(width_node); + } + if let Some(height) = floating_pane_coordinates.height { + let mut height_node = KdlNode::new("height"); + match height { + SplitSize::Percent(height) => { + height_node.push(format!("{}%", height)); + }, + SplitSize::Fixed(height) => { + height_node.push(KdlValue::Base10(height as i64)); + }, + }; + node_children.nodes_mut().push(height_node); + } + } + if let Some(name) = name { + let mut name_node = KdlNode::new("name"); + name_node.push(name.clone()); + node_children.nodes_mut().push(name_node); + } + if !node_children.nodes().is_empty() { + node.set_children(node_children); + } + Some(node) + }, + Action::NewInPlacePane(run_command_action, name) => { + let mut node = KdlNode::new("Run"); + let mut node_children = KdlDocument::new(); + if let Some(run_command_action) = run_command_action { + node.push(run_command_action.command.display().to_string()); + for arg in &run_command_action.args { + node.push(arg.clone()); + } + let mut in_place_node = KdlNode::new("in_place"); + in_place_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(in_place_node); + if let Some(cwd) = &run_command_action.cwd { + let mut cwd_node = KdlNode::new("cwd"); + cwd_node.push(cwd.display().to_string()); + node_children.nodes_mut().push(cwd_node); + } + if run_command_action.hold_on_start { + let mut hos_node = KdlNode::new("hold_on_start"); + hos_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(hos_node); + } + if !run_command_action.hold_on_close { + let mut hoc_node = KdlNode::new("hold_on_close"); + hoc_node.push(KdlValue::Bool(false)); + node_children.nodes_mut().push(hoc_node); + } + } + if let Some(name) = name { + let mut name_node = KdlNode::new("name"); + name_node.push(name.clone()); + node_children.nodes_mut().push(name_node); + } + if !node_children.nodes().is_empty() { + node.set_children(node_children); + } + Some(node) + }, + Action::Detach => Some(KdlNode::new("Detach")), + Action::LaunchOrFocusPlugin( + run_plugin_or_alias, + should_float, + move_to_focused_tab, + should_open_in_place, + skip_plugin_cache, + ) => { + let mut node = KdlNode::new("LaunchOrFocusPlugin"); + let mut node_children = KdlDocument::new(); + let location = run_plugin_or_alias.location_string(); + node.push(location); + if *should_float { + let mut should_float_node = KdlNode::new("floating"); + should_float_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(should_float_node); + } + if *move_to_focused_tab { + let mut move_to_focused_tab_node = KdlNode::new("move_to_focused_tab"); + move_to_focused_tab_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(move_to_focused_tab_node); + } + if *should_open_in_place { + let mut should_open_in_place_node = KdlNode::new("in_place"); + should_open_in_place_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(should_open_in_place_node); + } + if *skip_plugin_cache { + let mut skip_plugin_cache_node = KdlNode::new("skip_plugin_cache"); + skip_plugin_cache_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(skip_plugin_cache_node); + } + if let Some(configuration) = run_plugin_or_alias.get_configuration() { + for (config_key, config_value) in configuration.inner().iter() { + let mut node = KdlNode::new(config_key.clone()); + node.push(config_value.clone()); + node_children.nodes_mut().push(node); + } + } + if !node_children.nodes().is_empty() { + node.set_children(node_children); + } + Some(node) + }, + Action::LaunchPlugin( + run_plugin_or_alias, + should_float, + should_open_in_place, + skip_plugin_cache, + cwd, + ) => { + let mut node = KdlNode::new("LaunchPlugin"); + let mut node_children = KdlDocument::new(); + let location = run_plugin_or_alias.location_string(); + node.push(location); + if *should_float { + let mut should_float_node = KdlNode::new("floating"); + should_float_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(should_float_node); + } + if *should_open_in_place { + let mut should_open_in_place_node = KdlNode::new("in_place"); + should_open_in_place_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(should_open_in_place_node); + } + if *skip_plugin_cache { + let mut skip_plugin_cache_node = KdlNode::new("skip_plugin_cache"); + skip_plugin_cache_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(skip_plugin_cache_node); + } + if let Some(cwd) = &cwd { + let mut cwd_node = KdlNode::new("cwd"); + cwd_node.push(cwd.display().to_string()); + node_children.nodes_mut().push(cwd_node); + } else if let Some(cwd) = run_plugin_or_alias.get_initial_cwd() { + let mut cwd_node = KdlNode::new("cwd"); + cwd_node.push(cwd.display().to_string()); + node_children.nodes_mut().push(cwd_node); + } + if let Some(configuration) = run_plugin_or_alias.get_configuration() { + for (config_key, config_value) in configuration.inner().iter() { + let mut node = KdlNode::new(config_key.clone()); + node.push(config_value.clone()); + node_children.nodes_mut().push(node); + } + } + if !node_children.nodes().is_empty() { + node.set_children(node_children); + } + Some(node) + }, + Action::Copy => Some(KdlNode::new("Copy")), + Action::SearchInput(bytes) => { + let mut node = KdlNode::new("SearchInput"); + for byte in bytes { + node.push(KdlValue::Base10(*byte as i64)); + } + Some(node) + }, + Action::Search(search_direction) => { + let mut node = KdlNode::new("Search"); + let direction = match search_direction { + SearchDirection::Down => "down", + SearchDirection::Up => "up", + }; + node.push(direction); + Some(node) + }, + Action::SearchToggleOption(search_toggle_option) => { + let mut node = KdlNode::new("SearchToggleOption"); + node.push(format!("{:?}", search_toggle_option)); + Some(node) + }, + Action::ToggleMouseMode => Some(KdlNode::new("ToggleMouseMode")), + Action::PreviousSwapLayout => Some(KdlNode::new("PreviousSwapLayout")), + Action::NextSwapLayout => Some(KdlNode::new("NextSwapLayout")), + Action::BreakPane => Some(KdlNode::new("BreakPane")), + Action::BreakPaneRight => Some(KdlNode::new("BreakPaneRight")), + Action::BreakPaneLeft => Some(KdlNode::new("BreakPaneLeft")), + Action::KeybindPipe { + name, + payload, + args, + plugin, + configuration, + launch_new, + skip_cache, + floating, + in_place, + cwd, + pane_title, + } => { + let mut node = KdlNode::new("MessagePlugin"); + let mut node_children = KdlDocument::new(); + if let Some(plugin) = plugin { + node.push(plugin.clone()); + } + if let Some(name) = name { + let mut name_node = KdlNode::new("name"); + name_node.push(name.clone()); + node_children.nodes_mut().push(name_node); + } + if let Some(cwd) = cwd { + let mut cwd_node = KdlNode::new("cwd"); + cwd_node.push(cwd.display().to_string()); + node_children.nodes_mut().push(cwd_node); + } + if let Some(payload) = payload { + let mut payload_node = KdlNode::new("payload"); + payload_node.push(payload.clone()); + node_children.nodes_mut().push(payload_node); + } + if *launch_new { + let mut launch_new_node = KdlNode::new("launch_new"); + launch_new_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(launch_new_node); + } + if *skip_cache { + let mut skip_cache_node = KdlNode::new("skip_cache"); + skip_cache_node.push(KdlValue::Bool(true)); + node_children.nodes_mut().push(skip_cache_node); + } + if let Some(floating) = floating { + let mut floating_node = KdlNode::new("floating"); + floating_node.push(KdlValue::Bool(*floating)); + node_children.nodes_mut().push(floating_node); + } + if let Some(title) = pane_title { + let mut title_node = KdlNode::new("title"); + title_node.push(title.clone()); + node_children.nodes_mut().push(title_node); + } + if let Some(configuration) = configuration { + // we do this because the constructor removes the relevant config fields from + // above, otherwise we would have duplicates + let configuration = PluginUserConfiguration::new(configuration.clone()); + let configuration = configuration.inner(); + for (config_key, config_value) in configuration.iter() { + let mut node = KdlNode::new(config_key.clone()); + node.push(config_value.clone()); + node_children.nodes_mut().push(node); + } + } + if !node_children.nodes().is_empty() { + node.set_children(node_children); + } + Some(node) + }, + _ => None, + } + } } impl TryFrom<(&str, &KdlDocument)> for PaletteColor { @@ -667,6 +1189,23 @@ impl TryFrom<(&str, &KdlDocument)> for PaletteColor { } } +impl PaletteColor { + pub fn to_kdl(&self, color_name: &str) -> KdlNode { + let mut node = KdlNode::new(color_name); + match self { + PaletteColor::Rgb((r, g, b)) => { + node.push(KdlValue::Base10(*r as i64)); + node.push(KdlValue::Base10(*g as i64)); + node.push(KdlValue::Base10(*b as i64)); + }, + PaletteColor::EightBit(color_index) => { + node.push(KdlValue::Base10(*color_index as i64)); + }, + } + node + } +} + impl TryFrom<(&KdlNode, &Options)> for Action { type Error = ConfigError; fn try_from((kdl_action, config_options): (&KdlNode, &Options)) -> Result<Self, Self::Error> { @@ -1654,6 +2193,876 @@ impl Options { let document: KdlDocument = stringified_keybindings.parse()?; Options::from_kdl(&document) } + fn simplified_ui_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// Use a simplified UI without special fonts (arrow glyphs)", + "// Options:", + "// - true", + "// - false (Default)", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("simplified_ui"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(simplified_ui) = self.simplified_ui { + let mut node = create_node(simplified_ui); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(true); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn theme_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}", + " ", + "// Choose the theme that is specified in the themes section.", + "// Default: default", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("theme"); + node.push(node_value.to_owned()); + node + }; + if let Some(theme) = &self.theme { + let mut node = create_node(theme); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("dracula"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn default_mode_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}", + " ", "// Choose the base input mode of zellij.", "// Default: normal", "// " + ); + + let create_node = |default_mode: &InputMode| -> KdlNode { + let mut node = KdlNode::new("default_mode"); + node.push(format!("{:?}", default_mode).to_lowercase()); + node + }; + if let Some(default_mode) = &self.default_mode { + let mut node = create_node(default_mode); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(&InputMode::Locked); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn default_shell_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = + format!("{}\n{}\n{}\n{}", + " ", + "// Choose the path to the default shell that zellij will use for opening new panes", + "// Default: $SHELL", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("default_shell"); + node.push(node_value.to_owned()); + node + }; + if let Some(default_shell) = &self.default_shell { + let mut node = create_node(&default_shell.display().to_string()); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("fish"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn default_cwd_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}", + " ", + "// Choose the path to override cwd that zellij will use for opening new panes", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("default_cwd"); + node.push(node_value.to_owned()); + node + }; + if let Some(default_cwd) = &self.default_cwd { + let mut node = create_node(&default_cwd.display().to_string()); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("/tmp"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn default_layout_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}", + " ", + "// The name of the default layout to load on startup", + "// Default: \"default\"", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("default_layout"); + node.push(node_value.to_owned()); + node + }; + if let Some(default_layout) = &self.default_layout { + let mut node = create_node(&default_layout.display().to_string()); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("compact"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn layout_dir_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}", + " ", "// The folder in which Zellij will look for layouts", "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("layout_dir"); + node.push(node_value.to_owned()); + node + }; + if let Some(layout_dir) = &self.layout_dir { + let mut node = create_node(&layout_dir.display().to_string()); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("/tmp"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn theme_dir_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}", + " ", "// The folder in which Zellij will look for themes", "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("theme_dir"); + node.push(node_value.to_owned()); + node + }; + if let Some(theme_dir) = &self.theme_dir { + let mut node = create_node(&theme_dir.display().to_string()); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("/tmp"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn mouse_mode_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// Toggle enabling the mouse mode.", + "// On certain configurations, or terminals this could", + "// potentially interfere with copying text.", + "// Options:", + "// - true (default)", + "// - false", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("mouse_mode"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(mouse_mode) = self.mouse_mode { + let mut node = create_node(mouse_mode); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn pane_frames_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// Toggle having pane frames around the panes", + "// Options:", + "// - true (default, enabled)", + "// - false", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("pane_frames"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(pane_frames) = self.pane_frames { + let mut node = create_node(pane_frames); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn mirror_session_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// 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", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("mirror_session"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(mirror_session) = self.mirror_session { + let mut node = create_node(mirror_session); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(true); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn on_force_close_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// 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", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("on_force_close"); + node.push(node_value.to_owned()); + node + }; + if let Some(on_force_close) = &self.on_force_close { + let mut node = match on_force_close { + OnForceClose::Detach => create_node("detach"), + OnForceClose::Quit => create_node("quit"), + }; + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("quit"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn scroll_buffer_size_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// 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", + "// ", + ); + + let create_node = |node_value: usize| -> KdlNode { + let mut node = KdlNode::new("scroll_buffer_size"); + node.push(KdlValue::Base10(node_value as i64)); + node + }; + if let Some(scroll_buffer_size) = self.scroll_buffer_size { + let mut node = create_node(scroll_buffer_size); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(10000); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn copy_command_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// 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", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("copy_command"); + node.push(node_value.to_owned()); + node + }; + if let Some(copy_command) = &self.copy_command { + let mut node = create_node(copy_command); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("pbcopy"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn copy_clipboard_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!("{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// 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", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("copy_clipboard"); + node.push(node_value.to_owned()); + node + }; + if let Some(copy_clipboard) = &self.copy_clipboard { + let mut node = match copy_clipboard { + Clipboard::Primary => create_node("primary"), + Clipboard::System => create_node("system"), + }; + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("primary"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn copy_on_select_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}", + " ", + "// Enable automatic copying (and clearing) of selection when releasing mouse", + "// Default: true", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("copy_on_select"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(copy_on_select) = self.copy_on_select { + let mut node = create_node(copy_on_select); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(true); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn scrollback_editor_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}", + " ", + "// Path to the default editor to use to edit pane scrollbuffer", + "// Default: $EDITOR or $VISUAL", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("scrollback_editor"); + node.push(node_value.to_owned()); + node + }; + if let Some(scrollback_editor) = &self.scrollback_editor { + let mut node = create_node(&scrollback_editor.display().to_string()); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("/usr/bin/vim"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn session_name_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// A fixed name to always give the Zellij session.", + "// Consider also setting `attach_to_session true,`", + "// otherwise this will error if such a session exists.", + "// Default: <RANDOM>", + "// ", + ); + + let create_node = |node_value: &str| -> KdlNode { + let mut node = KdlNode::new("session_name"); + node.push(node_value.to_owned()); + node + }; + if let Some(session_name) = &self.session_name { + let mut node = create_node(&session_name); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node("My singleton session"); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn attach_to_session_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}", + " ", + "// When `session_name` is provided, attaches to that session", + "// if it is already running or creates it otherwise.", + "// Default: false", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("attach_to_session"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(attach_to_session) = self.attach_to_session { + let mut node = create_node(attach_to_session); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(true); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn auto_layout_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!("{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible", + "// Options:", + "// - true (default)", + "// - false", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("auto_layout"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(auto_layout) = self.auto_layout { + let mut node = create_node(auto_layout); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn session_serialization_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!("{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected", + "// Options:", + "// - true (default)", + "// - false", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("session_serialization"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(session_serialization) = self.session_serialization { + let mut node = create_node(session_serialization); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn serialize_pane_viewport_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}\n{}", + " ", + "// Whether pane viewports are serialized along with the session, default is false", + "// Options:", + "// - true", + "// - false (default)", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("serialize_pane_viewport"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(serialize_pane_viewport) = self.serialize_pane_viewport { + let mut node = create_node(serialize_pane_viewport); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn scrollback_lines_to_serialize_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!("{}\n{}\n{}\n{}\n{}", + " ", + "// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0", + "// defaults to the scrollback size. If this number is higher than the scrollback size, it will", + "// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true.", + "// ", + ); + + let create_node = |node_value: usize| -> KdlNode { + let mut node = KdlNode::new("scrollback_lines_to_serialize"); + node.push(KdlValue::Base10(node_value as i64)); + node + }; + if let Some(scrollback_lines_to_serialize) = self.scrollback_lines_to_serialize { + let mut node = create_node(scrollback_lines_to_serialize); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(10000); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn styled_underlines_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}\n{}\n{}", + " ", + "// Enable or disable the rendering of styled and colored underlines (undercurl).", + "// May need to be disabled for certain unsupported terminals", + "// Default: true", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("styled_underlines"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(styled_underlines) = self.styled_underlines { + let mut node = create_node(styled_underlines); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn serialization_interval_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!( + "{}\n{}\n{}", + " ", "// How often in seconds sessions are serialized", "// ", + ); + + let create_node = |node_value: u64| -> KdlNode { + let mut node = KdlNode::new("serialization_interval"); + node.push(KdlValue::Base10(node_value as i64)); + node + }; + if let Some(serialization_interval) = self.serialization_interval { + let mut node = create_node(serialization_interval); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(10000); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn disable_session_metadata_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!("{}\n{}\n{}\n{}\n{}", + " ", + "// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know", + "// metadata info on this session)", + "// Default: false", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("disable_session_metadata"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(disable_session_metadata) = self.disable_session_metadata { + let mut node = create_node(disable_session_metadata); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + fn support_kitty_keyboard_protocol_to_kdl(&self, add_comments: bool) -> Option<KdlNode> { + let comment_text = format!("{}\n{}\n{}\n{}", + " ", + "// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it)", + "// Default: true (if the host terminal supports it)", + "// ", + ); + + let create_node = |node_value: bool| -> KdlNode { + let mut node = KdlNode::new("support_kitty_keyboard_protocol"); + node.push(KdlValue::Bool(node_value)); + node + }; + if let Some(support_kitty_keyboard_protocol) = self.support_kitty_keyboard_protocol { + let mut node = create_node(support_kitty_keyboard_protocol); + if add_comments { + node.set_leading(format!("{}\n", comment_text)); + } + Some(node) + } else if add_comments { + let mut node = create_node(false); + node.set_leading(format!("{}\n// ", comment_text)); + Some(node) + } else { + None + } + } + pub fn to_kdl(&self, add_comments: bool) -> Vec<KdlNode> { + let mut nodes = vec![]; + if let Some(simplified_ui_node) = self.simplified_ui_to_kdl(add_comments) { + nodes.push(simplified_ui_node); + } + if let Some(theme_node) = self.theme_to_kdl(add_comments) { + nodes.push(theme_node); + } + if let Some(default_mode) = self.default_mode_to_kdl(add_comments) { + nodes.push(default_mode); + } + if let Some(default_shell) = self.default_shell_to_kdl(add_comments) { + nodes.push(default_shell); + } + if let Some(default_cwd) = self.default_cwd_to_kdl(add_comments) { + nodes.push(default_cwd); + } + if let Some(default_layout) = self.default_layout_to_kdl(add_comments) { + nodes.push(default_layout); + } + if let Some(layout_dir) = self.layout_dir_to_kdl(add_comments) { + nodes.push(layout_dir); + } + if let Some(theme_dir) = self.theme_dir_to_kdl(add_comments) { + nodes.push(theme_dir); + } + if let Some(mouse_mode) = self.mouse_mode_to_kdl(add_comments) { + nodes.push(mouse_mode); + } + if let Some(pane_frames) = self.pane_frames_to_kdl(add_comments) { + nodes.push(pane_frames); + } + if let Some(mirror_session) = self.mirror_session_to_kdl(add_comments) { + nodes.push(mirror_session); + } + if let Some(on_force_close) = self.on_force_close_to_kdl(add_comments) { + nodes.push(on_force_close); + } + if let Some(scroll_buffer_size) = self.scroll_buffer_size_to_kdl(add_comments) { + nodes.push(scroll_buffer_size); + } + if let Some(copy_command) = self.copy_command_to_kdl(add_comments) { + nodes.push(copy_command); + } + if let Some(copy_clipboard) = self.copy_clipboard_to_kdl(add_comments) { + nodes.push(copy_clipboard); + } + if let Some(copy_on_select) = self.copy_on_select_to_kdl(add_comments) { + nodes.push(copy_on_select); + } + if let Some(scrollback_editor) = self.scrollback_editor_to_kdl(add_comments) { + nodes.push(scrollback_editor); + } + if let Some(session_name) = self.session_name_to_kdl(add_comments) { + nodes.push(session_name); + } + if let Some(attach_to_session) = self.attach_to_session_to_kdl(add_comments) { + nodes.push(attach_to_session); + } + if let Some(auto_layout) = self.auto_layout_to_kdl(add_comments) { + nodes.push(auto_layout); + } + if let Some(session_serialization) = self.session_serialization_to_kdl(add_comments) { + nodes.push(session_serialization); + } + if let Some(serialize_pane_viewport) = self.serialize_pane_viewport_to_kdl(add_comments) { + nodes.push(serialize_pane_viewport); + } + if let Some(scrollback_lines_to_serialize) = + self.scrollback_lines_to_serialize_to_kdl(add_comments) + { + nodes.push(scrollback_lines_to_serialize); + } + if let Some(styled_underlines) = self.styled_underlines_to_kdl(add_comments) { + nodes.push(styled_underlines); + } + if let Some(serialization_interval) = self.serialization_interval_to_kdl(add_comments) { + nodes.push(serialization_interval); + } + if let Some(disable_session_metadata) = self.disable_session_metadata_to_kdl(add_comments) { + nodes.push(disable_session_metadata); + } + if let Some(support_kitty_keyboard_protocol) = + self.support_kitty_keyboard_protocol_to_kdl(add_comments) + { + nodes.push(support_kitty_keyboard_protocol); + } + nodes + } } impl Layout { @@ -1744,6 +3153,29 @@ impl EnvironmentVariables { } Ok(EnvironmentVariables::from_data(env)) } + pub fn to_kdl(&self) -> Option<KdlNode> { + let mut has_env_vars = false; + let mut env = KdlNode::new("env"); + let mut env_vars = KdlDocument::new(); + + let mut stable_sorted = BTreeMap::new(); + for (env_var_name, env_var_value) in self.inner() { + stable_sorted.insert(env_var_name, env_var_value); + } + for (env_key, env_value) in stable_sorted { + has_env_vars = true; + let mut variable_key = KdlNode::new(env_key.to_owned()); + variable_key.push(env_value.to_owned()); + env_vars.nodes_mut().push(variable_key); + } + + if has_env_vars { + env.set_children(env_vars); + Some(env) + } else { + None + } + } } impl Keybinds { @@ -1904,6 +3336,184 @@ impl Keybinds { )) } } + // minimize keybind entries for serialization, so that duplicate entries will appear in + // "shared" nodes later rather than once per mode + fn minimize_entries( + &self, + ) -> BTreeMap<BTreeSet<InputMode>, BTreeMap<KeyWithModifier, Vec<Action>>> { + let mut minimized: BTreeMap<BTreeSet<InputMode>, BTreeMap<KeyWithModifier, Vec<Action>>> = + BTreeMap::new(); + let mut flattened: Vec<BTreeMap<KeyWithModifier, Vec<Action>>> = self + .0 + .iter() + .map(|(_input_mode, keybind)| keybind.clone().into_iter().collect()) + .collect(); + for keybind in flattened.drain(..) { + for (key, actions) in keybind.into_iter() { + let mut appears_in_modes: BTreeSet<InputMode> = BTreeSet::new(); + for (input_mode, keybinds) in self.0.iter() { + if keybinds.get(&key) == Some(&actions) { + appears_in_modes.insert(*input_mode); + } + } + minimized + .entry(appears_in_modes) + .or_insert_with(Default::default) + .insert(key, actions); + } + } + minimized + } + fn serialize_mode_title_node(&self, input_modes: &BTreeSet<InputMode>) -> KdlNode { + let all_modes: Vec<InputMode> = InputMode::iter().collect(); + let total_input_mode_count = all_modes.len(); + if input_modes.len() == 1 { + let input_mode_name = + format!("{:?}", input_modes.iter().next().unwrap()).to_lowercase(); + KdlNode::new(input_mode_name) + } else if input_modes.len() == total_input_mode_count { + KdlNode::new("shared") + } else if input_modes.len() < total_input_mode_count / 2 { + let mut node = KdlNode::new("shared_among"); + for input_mode in input_modes { + node.push(format!("{:?}", input_mode).to_lowercase()); + } + node + } else { + let mut node = KdlNode::new("shared_except"); + let mut modes = all_modes.clone(); + for input_mode in input_modes { + modes.retain(|m| m != input_mode) + } + for mode in modes { + node.push(format!("{:?}", mode).to_lowercase()); + } + node + } + } + fn serialize_mode_keybinds( + &self, + keybinds: &BTreeMap<KeyWithModifier, Vec<Action>>, + ) -> KdlDocument { + let mut mode_keybinds = KdlDocument::new(); + for keybind in keybinds { + let mut keybind_node = KdlNode::new("bind"); + keybind_node.push(keybind.0.to_kdl()); + let mut actions = KdlDocument::new(); + let mut actions_have_children = false; + for action in keybind.1 { + if let Some(kdl_action) = action.to_kdl() { + if kdl_action.children().is_some() { + actions_have_children = true; + } + actions.nodes_mut().push(kdl_action); + } + } + if !actions_have_children { + for action in actions.nodes_mut() { + action.set_leading(""); + action.set_trailing("; "); + } + actions.set_leading(" "); + actions.set_trailing(""); + } + keybind_node.set_children(actions); + mode_keybinds.nodes_mut().push(keybind_node); + } + mode_keybinds + } + pub fn to_kdl(&self, should_clear_defaults: bool) -> KdlNode { + let mut keybinds_node = KdlNode::new("keybinds"); + if should_clear_defaults { + keybinds_node.insert("clear-defaults", true); + } + let mut minimized = self.minimize_entries(); + let mut keybinds_children = KdlDocument::new(); + + macro_rules! encode_single_input_mode { + ($mode_name:ident) => {{ + if let Some(keybinds) = minimized.remove(&BTreeSet::from([InputMode::$mode_name])) { + let mut mode_node = + KdlNode::new(format!("{:?}", InputMode::$mode_name).to_lowercase()); + let mode_keybinds = self.serialize_mode_keybinds(&keybinds); + mode_node.set_children(mode_keybinds); + keybinds_children.nodes_mut().push(mode_node); + } + }}; + } + // we do this explicitly so that the sorting order of modes in the config is more Human + // readable - this is actually less code (and clearer) than implementing Ord in this case + encode_single_input_mode!(Normal); + encode_single_input_mode!(Locked); + encode_single_input_mode!(Pane); + encode_single_input_mode!(Tab); + encode_single_input_mode!(Resize); + encode_single_input_mode!(Move); + encode_single_input_mode!(Scroll); + encode_single_input_mode!(Search); + encode_single_input_mode!(Session); + + for (input_modes, keybinds) in minimized { + if input_modes.is_empty() { + log::error!("invalid input mode for keybinds: {:#?}", keybinds); + continue; + } + let mut mode_node = self.serialize_mode_title_node(&input_modes); + let mode_keybinds = self.serialize_mode_keybinds(&keybinds); + mode_node.set_children(mode_keybinds); + keybinds_children.nodes_mut().push(mode_node); + } + keybinds_node.set_children(keybinds_children); + keybinds_node + } +} + +impl KeyWithModifier { + pub fn to_kdl(&self) -> String { + if self.key_modifiers.is_empty() { + self.bare_key.to_kdl() + } else { + format!( + "{} {}", + self.key_modifiers + .iter() + .map(|m| m.to_string()) + .collect::<Vec<_>>() + .join(" "), + self.bare_key.to_kdl() + ) + } + } +} + +impl BareKey { + pub fn to_kdl(&self) -> String { + match self { + BareKey::PageDown => format!("PageDown"), + BareKey::PageUp => format!("PageUp"), + BareKey::Left => format!("left"), + BareKey::Down => format!("down"), + BareKey::Up => format!("up"), + BareKey::Right => format!("right"), + BareKey::Home => format!("home"), + BareKey::End => format!("end"), + BareKey::Backspace => format!("backspace"), + BareKey::Delete => format!("del"), + BareKey::Insert => format!("insert"), + BareKey::F(index) => format!("F{}", index), + BareKey::Char(' ') => format!("space"), + BareKey::Char(character) => format!("{}", character), + BareKey::Tab => format!("tab"), + BareKey::Esc => format!("esc"), + BareKey::Enter => format!("enter"), + BareKey::CapsLock => format!("capslock"), + BareKey::ScrollLock => format!("scrolllock"), + BareKey::NumLock => format!("numlock"), + BareKey::PrintScreen => format!("printscreen"), + BareKey::Pause => format!("pause"), + BareKey::Menu => format!("menu"), + } + } } impl Config { @@ -1920,7 +3530,8 @@ impl Config { config.keybinds = Keybinds::from_kdl(&kdl_keybinds, config.keybinds, &config.options)?; } if let Some(kdl_themes) = kdl_config.get("themes") { - let config_themes = Themes::from_kdl(kdl_themes)?; + let sourced_from_external_file = false; + let config_themes = Themes::from_kdl(kdl_themes, sourced_from_external_file)?; config.themes = config.themes.merge(config_themes); } if let Some(kdl_plugin_aliases) = kdl_config.get("plugins") { @@ -1937,6 +3548,34 @@ impl Config { } Ok(config) } + pub fn to_string(&self, add_comments: bool) -> String { + let mut document = KdlDocument::new(); + + let clear_defaults = true; + let keybinds = self.keybinds.to_kdl(clear_defaults); + document.nodes_mut().push(keybinds); + + if let Some(themes) = self.themes.to_kdl() { + document.nodes_mut().push(themes); + } + + let plugins = self.plugins.to_kdl(); + document.nodes_mut().push(plugins); + + if let Some(ui_config) = self.ui.to_kdl() { + document.nodes_mut().push(ui_config); + } + + if let Some(env) = self.env.to_kdl() { + document.nodes_mut().push(env); + } + + document + .nodes_mut() + .append(&mut self.options.to_kdl(add_comments)); + + document.to_string() + } } impl PluginAliases { @@ -1962,6 +3601,46 @@ impl PluginAliases { } Ok(PluginAliases { aliases }) } + pub fn to_kdl(&self) -> KdlNode { + let mut plugins = KdlNode::new("plugins"); + let mut plugins_children = KdlDocument::new(); + for (alias_name, plugin_alias) in self.aliases.iter() { + let mut plugin_alias_node = KdlNode::new(alias_name.clone()); + let mut plugin_alias_children = KdlDocument::new(); + let location_string = plugin_alias.location.display(); + + plugin_alias_node.insert("location", location_string); + let cwd = plugin_alias.initial_cwd.as_ref(); + let mut has_children = false; + if let Some(cwd) = cwd { + has_children = true; + let mut cwd_node = KdlNode::new("cwd"); + cwd_node.push(cwd.display().to_string()); + plugin_alias_children.nodes_mut().push(cwd_node); + } + let configuration = plugin_alias.configuration.inner(); + if !configuration.is_empty() { + has_children = true; + for (config_key, config_value) in configuration { + let mut node = KdlNode::new(config_key.to_owned()); + if config_value == "true" { + node.push(KdlValue::Bool(true)); + } else if config_value == "false" { + node.push(KdlValue::Bool(false)); + } else { + node.push(config_value.to_string()); + } + plugin_alias_children.nodes_mut().push(node); + } + } + if has_children { + plugin_alias_node.set_children(plugin_alias_children); + } + plugins_children.nodes_mut().push(plugin_alias_node); + } + plugins.set_children(plugins_children); + plugins + } } impl UiConfig { @@ -1981,10 +3660,40 @@ impl UiConfig { } Ok(ui_config) } + pub fn to_kdl(&self) -> Option<KdlNode> { + let mut ui_config = KdlNode::new("ui"); + let mut ui_config_children = KdlDocument::new(); + let mut frame_config = KdlNode::new("pane_frames"); + let mut frame_config_children = KdlDocument::new(); + let mut has_ui_config = false; + if self.pane_frames.rounded_corners { + has_ui_config = true; + let mut rounded_corners = KdlNode::new("rounded_corners"); + rounded_corners.push(KdlValue::Bool(true)); + frame_config_children.nodes_mut().push(rounded_corners); + } + if self.pane_frames.hide_session_name { + has_ui_config = true; + let mut hide_session_name = KdlNode::new("hide_session_name"); + hide_session_name.push(KdlValue::Bool(true)); + frame_config_children.nodes_mut().push(hide_session_name); + } + if has_ui_config { + frame_config.set_children(frame_config_children); + ui_config_children.nodes_mut().push(frame_config); + ui_config.set_children(ui_config_children); + Some(ui_config) + } else { + None + } + } } impl Themes { - pub fn from_kdl(themes_from_kdl: &KdlNode) -> Result<Self, ConfigError> { + pub fn from_kdl( + themes_from_kdl: &KdlNode, + sourced_from_external_file: bool, + ) -> Result<Self, ConfigError> { let mut themes: HashMap<String, Theme> = HashMap::new(); for theme_config in kdl_children_nodes_or_error!(themes_from_kdl, "no themes found") { let theme_name = kdl_name!(theme_config); @@ -2004,6 +3713,7 @@ impl Themes { white: PaletteColor::try_from(("white", theme_colors))?, ..Default::default() }, + sourced_from_external_file, }; themes.insert(theme_name.into(), theme); } @@ -2011,14 +3721,17 @@ impl Themes { Ok(themes) } - pub fn from_string(raw_string: &String) -> Result<Self, ConfigError> { + pub fn from_string( + raw_string: &String, + sourced_from_external_file: bool, + ) -> Result<Self, ConfigError> { let kdl_config: KdlDocument = raw_string.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 all_themes_in_file = Themes::from_kdl(kdl_themes, sourced_from_external_file)?; Ok(all_themes_in_file) } @@ -2026,7 +3739,8 @@ impl Themes { // String is the theme name let kdl_config = std::fs::read_to_string(&path_to_theme_file) .map_err(|e| ConfigError::IoPath(e, path_to_theme_file.clone()))?; - Themes::from_string(&kdl_config).map_err(|e| match e { + let sourced_from_external_file = true; + Themes::from_string(&kdl_config, sourced_from_external_file).map_err(|e| match e { ConfigError::KdlError(kdl_error) => ConfigError::KdlError( kdl_error.add_src(path_to_theme_file.display().to_string(), kdl_config), ), @@ -2049,6 +3763,63 @@ impl Themes { } Ok(themes) } + pub fn to_kdl(&self) -> Option<KdlNode> { + let mut theme_node = KdlNode::new("themes"); + let mut themes = KdlDocument::new(); + let mut has_themes = false; + let sorted_themes: BTreeMap<String, Theme> = self.inner().clone().into_iter().collect(); + for (theme_name, theme) in sorted_themes { + if theme.sourced_from_external_file { + // we do not serialize themes that have been defined in external files so as not to + // clog up the configuration file definitions + continue; + } + has_themes = true; + let mut current_theme_node = KdlNode::new(theme_name.clone()); + let mut current_theme_node_children = KdlDocument::new(); + current_theme_node_children + .nodes_mut() + .push(theme.palette.fg.to_kdl("fg")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.bg.to_kdl("bg")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.red.to_kdl("red")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.green.to_kdl("green")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.yellow.to_kdl("yellow")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.blue.to_kdl("blue")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.magenta.to_kdl("magenta")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.orange.to_kdl("orange")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.cyan.to_kdl("cyan")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.black.to_kdl("black")); + current_theme_node_children + .nodes_mut() + .push(theme.palette.white.to_kdl("white")); + current_theme_node.set_children(current_theme_node_children); + themes.nodes_mut().push(current_theme_node); + } + if has_themes { + theme_node.set_children(themes); + Some(theme_node) + } else { + None + } + } } impl PermissionCache { @@ -2197,7 +3968,7 @@ impl SessionInfo { LayoutInfo::File(name) => (name.clone(), "file"), LayoutInfo::BuiltIn(name) => (name.clone(), "built-in"), LayoutInfo::Url(url) => (url.clone(), "url"), - LayoutInfo::Stringified(stringified) => ("stringified-layout".to_owned(), "N/A"), + LayoutInfo::Stringified(_stringified) => ("stringified-layout".to_owned(), "N/A"), }; let mut layout_node = KdlNode::new(format!("{}", layout_name)); let layout_source = KdlEntry::new_prop("source", layout_source); @@ -2707,3 +4478,879 @@ fn serialize_and_deserialize_session_info_with_data() { assert_eq!(session_info, deserealized); insta::assert_snapshot!(serialized); } + +#[test] +fn keybinds_to_string() { + let fake_config = r#" + keybinds { + normal { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + }"#; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Keybinds::from_kdl( + document.get("keybinds").unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + let clear_defaults = true; + let serialized = Keybinds::to_kdl(&deserialized, clear_defaults); + let deserialized_from_serialized = Keybinds::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("keybinds") + .unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + insta::assert_snapshot!(serialized.to_string()); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); +} + +#[test] +fn keybinds_to_string_without_clearing_defaults() { + let fake_config = r#" + keybinds { + normal { + bind "Ctrl g" { SwitchToMode "Locked"; } + } + }"#; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Keybinds::from_kdl( + document.get("keybinds").unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + let clear_defaults = false; + let serialized = Keybinds::to_kdl(&deserialized, clear_defaults); + let deserialized_from_serialized = Keybinds::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("keybinds") + .unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + insta::assert_snapshot!(serialized.to_string()); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); +} + +#[test] +fn keybinds_to_string_with_multiple_actions() { + let fake_config = r#" + keybinds { + normal { + bind "Ctrl n" { NewPane; SwitchToMode "Locked"; } + } + }"#; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Keybinds::from_kdl( + document.get("keybinds").unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + let clear_defaults = true; + let serialized = Keybinds::to_kdl(&deserialized, clear_defaults); + let deserialized_from_serialized = Keybinds::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("keybinds") + .unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn keybinds_to_string_with_all_actions() { + let fake_config = r#" + keybinds { + normal { + bind "Ctrl a" { Quit; } + bind "Ctrl b" { Write 102 111 111; } + bind "Ctrl c" { WriteChars "hi there!"; } + bind "Ctrl d" { SwitchToMode "Locked"; } + bind "Ctrl e" { Resize "Increase"; } + bind "Ctrl f" { FocusNextPane; } + bind "Ctrl g" { FocusPreviousPane; } + bind "Ctrl h" { SwitchFocus; } + bind "Ctrl i" { MoveFocus "Right"; } + bind "Ctrl j" { MoveFocusOrTab "Right"; } + bind "Ctrl k" { MovePane "Right"; } + bind "Ctrl l" { MovePaneBackwards; } + bind "Ctrl m" { Resize "Decrease Down"; } + bind "Ctrl n" { DumpScreen "/tmp/dumped"; } + bind "Ctrl o" { DumpLayout "/tmp/dumped-layout"; } + bind "Ctrl p" { EditScrollback; } + bind "Ctrl q" { ScrollUp; } + bind "Ctrl r" { ScrollDown; } + bind "Ctrl s" { ScrollToBottom; } + bind "Ctrl t" { ScrollToTop; } + bind "Ctrl u" { PageScrollUp; } + bind "Ctrl v" { PageScrollDown; } + bind "Ctrl w" { HalfPageScrollUp; } + bind "Ctrl x" { HalfPageScrollDown; } + bind "Ctrl y" { ToggleFocusFullscreen; } + bind "Ctrl z" { TogglePaneFrames; } + bind "Alt a" { ToggleActiveSyncTab; } + bind "Alt b" { NewPane "Right"; } + bind "Alt c" { TogglePaneEmbedOrFloating; } + bind "Alt d" { ToggleFloatingPanes; } + bind "Alt e" { CloseFocus; } + bind "Alt f" { PaneNameInput 0; } + bind "Alt g" { UndoRenamePane; } + bind "Alt h" { NewTab; } + bind "Alt i" { GoToNextTab; } + bind "Alt j" { GoToPreviousTab; } + bind "Alt k" { CloseTab; } + bind "Alt l" { GoToTab 1; } + bind "Alt m" { ToggleTab; } + bind "Alt n" { TabNameInput 0; } + bind "Alt o" { UndoRenameTab; } + bind "Alt p" { MoveTab "Right"; } + bind "Alt q" { + Run "ls" "-l" { + hold_on_start true; + hold_on_close false; + cwd "/tmp"; + name "my cool pane"; + }; + } + bind "Alt r" { + Run "ls" "-l" { + hold_on_start true; + hold_on_close false; + cwd "/tmp"; + name "my cool pane"; + floating true; + }; + } + bind "Alt s" { + Run "ls" "-l" { + hold_on_start true; + hold_on_close false; + cwd "/tmp"; + name "my cool pane"; + in_place true; + }; + } + bind "Alt t" { Detach; } + bind "Alt u" { + LaunchOrFocusPlugin "zellij:session-manager"{ + floating true; + move_to_focused_tab true; + skip_plugin_cache true; + config_key_1 "config_value_1"; + config_key_2 "config_value_2"; + }; + } + bind "Alt v" { + LaunchOrFocusPlugin "zellij:session-manager"{ + in_place true; + move_to_focused_tab true; + skip_plugin_cache true; + config_key_1 "config_value_1"; + config_key_2 "config_value_2"; + }; + } + bind "Alt w" { + LaunchPlugin "zellij:session-manager" { + floating true; + skip_plugin_cache true; + config_key_1 "config_value_1"; + config_key_2 "config_value_2"; + }; + } + bind "Alt x" { + LaunchPlugin "zellij:session-manager"{ + in_place true; + skip_plugin_cache true; + config_key_1 "config_value_1"; + config_key_2 "config_value_2"; + }; + } + bind "Alt y" { Copy; } + bind "Alt z" { SearchInput 0; } + bind "Ctrl Alt a" { Search "Up"; } + bind "Ctrl Alt b" { SearchToggleOption "CaseSensitivity"; } + bind "Ctrl Alt c" { ToggleMouseMode; } + bind "Ctrl Alt d" { PreviousSwapLayout; } + bind "Ctrl Alt e" { NextSwapLayout; } + bind "Ctrl Alt g" { BreakPane; } + bind "Ctrl Alt h" { BreakPaneRight; } + bind "Ctrl Alt i" { BreakPaneLeft; } + bind "Ctrl Alt i" { BreakPaneLeft; } + bind "Ctrl Alt j" { + MessagePlugin "zellij:session-manager"{ + name "message_name"; + payload "message_payload"; + cwd "/tmp"; + launch_new true; + skip_cache true; + floating true; + title "plugin_title"; + config_key_1 "config_value_1"; + config_key_2 "config_value_2"; + }; + } + } + }"#; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Keybinds::from_kdl( + document.get("keybinds").unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + let clear_defaults = true; + let serialized = Keybinds::to_kdl(&deserialized, clear_defaults); + let deserialized_from_serialized = Keybinds::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("keybinds") + .unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + // uncomment the below lines for more easily debugging a failed assertion here + // for (input_mode, input_mode_keybinds) in deserialized.0 { + // if let Some(other_input_mode_keybinds) = deserialized_from_serialized.0.get(&input_mode) { + // for (keybind, action) in input_mode_keybinds { + // if let Some(other_action) = other_input_mode_keybinds.get(&keybind) { + // assert_eq!(&action, other_action); + // } else { + // eprintln!("keybind: {:?} not found in other", keybind); + // } + // } + // } + // } + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn keybinds_to_string_with_shared_modes() { + let fake_config = r#" + keybinds { + normal { + bind "Ctrl n" { NewPane; SwitchToMode "Locked"; } + } + locked { + bind "Ctrl n" { NewPane; SwitchToMode "Locked"; } + } + shared_except "locked" "pane" { + bind "Ctrl f" { TogglePaneEmbedOrFloating; } + } + shared_among "locked" "pane" { + bind "Ctrl p" { WriteChars "foo"; } + } + }"#; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Keybinds::from_kdl( + document.get("keybinds").unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + let clear_defaults = true; + let serialized = Keybinds::to_kdl(&deserialized, clear_defaults); + let deserialized_from_serialized = Keybinds::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("keybinds") + .unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn keybinds_to_string_with_multiple_multiline_actions() { + let fake_config = r#" + keybinds { + shared { + bind "Ctrl n" { + NewPane + SwitchToMode "Locked" + MessagePlugin "zellij:session-manager"{ + name "message_name"; + payload "message_payload"; + cwd "/tmp"; + launch_new true; + skip_cache true; + floating true; + title "plugin_title"; + config_key_1 "config_value_1"; + config_key_2 "config_value_2"; + }; + } + } + }"#; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Keybinds::from_kdl( + document.get("keybinds").unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + let clear_defaults = true; + let serialized = Keybinds::to_kdl(&deserialized, clear_defaults); + let deserialized_from_serialized = Keybinds::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("keybinds") + .unwrap(), + Default::default(), + &Default::default(), + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn themes_to_string() { + let fake_config = r#" + 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 + } + }"#; + let document: KdlDocument = fake_config.parse().unwrap(); + let sourced_from_external_file = false; + let deserialized = + Themes::from_kdl(document.get("themes").unwrap(), sourced_from_external_file).unwrap(); + let serialized = Themes::to_kdl(&deserialized).unwrap(); + let deserialized_from_serialized = Themes::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("themes") + .unwrap(), + sourced_from_external_file, + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn themes_to_string_with_hex_definitions() { + let fake_config = r##" + themes { + nord { + fg "#D8DEE9" + bg "#2E3440" + black "#3B4252" + red "#BF616A" + green "#A3BE8C" + yellow "#EBCB8B" + blue "#81A1C1" + magenta "#B48EAD" + cyan "#88C0D0" + white "#E5E9F0" + orange "#D08770" + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let sourced_from_external_file = false; + let deserialized = + Themes::from_kdl(document.get("themes").unwrap(), sourced_from_external_file).unwrap(); + let serialized = Themes::to_kdl(&deserialized).unwrap(); + let deserialized_from_serialized = Themes::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("themes") + .unwrap(), + sourced_from_external_file, + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn themes_to_string_with_eight_bit_definitions() { + let fake_config = r##" + themes { + default { + fg 1 + bg 10 + black 20 + red 30 + green 40 + yellow 50 + blue 60 + magenta 70 + cyan 80 + white 90 + orange 254 + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let sourced_from_external_file = false; + let deserialized = + Themes::from_kdl(document.get("themes").unwrap(), sourced_from_external_file).unwrap(); + let serialized = Themes::to_kdl(&deserialized).unwrap(); + let deserialized_from_serialized = Themes::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("themes") + .unwrap(), + sourced_from_external_file, + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn themes_to_string_with_combined_definitions() { + let fake_config = r##" + themes { + default { + fg 1 + bg 10 + black 20 + red 30 + green 40 + yellow 50 + blue 60 + magenta 70 + cyan 80 + white 255 255 255 + orange "#D08770" + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let sourced_from_external_file = false; + let deserialized = + Themes::from_kdl(document.get("themes").unwrap(), sourced_from_external_file).unwrap(); + let serialized = Themes::to_kdl(&deserialized).unwrap(); + let deserialized_from_serialized = Themes::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("themes") + .unwrap(), + sourced_from_external_file, + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn themes_to_string_with_multiple_theme_definitions() { + let fake_config = r##" + themes { + nord { + fg "#D8DEE9" + bg "#2E3440" + black "#3B4252" + red "#BF616A" + green "#A3BE8C" + yellow "#EBCB8B" + blue "#81A1C1" + magenta "#B48EAD" + cyan "#88C0D0" + white "#E5E9F0" + orange "#D08770" + } + 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 + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let sourced_from_external_file = false; + let deserialized = + Themes::from_kdl(document.get("themes").unwrap(), sourced_from_external_file).unwrap(); + let serialized = Themes::to_kdl(&deserialized).unwrap(); + let deserialized_from_serialized = Themes::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("themes") + .unwrap(), + sourced_from_external_file, + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn plugins_to_string() { + let fake_config = r##" + plugins { + tab-bar location="zellij:tab-bar" + status-bar location="zellij:status-bar" + strider location="zellij:strider" + compact-bar location="zellij:compact-bar" + session-manager location="zellij:session-manager" + welcome-screen location="zellij:session-manager" { + welcome_screen true + } + filepicker location="zellij:strider" { + cwd "/" + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = PluginAliases::from_kdl(document.get("plugins").unwrap()).unwrap(); + let serialized = PluginAliases::to_kdl(&deserialized); + let deserialized_from_serialized = PluginAliases::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("plugins") + .unwrap(), + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn plugins_to_string_with_file_and_web() { + let fake_config = r##" + plugins { + tab-bar location="https://foo.com/plugin.wasm" + filepicker location="file:/path/to/my/plugin.wasm" { + cwd "/" + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = PluginAliases::from_kdl(document.get("plugins").unwrap()).unwrap(); + let serialized = PluginAliases::to_kdl(&deserialized); + let deserialized_from_serialized = PluginAliases::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("plugins") + .unwrap(), + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn ui_config_to_string() { + let fake_config = r##" + ui { + pane_frames { + rounded_corners true + hide_session_name true + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = UiConfig::from_kdl(document.get("ui").unwrap()).unwrap(); + let serialized = UiConfig::to_kdl(&deserialized).unwrap(); + let deserialized_from_serialized = UiConfig::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("ui") + .unwrap(), + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn ui_config_to_string_with_no_ui_config() { + let fake_config = r##" + ui { + pane_frames { + } + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = UiConfig::from_kdl(document.get("ui").unwrap()).unwrap(); + assert_eq!(UiConfig::to_kdl(&deserialized), None); +} + +#[test] +fn env_vars_to_string() { + let fake_config = r##" + env { + foo "bar" + bar "foo" + thing 1 + baz "true" + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = EnvironmentVariables::from_kdl(document.get("env").unwrap()).unwrap(); + let serialized = EnvironmentVariables::to_kdl(&deserialized).unwrap(); + let deserialized_from_serialized = EnvironmentVariables::from_kdl( + serialized + .to_string() + .parse::<KdlDocument>() + .unwrap() + .get("env") + .unwrap(), + ) + .unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(serialized.to_string()); +} + +#[test] +fn env_vars_to_string_with_no_env_vars() { + let fake_config = r##" + env { + }"##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = EnvironmentVariables::from_kdl(document.get("env").unwrap()).unwrap(); + assert_eq!(EnvironmentVariables::to_kdl(&deserialized), None); +} + +#[test] +fn config_options_to_string() { + let fake_config = r##" + simplified_ui true + theme "dracula" + default_mode "locked" + default_shell "fish" + default_cwd "/tmp/foo" + default_layout "compact" + layout_dir "/tmp/layouts" + theme_dir "/tmp/themes" + mouse_mode false + pane_frames false + mirror_session true + on_force_close "quit" + scroll_buffer_size 100 + copy_command "pbcopy" + copy_clipboard "system" + copy_on_select false + scrollback_editor "vim" + session_name "my_cool_session" + attach_to_session false + auto_layout false + session_serialization true + serialize_pane_viewport false + scrollback_lines_to_serialize 1000 + styled_underlines false + serialization_interval 1 + disable_session_metadata true + support_kitty_keyboard_protocol false + "##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Options::from_kdl(&document).unwrap(); + let mut serialized = Options::to_kdl(&deserialized, false); + let mut fake_document = KdlDocument::new(); + fake_document.nodes_mut().append(&mut serialized); + let deserialized_from_serialized = + Options::from_kdl(&fake_document.to_string().parse::<KdlDocument>().unwrap()).unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(fake_document.to_string()); +} + +#[test] +fn config_options_to_string_with_comments() { + let fake_config = r##" + simplified_ui true + theme "dracula" + default_mode "locked" + default_shell "fish" + default_cwd "/tmp/foo" + default_layout "compact" + layout_dir "/tmp/layouts" + theme_dir "/tmp/themes" + mouse_mode false + pane_frames false + mirror_session true + on_force_close "quit" + scroll_buffer_size 100 + copy_command "pbcopy" + copy_clipboard "system" + copy_on_select false + scrollback_editor "vim" + session_name "my_cool_session" + attach_to_session false + auto_layout false + session_serialization true + serialize_pane_viewport false + scrollback_lines_to_serialize 1000 + styled_underlines false + serialization_interval 1 + disable_session_metadata true + support_kitty_keyboard_protocol false + "##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Options::from_kdl(&document).unwrap(); + let mut serialized = Options::to_kdl(&deserialized, true); + let mut fake_document = KdlDocument::new(); + fake_document.nodes_mut().append(&mut serialized); + let deserialized_from_serialized = + Options::from_kdl(&fake_document.to_string().parse::<KdlDocument>().unwrap()).unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(fake_document.to_string()); +} + +#[test] +fn config_options_to_string_without_options() { + let fake_config = r##" + "##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Options::from_kdl(&document).unwrap(); + let mut serialized = Options::to_kdl(&deserialized, false); + let mut fake_document = KdlDocument::new(); + fake_document.nodes_mut().append(&mut serialized); + let deserialized_from_serialized = + Options::from_kdl(&fake_document.to_string().parse::<KdlDocument>().unwrap()).unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(fake_document.to_string()); +} + +#[test] +fn config_options_to_string_with_some_options() { + let fake_config = r##" + default_layout "compact" + "##; + let document: KdlDocument = fake_config.parse().unwrap(); + let deserialized = Options::from_kdl(&document).unwrap(); + let mut serialized = Options::to_kdl(&deserialized, false); + let mut fake_document = KdlDocument::new(); + fake_document.nodes_mut().append(&mut serialized); + let deserialized_from_serialized = + Options::from_kdl(&fake_document.to_string().parse::<KdlDocument>().unwrap()).unwrap(); + assert_eq!( + deserialized, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(fake_document.to_string()); +} + +#[test] +fn bare_config_from_default_assets_to_string() { + let fake_config = Config::from_default_assets().unwrap(); + let fake_config_stringified = fake_config.to_string(false); + let deserialized_from_serialized = Config::from_kdl(&fake_config_stringified, None).unwrap(); + assert_eq!( + fake_config, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(fake_config_stringified); +} + +#[test] +fn bare_config_from_default_assets_to_string_with_comments() { + let fake_config = Config::from_default_assets().unwrap(); + let fake_config_stringified = fake_config.to_string(true); + let deserialized_from_serialized = Config::from_kdl(&fake_config_stringified, None).unwrap(); + assert_eq!( + fake_config, deserialized_from_serialized, + "Deserialized serialized config equals original config" + ); + insta::assert_snapshot!(fake_config_stringified); +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap new file mode 100644 index 00000000..6cd58d55 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap @@ -0,0 +1,240 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 5060 +expression: fake_config_stringified +--- +keybinds clear-defaults=true { + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "left" { MoveFocus "left"; } + bind "down" { MoveFocus "down"; } + bind "up" { MoveFocus "up"; } + bind "right" { MoveFocus "right"; } + bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; } + bind "d" { NewPane "down"; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; } + bind "j" { MoveFocus "down"; } + bind "k" { MoveFocus "up"; } + bind "l" { MoveFocus "right"; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "p" { SwitchFocus; } + bind "Ctrl p" { SwitchToMode "normal"; } + bind "r" { NewPane "right"; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + } + tab { + bind "left" { GoToPreviousTab; } + bind "down" { GoToNextTab; } + bind "up" { GoToPreviousTab; } + bind "right" { GoToNextTab; } + 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 "[" { BreakPaneLeft; SwitchToMode "normal"; } + bind "]" { BreakPaneRight; SwitchToMode "normal"; } + bind "b" { BreakPane; SwitchToMode "normal"; } + bind "h" { GoToPreviousTab; } + bind "j" { GoToNextTab; } + bind "k" { GoToPreviousTab; } + bind "l" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "r" { SwitchToMode "renametab"; TabNameInput 0; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "tab" { ToggleTab; } + } + resize { + bind "left" { Resize "Increase left"; } + bind "down" { Resize "Increase down"; } + bind "up" { Resize "Increase up"; } + bind "right" { Resize "Increase right"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "=" { Resize "Increase"; } + bind "H" { Resize "Decrease left"; } + bind "J" { Resize "Decrease down"; } + bind "K" { Resize "Decrease up"; } + bind "L" { Resize "Decrease right"; } + bind "h" { Resize "Increase left"; } + bind "j" { Resize "Increase down"; } + bind "k" { Resize "Increase up"; } + bind "l" { Resize "Increase right"; } + bind "Ctrl n" { SwitchToMode "normal"; } + } + move { + bind "left" { MovePane "left"; } + bind "down" { MovePane "down"; } + bind "up" { MovePane "up"; } + bind "right" { MovePane "right"; } + bind "h" { MovePane "left"; } + bind "Ctrl h" { SwitchToMode "normal"; } + bind "j" { MovePane "down"; } + bind "k" { MovePane "up"; } + bind "l" { MovePane "right"; } + bind "n" { MovePane; } + bind "p" { MovePaneBackwards; } + bind "tab" { MovePane; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + search { + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "n" { Search "down"; } + bind "o" { SearchToggleOption "WholeWord"; } + bind "p" { Search "up"; } + bind "w" { SearchToggleOption "Wrap"; } + } + session { + bind "c" { + LaunchOrFocusPlugin "configuration" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + bind "Ctrl o" { SwitchToMode "normal"; } + bind "w" { + LaunchOrFocusPlugin "session-manager" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + } + shared_except "locked" { + bind "Alt left" { MoveFocusOrTab "left"; } + bind "Alt down" { MoveFocus "down"; } + bind "Alt up" { MoveFocus "up"; } + bind "Alt right" { MoveFocusOrTab "right"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt [" { PreviousSwapLayout; } + bind "Alt ]" { NextSwapLayout; } + bind "Alt f" { ToggleFloatingPanes; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Alt h" { MoveFocusOrTab "left"; } + bind "Alt i" { MoveTab "left"; } + bind "Alt j" { MoveFocus "down"; } + bind "Alt k" { MoveFocus "up"; } + bind "Alt l" { MoveFocusOrTab "right"; } + bind "Alt n" { NewPane; } + bind "Alt o" { MoveTab "right"; } + bind "Ctrl q" { Quit; } + } + shared_except "locked" "move" { + bind "Ctrl h" { SwitchToMode "move"; } + } + shared_except "locked" "session" { + bind "Ctrl o" { SwitchToMode "session"; } + } + shared_except "locked" "scroll" "search" "tmux" { + bind "Ctrl b" { SwitchToMode "tmux"; } + } + shared_except "locked" "scroll" "search" { + bind "Ctrl s" { SwitchToMode "scroll"; } + } + shared_except "locked" "tab" { + bind "Ctrl t" { SwitchToMode "tab"; } + } + shared_except "locked" "pane" { + bind "Ctrl p" { SwitchToMode "pane"; } + } + shared_except "locked" "resize" { + bind "Ctrl n" { SwitchToMode "resize"; } + } + shared_except "normal" "locked" "entersearch" { + bind "enter" { SwitchToMode "normal"; } + } + shared_except "normal" "locked" "entersearch" "renametab" "renamepane" { + bind "esc" { SwitchToMode "normal"; } + } + shared_among "pane" "tmux" { + bind "x" { CloseFocus; SwitchToMode "normal"; } + } + shared_among "scroll" "search" { + bind "PageDown" { PageScrollDown; } + bind "PageUp" { PageScrollUp; } + bind "left" { PageScrollUp; } + bind "down" { ScrollDown; } + bind "up" { ScrollUp; } + bind "right" { PageScrollDown; } + bind "Ctrl b" { PageScrollUp; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "d" { HalfPageScrollDown; } + bind "Ctrl f" { PageScrollDown; } + bind "h" { PageScrollUp; } + bind "j" { ScrollDown; } + bind "k" { ScrollUp; } + bind "l" { PageScrollDown; } + bind "Ctrl s" { SwitchToMode "normal"; } + bind "u" { HalfPageScrollUp; } + } + entersearch { + bind "Ctrl c" { SwitchToMode "scroll"; } + bind "esc" { SwitchToMode "scroll"; } + bind "enter" { SwitchToMode "search"; } + } + renametab { + bind "esc" { UndoRenameTab; SwitchToMode "tab"; } + } + shared_among "renametab" "renamepane" { + bind "Ctrl c" { SwitchToMode "normal"; } + } + renamepane { + bind "esc" { UndoRenamePane; SwitchToMode "pane"; } + } + shared_among "session" "tmux" { + bind "d" { Detach; } + } + tmux { + bind "left" { MoveFocus "left"; SwitchToMode "normal"; } + bind "down" { MoveFocus "down"; SwitchToMode "normal"; } + bind "up" { MoveFocus "up"; SwitchToMode "normal"; } + bind "right" { MoveFocus "right"; SwitchToMode "normal"; } + bind "space" { NextSwapLayout; } + bind "\"" { NewPane "down"; SwitchToMode "normal"; } + bind "%" { NewPane "right"; SwitchToMode "normal"; } + bind "," { SwitchToMode "renametab"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; SwitchToMode "normal"; } + bind "j" { MoveFocus "down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "up"; SwitchToMode "normal"; } + bind "l" { MoveFocus "right"; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "o" { FocusNextPane; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + } +} +plugins { + compact-bar location="zellij:compact-bar" + configuration location="zellij:configuration" + filepicker location="zellij:strider" { + cwd "/" + } + session-manager location="zellij:session-manager" + status-bar location="zellij:status-bar" + strider location="zellij:strider" + tab-bar location="zellij:tab-bar" + welcome-screen location="zellij:session-manager" { + welcome_screen true + } +} + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap new file mode 100644 index 00000000..443f1017 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap @@ -0,0 +1,409 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 5069 +expression: fake_config_stringified +--- +keybinds clear-defaults=true { + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "left" { MoveFocus "left"; } + bind "down" { MoveFocus "down"; } + bind "up" { MoveFocus "up"; } + bind "right" { MoveFocus "right"; } + bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; } + bind "d" { NewPane "down"; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; } + bind "j" { MoveFocus "down"; } + bind "k" { MoveFocus "up"; } + bind "l" { MoveFocus "right"; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "p" { SwitchFocus; } + bind "Ctrl p" { SwitchToMode "normal"; } + bind "r" { NewPane "right"; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + } + tab { + bind "left" { GoToPreviousTab; } + bind "down" { GoToNextTab; } + bind "up" { GoToPreviousTab; } + bind "right" { GoToNextTab; } + 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 "[" { BreakPaneLeft; SwitchToMode "normal"; } + bind "]" { BreakPaneRight; SwitchToMode "normal"; } + bind "b" { BreakPane; SwitchToMode "normal"; } + bind "h" { GoToPreviousTab; } + bind "j" { GoToNextTab; } + bind "k" { GoToPreviousTab; } + bind "l" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "r" { SwitchToMode "renametab"; TabNameInput 0; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "tab" { ToggleTab; } + } + resize { + bind "left" { Resize "Increase left"; } + bind "down" { Resize "Increase down"; } + bind "up" { Resize "Increase up"; } + bind "right" { Resize "Increase right"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "=" { Resize "Increase"; } + bind "H" { Resize "Decrease left"; } + bind "J" { Resize "Decrease down"; } + bind "K" { Resize "Decrease up"; } + bind "L" { Resize "Decrease right"; } + bind "h" { Resize "Increase left"; } + bind "j" { Resize "Increase down"; } + bind "k" { Resize "Increase up"; } + bind "l" { Resize "Increase right"; } + bind "Ctrl n" { SwitchToMode "normal"; } + } + move { + bind "left" { MovePane "left"; } + bind "down" { MovePane "down"; } + bind "up" { MovePane "up"; } + bind "right" { MovePane "right"; } + bind "h" { MovePane "left"; } + bind "Ctrl h" { SwitchToMode "normal"; } + bind "j" { MovePane "down"; } + bind "k" { MovePane "up"; } + bind "l" { MovePane "right"; } + bind "n" { MovePane; } + bind "p" { MovePaneBackwards; } + bind "tab" { MovePane; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + search { + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "n" { Search "down"; } + bind "o" { SearchToggleOption "WholeWord"; } + bind "p" { Search "up"; } + bind "w" { SearchToggleOption "Wrap"; } + } + session { + bind "c" { + LaunchOrFocusPlugin "configuration" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + bind "Ctrl o" { SwitchToMode "normal"; } + bind "w" { + LaunchOrFocusPlugin "session-manager" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + } + shared_except "locked" { + bind "Alt left" { MoveFocusOrTab "left"; } + bind "Alt down" { MoveFocus "down"; } + bind "Alt up" { MoveFocus "up"; } + bind "Alt right" { MoveFocusOrTab "right"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt [" { PreviousSwapLayout; } + bind "Alt ]" { NextSwapLayout; } + bind "Alt f" { ToggleFloatingPanes; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Alt h" { MoveFocusOrTab "left"; } + bind "Alt i" { MoveTab "left"; } + bind "Alt j" { MoveFocus "down"; } + bind "Alt k" { MoveFocus "up"; } + bind "Alt l" { MoveFocusOrTab "right"; } + bind "Alt n" { NewPane; } + bind "Alt o" { MoveTab "right"; } + bind "Ctrl q" { Quit; } + } + shared_except "locked" "move" { + bind "Ctrl h" { SwitchToMode "move"; } + } + shared_except "locked" "session" { + bind "Ctrl o" { SwitchToMode "session"; } + } + shared_except "locked" "scroll" "search" "tmux" { + bind "Ctrl b" { SwitchToMode "tmux"; } + } + shared_except "locked" "scroll" "search" { + bind "Ctrl s" { SwitchToMode "scroll"; } + } + shared_except "locked" "tab" { + bind "Ctrl t" { SwitchToMode "tab"; } + } + shared_except "locked" "pane" { + bind "Ctrl p" { SwitchToMode "pane"; } + } + shared_except "locked" "resize" { + bind "Ctrl n" { SwitchToMode "resize"; } + } + shared_except "normal" "locked" "entersearch" { + bind "enter" { SwitchToMode "normal"; } + } + shared_except "normal" "locked" "entersearch" "renametab" "renamepane" { + bind "esc" { SwitchToMode "normal"; } + } + shared_among "pane" "tmux" { + bind "x" { CloseFocus; SwitchToMode "normal"; } + } + shared_among "scroll" "search" { + bind "PageDown" { PageScrollDown; } + bind "PageUp" { PageScrollUp; } + bind "left" { PageScrollUp; } + bind "down" { ScrollDown; } + bind "up" { ScrollUp; } + bind "right" { PageScrollDown; } + bind "Ctrl b" { PageScrollUp; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "d" { HalfPageScrollDown; } + bind "Ctrl f" { PageScrollDown; } + bind "h" { PageScrollUp; } + bind "j" { ScrollDown; } + bind "k" { ScrollUp; } + bind "l" { PageScrollDown; } + bind "Ctrl s" { SwitchToMode "normal"; } + bind "u" { HalfPageScrollUp; } + } + entersearch { + bind "Ctrl c" { SwitchToMode "scroll"; } + bind "esc" { SwitchToMode "scroll"; } + bind "enter" { SwitchToMode "search"; } + } + renametab { + bind "esc" { UndoRenameTab; SwitchToMode "tab"; } + } + shared_among "renametab" "renamepane" { + bind "Ctrl c" { SwitchToMode "normal"; } + } + renamepane { + bind "esc" { UndoRenamePane; SwitchToMode "pane"; } + } + shared_among "session" "tmux" { + bind "d" { Detach; } + } + tmux { + bind "left" { MoveFocus "left"; SwitchToMode "normal"; } + bind "down" { MoveFocus "down"; SwitchToMode "normal"; } + bind "up" { MoveFocus "up"; SwitchToMode "normal"; } + bind "right" { MoveFocus "right"; SwitchToMode "normal"; } + bind "space" { NextSwapLayout; } + bind "\"" { NewPane "down"; SwitchToMode "normal"; } + bind "%" { NewPane "right"; SwitchToMode "normal"; } + bind "," { SwitchToMode "renametab"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; SwitchToMode "normal"; } + bind "j" { MoveFocus "down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "up"; SwitchToMode "normal"; } + bind "l" { MoveFocus "right"; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "o" { FocusNextPane; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + } +} +plugins { + compact-bar location="zellij:compact-bar" + configuration location="zellij:configuration" + filepicker location="zellij:strider" { + cwd "/" + } + session-manager location="zellij:session-manager" + status-bar location="zellij:status-bar" + strider location="zellij:strider" + tab-bar location="zellij:tab-bar" + welcome-screen location="zellij:session-manager" { + welcome_screen true + } +} + +// Use a simplified UI without special fonts (arrow glyphs) +// Options: +// - true +// - false (Default) +// +// simplified_ui true + +// Choose the theme that is specified in the themes section. +// Default: default +// +// theme "dracula" + +// Choose the base input mode of zellij. +// Default: normal +// +// default_mode "locked" + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +// default_shell "fish" + +// Choose the path to override cwd that zellij will use for opening new panes +// +// default_cwd "/tmp" + +// The name of the default layout to load on startup +// Default: "default" +// +// default_layout "compact" + +// The folder in which Zellij will look for layouts +// +// layout_dir "/tmp" + +// The folder in which Zellij will look for themes +// +// theme_dir "/tmp" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +// mouse_mode false + +// Toggle having pane frames around the panes +// Options: +// - true (default, enabled) +// - false +// +// pane_frames false + +// 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 + +// 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" + +// 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 automatic copying (and clearing) 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/vim" + +// A fixed name to always give the Zellij session. +// Consider also setting `attach_to_session true,` +// otherwise this will error if such a session exists. +// Default: <RANDOM> +// +// session_name "My singleton session" + +// When `session_name` is provided, attaches to that session +// if it is already running or creates it otherwise. +// Default: false +// +// attach_to_session true + +// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible +// Options: +// - true (default) +// - false +// +// auto_layout false + +// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected +// Options: +// - true (default) +// - false +// +// session_serialization false + +// Whether pane viewports are serialized along with the session, default is false +// Options: +// - true +// - false (default) +// +// serialize_pane_viewport false + +// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0 +// defaults to the scrollback size. If this number is higher than the scrollback size, it will +// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true. +// +// scrollback_lines_to_serialize 10000 + +// Enable or disable the rendering of styled and colored underlines (undercurl). +// May need to be disabled for certain unsupported terminals +// Default: true +// +// styled_underlines false + +// How often in seconds sessions are serialized +// +// serialization_interval 10000 + +// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know +// metadata info on this session) +// Default: false +// +// disable_session_metadata false + +// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it) +// Default: true (if the host terminal supports it) +// +// support_kitty_keyboard_protocol false + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string.snap new file mode 100644 index 00000000..e7f95a87 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string.snap @@ -0,0 +1,33 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 4182 +expression: fake_document.to_string() +--- +simplified_ui true +theme "dracula" +default_mode "locked" +default_shell "fish" +default_cwd "/tmp/foo" +default_layout "compact" +layout_dir "/tmp/layouts" +theme_dir "/tmp/themes" +mouse_mode false +pane_frames false +mirror_session true +on_force_close "quit" +scroll_buffer_size 100 +copy_command "pbcopy" +copy_clipboard "system" +copy_on_select false +scrollback_editor "vim" +session_name "my_cool_session" +attach_to_session false +auto_layout false +session_serialization true +serialize_pane_viewport false +scrollback_lines_to_serialize 1000 +styled_underlines false +serialization_interval 1 +disable_session_metadata true +support_kitty_keyboard_protocol false + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_with_comments.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_with_comments.snap new file mode 100644 index 00000000..3d0736e0 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_with_comments.snap @@ -0,0 +1,175 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 4987 +expression: fake_document.to_string() +--- + +// Use a simplified UI without special fonts (arrow glyphs) +// Options: +// - true +// - false (Default) +// +simplified_ui true + +// Choose the theme that is specified in the themes section. +// Default: default +// +theme "dracula" + +// Choose the base input mode of zellij. +// Default: normal +// +default_mode "locked" + +// Choose the path to the default shell that zellij will use for opening new panes +// Default: $SHELL +// +default_shell "fish" + +// Choose the path to override cwd that zellij will use for opening new panes +// +default_cwd "/tmp/foo" + +// The name of the default layout to load on startup +// Default: "default" +// +default_layout "compact" + +// The folder in which Zellij will look for layouts +// +layout_dir "/tmp/layouts" + +// The folder in which Zellij will look for themes +// +theme_dir "/tmp/themes" + +// Toggle enabling the mouse mode. +// On certain configurations, or terminals this could +// potentially interfere with copying text. +// Options: +// - true (default) +// - false +// +mouse_mode false + +// Toggle having pane frames around the panes +// Options: +// - true (default, enabled) +// - false +// +pane_frames false + +// 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 + +// 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" + +// 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 100 + +// 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 "system" + +// Enable automatic copying (and clearing) 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 "vim" + +// A fixed name to always give the Zellij session. +// Consider also setting `attach_to_session true,` +// otherwise this will error if such a session exists. +// Default: <RANDOM> +// +session_name "my_cool_session" + +// When `session_name` is provided, attaches to that session +// if it is already running or creates it otherwise. +// Default: false +// +attach_to_session false + +// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible +// Options: +// - true (default) +// - false +// +auto_layout false + +// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected +// Options: +// - true (default) +// - false +// +session_serialization true + +// Whether pane viewports are serialized along with the session, default is false +// Options: +// - true +// - false (default) +// +serialize_pane_viewport false + +// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0 +// defaults to the scrollback size. If this number is higher than the scrollback size, it will +// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true. +// +scrollback_lines_to_serialize 1000 + +// Enable or disable the rendering of styled and colored underlines (undercurl). +// May need to be disabled for certain unsupported terminals +// Default: true +// +styled_underlines false + +// How often in seconds sessions are serialized +// +serialization_interval 1 + +// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know +// metadata info on this session) +// Default: false +// +disable_session_metadata true + +// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it) +// Default: true (if the host terminal supports it) +// +support_kitty_keyboard_protocol false + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_with_some_options.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_with_some_options.snap new file mode 100644 index 00000000..2cf4ba5b --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_with_some_options.snap @@ -0,0 +1,7 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 4211 +expression: fake_document.to_string() +--- +default_layout "compact" + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_without_options.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_without_options.snap new file mode 100644 index 00000000..82eaf8e5 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__config_options_to_string_without_options.snap @@ -0,0 +1,6 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 4196 +expression: fake_document.to_string() +--- + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__env_vars_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__env_vars_to_string.snap new file mode 100644 index 00000000..609ed896 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__env_vars_to_string.snap @@ -0,0 +1,11 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3981 +expression: serialized.to_string() +--- +env { + bar "foo" + baz "true" + foo "bar" + thing "1" +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string.snap new file mode 100644 index 00000000..3055ea87 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string.snap @@ -0,0 +1,11 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 2558 +expression: serialized.to_string() +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + } +} + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_all_actions.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_all_actions.snap new file mode 100644 index 00000000..43e85faa --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_all_actions.snap @@ -0,0 +1,130 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 2731 +expression: serialized.to_string() +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl a" { Quit; } + bind "Ctrl Alt a" { Search "up"; } + bind "Alt a" { ToggleActiveSyncTab; } + bind "Ctrl b" { Write 102 111 111; } + bind "Ctrl Alt b" { SearchToggleOption "CaseSensitivity"; } + bind "Alt b" { NewPane "right"; } + bind "Ctrl c" { WriteChars "hi there!"; } + bind "Ctrl Alt c" { ToggleMouseMode; } + bind "Alt c" { TogglePaneEmbedOrFloating; } + bind "Ctrl d" { SwitchToMode "locked"; } + bind "Ctrl Alt d" { PreviousSwapLayout; } + bind "Alt d" { ToggleFloatingPanes; } + bind "Ctrl e" { Resize "Increase"; } + bind "Ctrl Alt e" { NextSwapLayout; } + bind "Alt e" { CloseFocus; } + bind "Ctrl f" { FocusNextPane; } + bind "Alt f" { PaneNameInput 0; } + bind "Ctrl g" { FocusPreviousPane; } + bind "Ctrl Alt g" { BreakPane; } + bind "Alt g" { UndoRenamePane; } + bind "Ctrl h" { SwitchFocus; } + bind "Ctrl Alt h" { BreakPaneRight; } + bind "Alt h" { NewTab; } + bind "Ctrl i" { MoveFocus "right"; } + bind "Ctrl Alt i" { BreakPaneLeft; } + bind "Alt i" { GoToNextTab; } + bind "Ctrl j" { MoveFocusOrTab "right"; } + bind "Ctrl Alt j" { + MessagePlugin "zellij:session-manager" { + name "message_name" + cwd "/tmp" + payload "message_payload" + launch_new true + skip_cache true + floating true + title "plugin_title" + config_key_1 "config_value_1" + config_key_2 "config_value_2" + } + } + bind "Alt j" { GoToPreviousTab; } + bind "Ctrl k" { MovePane "right"; } + bind "Alt k" { CloseTab; } + bind "Ctrl l" { MovePaneBackwards; } + bind "Alt l" { GoToTab 1; } + bind "Ctrl m" { Resize "Decrease down"; } + bind "Alt m" { ToggleTab; } + bind "Ctrl n" { DumpScreen "/tmp/dumped"; } + bind "Alt n" { TabNameInput 0; } + bind "Ctrl o" { DumpLayout; } + bind "Alt o" { UndoRenameTab; } + bind "Ctrl p" { EditScrollback; } + bind "Alt p" { MoveTab "right"; } + bind "Ctrl q" { ScrollUp; } + bind "Alt q" { + Run "ls" "-l" { + cwd "/tmp" + name "my cool pane" + } + } + bind "Ctrl r" { ScrollDown; } + bind "Alt r" { + Run "ls" "-l" { + floating true + cwd "/tmp" + name "my cool pane" + } + } + bind "Ctrl s" { ScrollToBottom; } + bind "Alt s" { + Run "ls" "-l" { + in_place true + cwd "/tmp" + name "my cool pane" + } + } + bind "Ctrl t" { ScrollToTop; } + bind "Alt t" { Detach; } + bind "Ctrl u" { PageScrollUp; } + bind "Alt u" { + LaunchOrFocusPlugin "zellij:session-manager" { + floating true + move_to_focused_tab true + skip_plugin_cache true + config_key_1 "config_value_1" + config_key_2 "config_value_2" + } + } + bind "Ctrl v" { PageScrollDown; } + bind "Alt v" { + LaunchOrFocusPlugin "zellij:session-manager" { + move_to_focused_tab true + in_place true + skip_plugin_cache true + config_key_1 "config_value_1" + config_key_2 "config_value_2" + } + } + bind "Ctrl w" { HalfPageScrollUp; } + bind "Alt w" { + LaunchPlugin "zellij:session-manager" { + floating true + skip_plugin_cache true + config_key_1 "config_value_1" + config_key_2 "config_value_2" + } + } + bind "Ctrl x" { HalfPageScrollDown; } + bind "Alt x" { + LaunchPlugin "zellij:session-manager" { + in_place true + skip_plugin_cache true + config_key_1 "config_value_1" + config_key_2 "config_value_2" + } + } + bind "Ctrl y" { ToggleFocusFullscreen; } + bind "Alt y" { Copy; } + bind "Ctrl z" { TogglePaneFrames; } + bind "Alt z" { SearchInput 0; } + } +} + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_multiple_actions.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_multiple_actions.snap new file mode 100644 index 00000000..ddaa4c0d --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_multiple_actions.snap @@ -0,0 +1,11 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 2576 +expression: serialized.to_string() +--- +keybinds clear-defaults=true { + normal { + bind "Ctrl n" { NewPane; SwitchToMode "locked"; } + } +} + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_multiple_multiline_actions.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_multiple_multiline_actions.snap new file mode 100644 index 00000000..d6a1792c --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_multiple_multiline_actions.snap @@ -0,0 +1,25 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 2788 +expression: serialized.to_string() +--- +keybinds clear-defaults=true { + shared { + bind "Ctrl n" { + NewPane + SwitchToMode "locked" + MessagePlugin "zellij:session-manager" { + name "message_name" + cwd "/tmp" + payload "message_payload" + launch_new true + skip_cache true + floating true + title "plugin_title" + config_key_1 "config_value_1" + config_key_2 "config_value_2" + } + } + } +} + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_shared_modes.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_shared_modes.snap new file mode 100644 index 00000000..d7ca3ad2 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_with_shared_modes.snap @@ -0,0 +1,17 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 2757 +expression: serialized.to_string() +--- +keybinds clear-defaults=true { + shared_among "normal" "locked" { + bind "Ctrl n" { NewPane; SwitchToMode "locked"; } + } + shared_except "locked" "pane" { + bind "Ctrl f" { TogglePaneEmbedOrFloating; } + } + shared_among "locked" "pane" { + bind "Ctrl p" { WriteChars "foo"; } + } +} + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_without_clearing_defaults.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_without_clearing_defaults.snap new file mode 100644 index 00000000..143bb1ef --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__keybinds_to_string_without_clearing_defaults.snap @@ -0,0 +1,11 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 2575 +expression: serialized.to_string() +--- +keybinds { + normal { + bind "Ctrl g" { SwitchToMode "locked"; } + } +} + diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__plugins_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__plugins_to_string.snap new file mode 100644 index 00000000..694f2c15 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__plugins_to_string.snap @@ -0,0 +1,18 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3874 +expression: serialized.to_string() +--- +plugins { + compact-bar location="zellij:compact-bar" + filepicker location="zellij:strider" { + cwd "/" + } + session-manager location="zellij:session-manager" + status-bar location="zellij:status-bar" + strider location="zellij:strider" + tab-bar location="zellij:tab-bar" + welcome-screen location="zellij:session-manager" { + welcome_screen true + } +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__plugins_to_string_with_file_and_web.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__plugins_to_string_with_file_and_web.snap new file mode 100644 index 00000000..4f998225 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__plugins_to_string_with_file_and_web.snap @@ -0,0 +1,11 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3891 +expression: serialized.to_string() +--- +plugins { + filepicker location="file:/path/to/my/plugin.wasm" { + cwd "/" + } + tab-bar location="https://foo.com/plugin.wasm" +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string.snap new file mode 100644 index 00000000..7bbc19cd --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string.snap @@ -0,0 +1,20 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3697 +expression: serialized.to_string() +--- +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 + } +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_combined_definitions.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_combined_definitions.snap new file mode 100644 index 00000000..3498af78 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_combined_definitions.snap @@ -0,0 +1,20 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3775 +expression: serialized.to_string() +--- +themes { + default { + fg 1 + bg 10 + red 30 + green 40 + yellow 50 + blue 60 + magenta 70 + orange 208 135 112 + cyan 80 + black 20 + white 255 255 255 + } +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_eight_bit_definitions.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_eight_bit_definitions.snap new file mode 100644 index 00000000..5406cbb8 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_eight_bit_definitions.snap @@ -0,0 +1,20 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3749 +expression: serialized.to_string() +--- +themes { + default { + fg 1 + bg 10 + red 30 + green 40 + yellow 50 + blue 60 + magenta 70 + orange 254 + cyan 80 + black 20 + white 90 + } +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_hex_definitions.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_hex_definitions.snap new file mode 100644 index 00000000..3cbf559a --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_hex_definitions.snap @@ -0,0 +1,20 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3723 +expression: serialized.to_string() +--- +themes { + nord { + fg 216 222 233 + bg 46 52 64 + red 191 97 106 + green 163 190 140 + yellow 235 203 139 + blue 129 161 193 + magenta 180 142 173 + orange 208 135 112 + cyan 136 192 208 + black 59 66 82 + white 229 233 240 + } +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_multiple_theme_definitions.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_multiple_theme_definitions.snap new file mode 100644 index 00000000..f8d7d38b --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__themes_to_string_with_multiple_theme_definitions.snap @@ -0,0 +1,33 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 4821 +expression: serialized.to_string() +--- +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 216 222 233 + bg 46 52 64 + red 191 97 106 + green 163 190 140 + yellow 235 203 139 + blue 129 161 193 + magenta 180 142 173 + orange 208 135 112 + cyan 136 192 208 + black 59 66 82 + white 229 233 240 + } +} diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__ui_config_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__ui_config_to_string.snap new file mode 100644 index 00000000..5956ba92 --- /dev/null +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__ui_config_to_string.snap @@ -0,0 +1,11 @@ +--- +source: zellij-utils/src/kdl/mod.rs +assertion_line: 3932 +expression: serialized.to_string() +--- +ui { + pane_frames { + rounded_corners true + hide_session_name true + } +} |
