From cd0b0119a022926e659d941f3013b618164e6881 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Thu, 26 Aug 2021 15:06:59 +0200 Subject: [PATCH] Split tab-layout into `template` & `tabs` section * adjust example layouts and move them from `./example` to `./example/layouts` * simplify the deserialization of the layout * layouts are now constructed as follows: ``` --- template: direction: Horizontal parts: - direction: Vertical borderless: true split_size: Fixed: 1 run: plugin: tab-bar - direction: Vertical body: true # <== The body section specifies the position of the # inserted tab - direction: Vertical borderless: true split_size: Fixed: 2 run: plugin: status-bar tabs: - direction: Vertical - direction: Vertical ``` --- example/layouts/multiple_tabs_layout.yaml | 87 ++++ .../multiple_tabs_layout_htop_command.yaml | 90 ++++ example/layouts/run_htop_layout.yaml | 21 + .../layouts/run_htop_layout_with_plugins.yaml | 33 ++ example/multiple_tabs_layout.yaml | 82 ---- .../multiple_tabs_layout_htop_command.yaml | 85 ---- example/run_htop_layout.yaml | 20 - example/run_htop_layout_with_plugins.yaml | 30 -- nonexistent.yaml | 2 + zellij-client/src/lib.rs | 6 +- zellij-server/src/lib.rs | 9 +- zellij-server/src/pty.rs | 8 +- zellij-utils/src/input/layout.rs | 238 ++++------- .../layouts/deeply-nested-tab-layout.yaml | 2 - .../layouts/no-layout-template-specified.yaml | 6 + .../layouts/no-tab-section-specified.yaml | 6 + zellij-utils/src/input/unit/layout_test.rs | 383 ++++++++---------- zellij-utils/src/ipc.rs | 4 +- zellij-utils/src/setup.rs | 8 +- 19 files changed, 507 insertions(+), 613 deletions(-) create mode 100644 example/layouts/multiple_tabs_layout.yaml create mode 100644 example/layouts/multiple_tabs_layout_htop_command.yaml create mode 100644 example/layouts/run_htop_layout.yaml create mode 100644 example/layouts/run_htop_layout_with_plugins.yaml delete mode 100644 example/multiple_tabs_layout.yaml delete mode 100644 example/multiple_tabs_layout_htop_command.yaml delete mode 100644 example/run_htop_layout.yaml delete mode 100644 example/run_htop_layout_with_plugins.yaml create mode 100644 nonexistent.yaml create mode 100644 zellij-utils/src/input/unit/fixtures/layouts/no-layout-template-specified.yaml create mode 100644 zellij-utils/src/input/unit/fixtures/layouts/no-tab-section-specified.yaml diff --git a/example/layouts/multiple_tabs_layout.yaml b/example/layouts/multiple_tabs_layout.yaml new file mode 100644 index 00000000..cba76b88 --- /dev/null +++ b/example/layouts/multiple_tabs_layout.yaml @@ -0,0 +1,87 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: tab-bar + borderless: true + - direction: Vertical + body: true + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: status-bar + borderless: true + +tabs: +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Horizontal + split_size: + Percent: 50 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical +- direction: Vertical +- direction: Vertical +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 20 + run: + plugin: strider + - direction: Horizontal + split_size: + Percent: 80 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 40 + - direction: Horizontal + split_size: + Percent: 60 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 diff --git a/example/layouts/multiple_tabs_layout_htop_command.yaml b/example/layouts/multiple_tabs_layout_htop_command.yaml new file mode 100644 index 00000000..13901c13 --- /dev/null +++ b/example/layouts/multiple_tabs_layout_htop_command.yaml @@ -0,0 +1,90 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: tab-bar + borderless: true + - direction: Vertical + body: true + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: status-bar + borderless: true + +tabs: +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop} + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Horizontal + split_size: + Percent: 50 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical +- direction: Vertical + run: + command: {cmd: htop, args: ["-C"]} +- direction: Vertical +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 20 + run: + plugin: strider + - direction: Horizontal + split_size: + Percent: 80 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 +- direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 40 + - direction: Horizontal + split_size: + Percent: 60 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 diff --git a/example/layouts/run_htop_layout.yaml b/example/layouts/run_htop_layout.yaml new file mode 100644 index 00000000..91f4f63c --- /dev/null +++ b/example/layouts/run_htop_layout.yaml @@ -0,0 +1,21 @@ +--- +tabs: + - direction: Vertical + parts: + - direction: Horizontal + split_size: + Percent: 50 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop} + - direction: Horizontal + split_size: + Percent: 50 + run: + command: {cmd: htop} diff --git a/example/layouts/run_htop_layout_with_plugins.yaml b/example/layouts/run_htop_layout_with_plugins.yaml new file mode 100644 index 00000000..2868cba5 --- /dev/null +++ b/example/layouts/run_htop_layout_with_plugins.yaml @@ -0,0 +1,33 @@ +--- +tabs: + - direction: Horizontal + parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: tab-bar + borderless: true + - direction: Vertical + parts: + - direction: Vertical + parts: + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop} + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop, args: ["-C"]} + - direction: Vertical + split_size: + Fixed: 5 + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: status-bar + borderless: true diff --git a/example/multiple_tabs_layout.yaml b/example/multiple_tabs_layout.yaml deleted file mode 100644 index 6c4d1598..00000000 --- a/example/multiple_tabs_layout.yaml +++ /dev/null @@ -1,82 +0,0 @@ ---- -direction: Horizontal -parts: - - direction: Vertical - split_size: - Fixed: 1 - run: - plugin: tab-bar - - direction: Vertical - tabs: - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Horizontal - split_size: - Percent: 50 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - - direction: Vertical - - direction: Vertical - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 20 - run: - plugin: strider - - direction: Horizontal - split_size: - Percent: 80 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 40 - - direction: Horizontal - split_size: - Percent: 60 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Fixed: 2 - run: - plugin: status-bar diff --git a/example/multiple_tabs_layout_htop_command.yaml b/example/multiple_tabs_layout_htop_command.yaml deleted file mode 100644 index 6739eba8..00000000 --- a/example/multiple_tabs_layout_htop_command.yaml +++ /dev/null @@ -1,85 +0,0 @@ ---- -direction: Horizontal -parts: - - direction: Vertical - split_size: - Fixed: 1 - run: - plugin: tab-bar - - direction: Vertical - tabs: - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 50 - run: - command: {cmd: htop} - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Horizontal - split_size: - Percent: 50 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - - direction: Vertical - run: - command: {cmd: htop, args: ["-C"]} - - direction: Vertical - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 20 - run: - plugin: strider - - direction: Horizontal - split_size: - Percent: 80 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 40 - - direction: Horizontal - split_size: - Percent: 60 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Fixed: 2 - run: - plugin: status-bar diff --git a/example/run_htop_layout.yaml b/example/run_htop_layout.yaml deleted file mode 100644 index 949435d6..00000000 --- a/example/run_htop_layout.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -direction: Vertical -parts: - - direction: Horizontal - split_size: - Percent: 50 - parts: - - direction: Vertical - split_size: - Percent: 50 - - direction: Vertical - split_size: - Percent: 50 - run: - command: {cmd: htop} - - direction: Horizontal - split_size: - Percent: 50 - run: - command: {cmd: htop} diff --git a/example/run_htop_layout_with_plugins.yaml b/example/run_htop_layout_with_plugins.yaml deleted file mode 100644 index 99f72edb..00000000 --- a/example/run_htop_layout_with_plugins.yaml +++ /dev/null @@ -1,30 +0,0 @@ ---- -direction: Horizontal -parts: - - direction: Vertical - split_size: - Fixed: 1 - run: - plugin: tab-bar - - direction: Vertical - parts: - - direction: Vertical - parts: - - direction: Vertical - split_size: - Percent: 50 - run: - command: {cmd: htop} - - direction: Vertical - split_size: - Percent: 50 - run: - command: {cmd: htop, args: ["-C"]} - - direction: Vertical - split_size: - Fixed: 5 - - direction: Vertical - split_size: - Fixed: 2 - run: - plugin: status-bar diff --git a/nonexistent.yaml b/nonexistent.yaml new file mode 100644 index 00000000..740bde92 --- /dev/null +++ b/nonexistent.yaml @@ -0,0 +1,2 @@ +--- +borderless: false diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index f74a74dd..e806ec3b 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -14,14 +14,14 @@ use crate::{ command_is_executing::CommandIsExecuting, input_handler::input_loop, os_input_output::ClientOsApi, }; -use zellij_utils::cli::CliArgs; use zellij_utils::{ channels::{self, ChannelWithContext, SenderWithContext}, consts::{SESSION_NAME, ZELLIJ_IPC_PIPE}, errors::{ClientContext, ContextType, ErrorInstruction}, - input::{actions::Action, config::Config, layout::LayoutTemplate, options::Options}, + input::{actions::Action, config::Config, options::Options}, ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg}, }; +use zellij_utils::{cli::CliArgs, input::layout::LayoutFromYaml}; /// Instructions related to the client-side application #[derive(Debug, Clone)] @@ -87,7 +87,7 @@ pub fn start_client( opts: CliArgs, config: Config, info: ClientInfo, - layout: Option, + layout: Option, ) { info!("Starting Zellij client!"); let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}12l\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l\u{1b}[?12l"; diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index d0b3b5d2..e9848e70 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -36,7 +36,7 @@ use zellij_utils::{ input::{ command::{RunCommand, TerminalAction}, get_mode_info, - layout::LayoutTemplate, + layout::LayoutFromYaml, options::Options, }, ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg}, @@ -50,7 +50,7 @@ pub(crate) enum ServerInstruction { ClientAttributes, Box, Box, - Option, + Option, ), Render(Option), UnblockInputThread, @@ -245,9 +245,6 @@ pub fn start_server(os_input: Box, socket_path: PathBuf) { if !&layout.tabs.is_empty() { for tab_layout in layout.tabs { spawn_tabs(Some(tab_layout.clone())); - // Spawning tabs in too quick succession might mess up the layout - // TODO: investigate why - thread::sleep(std::time::Duration::from_millis(250)); } } else { spawn_tabs(None); @@ -329,7 +326,7 @@ fn init_session( to_server: SenderWithContext, client_attributes: ClientAttributes, session_state: Arc>, - layout: Option, + layout: Option, ) -> SessionMetaData { let (to_screen, screen_receiver): ChannelWithContext = channels::unbounded(); let to_screen = SenderWithContext::new(to_screen); diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 5c0e4a26..011b45ca 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -20,7 +20,7 @@ use zellij_utils::{ errors::{get_current_ctx, ContextType, PtyContext}, input::{ command::TerminalAction, - layout::{Layout, LayoutTemplate, Run, TabLayout}, + layout::{Layout, LayoutFromYaml, Run, TabLayout}, }, logging::debug_to_file, }; @@ -60,7 +60,7 @@ pub(crate) struct Pty { task_handles: HashMap>, } -pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option) { +pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option) { loop { let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Pty((&event).into())); @@ -88,8 +88,8 @@ pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option } PtyInstruction::NewTab(terminal_action, tab_layout) => { if let Some(layout) = maybe_layout.clone() { - let merged_layout = layout.construct_tab_layout(tab_layout); - pty.spawn_terminals_for_layout(merged_layout, terminal_action.clone()); + let merged_layout = layout.template.insert_tab_layout(tab_layout); + pty.spawn_terminals_for_layout(merged_layout.into(), terminal_action.clone()); } else { let pid = pty.spawn_terminal(terminal_action.clone()); pty.bus diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 15c964fe..a3da6aba 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -20,8 +20,6 @@ use std::path::{Path, PathBuf}; use std::vec::Vec; use std::{fs::File, io::prelude::*}; -use super::config::{LayoutMissingTabSectionError, LayoutPartAndTabError}; - #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] pub enum Direction { @@ -52,8 +50,6 @@ pub struct Layout { pub direction: Direction, #[serde(default)] pub parts: Vec, - #[serde(default)] - pub tabs: Vec, pub split_size: Option, pub run: Option, #[serde(default)] @@ -64,9 +60,10 @@ pub struct Layout { // a yaml configuration file #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] +#[serde(default)] pub struct LayoutFromYaml { - //#[serde(default)] - pub template: LayoutTemplateFromYaml, + #[serde(default)] + pub template: LayoutTemplate, #[serde(default)] pub borderless: bool, #[serde(default)] @@ -84,6 +81,7 @@ impl LayoutFromYaml { let mut layout = String::new(); layout_file.read_to_string(&mut layout)?; let layout: LayoutFromYaml = serde_yaml::from_str(&layout)?; + Ok(layout) } @@ -112,16 +110,6 @@ impl LayoutFromYaml { )) }) } - - pub fn construct_layout_template(&self) -> LayoutTemplate { - let (pre_tab, post_tab) = self.template.split_template().unwrap(); - LayoutTemplate { - pre_tab: pre_tab.into(), - post_tab: Layout::from_vec_template_layout(post_tab), - tabs: self.tabs.clone(), - } - } - // Currently still needed but on nightly // this is already possible: // HashMap<&'static str, Vec> @@ -162,58 +150,43 @@ impl LayoutFromYaml { // construct the layout #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] -pub struct LayoutTemplateFromYaml { +pub struct LayoutTemplate { pub direction: Direction, #[serde(default)] pub borderless: bool, #[serde(default)] - pub parts: Vec, + pub parts: Vec, #[serde(default)] pub body: bool, pub split_size: Option, pub run: Option, } -impl LayoutTemplateFromYaml { - // Split the layout into parts that can be reassebled per tab - // returns the layout pre tab and the parts post tab - pub fn split_template( - &self, - ) -> Result<(LayoutTemplateFromYaml, Vec), LayoutPartAndTabError> { - let mut main_layout = self.clone(); - let mut pre_tab_layout = self.clone(); - let mut post_tab_layout = vec![]; - let mut post_tab = false; - - pre_tab_layout.parts.clear(); - - if main_layout.body { - post_tab = true; +impl LayoutTemplate { + // Insert an optional `[TabLayout]` at the correct postion + pub fn insert_tab_layout(mut self, tab_layout: Option) -> Self { + if self.body { + return tab_layout.unwrap_or_default().into(); } - - for part in main_layout.parts.drain(..) { - let (curr_pre_layout, mut curr_post_layout) = part.split_template()?; - - // Leaf - if !post_tab && !part.body { - pre_tab_layout.parts.push(curr_pre_layout); - } - - // Node + for (i, part) in self.parts.clone().iter().enumerate() { if part.body { - post_tab = true; - // Leaf - } else if post_tab { - if curr_post_layout.is_empty() { - let mut part_no_tab = part.clone(); - part_no_tab.parts.clear(); - post_tab_layout.push(part_no_tab); - } else { - post_tab_layout.append(&mut curr_post_layout); - } + self.parts.push(tab_layout.unwrap_or_default().into()); + self.parts.swap_remove(i); + break; } + // recurse + let new_part = part.clone().insert_tab_layout(tab_layout.clone()); + self.parts.push(new_part); + self.parts.swap_remove(i); } - Ok((pre_tab_layout, post_tab_layout)) + self + } + + fn from_vec_tab_layout(tab_layout: Vec) -> Vec { + tab_layout + .iter() + .map(|tab_layout| Self::from(tab_layout.to_owned())) + .collect() } } @@ -230,35 +203,6 @@ pub struct TabLayout { pub run: Option, } -// Main template layout struct, that carries information based on position of -// tabs in relation to the whole layout. -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] -pub struct LayoutTemplate { - pub pre_tab: Layout, - pub post_tab: Vec, - pub tabs: Vec, -} - -impl LayoutTemplate { - pub fn construct_tab_layout(&self, tab_layout: Option) -> Layout { - if let Some(tab_layout) = tab_layout { - let mut pre_tab_layout = self.pre_tab.clone(); - let post_tab_layout = &self.post_tab; - pre_tab_layout.merge_tab_layout(tab_layout); - pre_tab_layout.merge_layout_parts(post_tab_layout.to_owned()); - pre_tab_layout - } else { - let mut pre_tab_layout = self.pre_tab.clone(); - let post_tab_layout = &self.post_tab; - let default_tab_layout = TabLayout::default(); - pre_tab_layout.merge_tab_layout(default_tab_layout); - pre_tab_layout.merge_layout_parts(post_tab_layout.to_owned()); - pre_tab_layout - } - } -} - impl Layout { pub fn total_terminal_panes(&self) -> usize { let mut total_panes = 0; @@ -301,65 +245,6 @@ impl Layout { split_space(space, self) } - // Split the layout into parts that can be reassebled per tab - // returns the layout pre tab, the parts post tab and the tab layouts - pub fn split_main_and_tab_layout( - &self, - ) -> Result<(Layout, Vec, Vec), LayoutPartAndTabError> { - let mut main_layout = self.clone(); - let mut pre_tab_layout = self.clone(); - let mut post_tab_layout = vec![]; - let mut tabs = vec![]; - let mut post_tab = false; - - pre_tab_layout.parts.clear(); - pre_tab_layout.tabs.clear(); - - if !main_layout.tabs.is_empty() { - tabs.append(&mut main_layout.tabs); - post_tab = true; - } - - if !main_layout.tabs.is_empty() && !main_layout.parts.is_empty() { - return Err(LayoutPartAndTabError); - } - - for part in main_layout.parts.drain(..) { - let (curr_pre_layout, mut curr_post_layout, mut curr_tabs) = - part.split_main_and_tab_layout()?; - - // Leaf - if !post_tab && part.tabs.is_empty() { - pre_tab_layout.parts.push(curr_pre_layout); - } - - if !part.tabs.is_empty() && !part.parts.is_empty() { - return Err(LayoutPartAndTabError); - } - - // Node - if !part.tabs.is_empty() { - tabs.append(&mut part.tabs.clone()); - post_tab = true; - // Node - } else if !curr_tabs.is_empty() { - tabs.append(&mut curr_tabs); - post_tab = true; - // Leaf - } else if post_tab { - if curr_post_layout.is_empty() { - let mut part_no_tab = part.clone(); - part_no_tab.tabs.clear(); - part_no_tab.parts.clear(); - post_tab_layout.push(part_no_tab); - } else { - post_tab_layout.append(&mut curr_post_layout); - } - } - } - Ok((pre_tab_layout, post_tab_layout, tabs)) - } - pub fn merge_tab_layout(&mut self, tab: TabLayout) { self.parts.push(tab.into()); } @@ -368,20 +253,6 @@ impl Layout { self.parts.append(&mut parts); } - pub fn construct_layout_template(&self) -> Result { - let (pre_tab, post_tab, tabs) = self.split_main_and_tab_layout()?; - - if tabs.is_empty() { - return Err(ConfigError::Layout(LayoutMissingTabSectionError)); - } - - Ok(LayoutTemplate { - pre_tab, - post_tab, - tabs, - }) - } - fn from_vec_tab_layout(tab_layout: Vec) -> Vec { tab_layout .iter() @@ -389,7 +260,7 @@ impl Layout { .collect() } - fn from_vec_template_layout(layout_template: Vec) -> Vec { + fn from_vec_template_layout(layout_template: Vec) -> Vec { layout_template .iter() .map(|layout_template| Layout::from(layout_template.to_owned())) @@ -555,21 +426,32 @@ impl From for Layout { Layout { direction: tab.direction, borderless: tab.borderless, - parts: Layout::from_vec_tab_layout(tab.parts), - tabs: vec![], + parts: Self::from_vec_tab_layout(tab.parts), split_size: tab.split_size, run: tab.run, } } } -impl From for Layout { - fn from(template: LayoutTemplateFromYaml) -> Self { +impl From for LayoutTemplate { + fn from(tab: TabLayout) -> Self { + Self { + direction: tab.direction, + borderless: tab.borderless, + parts: Self::from_vec_tab_layout(tab.parts), + body: false, + split_size: tab.split_size, + run: tab.run, + } + } +} + +impl From for Layout { + fn from(template: LayoutTemplate) -> Self { Layout { direction: template.direction, borderless: template.borderless, - parts: Layout::from_vec_template_layout(template.parts), - tabs: vec![], + parts: Self::from_vec_template_layout(template.parts), split_size: template.split_size, run: template.run, } @@ -588,6 +470,36 @@ impl Default for TabLayout { } } +impl Default for LayoutTemplate { + fn default() -> Self { + Self { + direction: Direction::Horizontal, + body: false, + borderless: false, + parts: vec![LayoutTemplate { + direction: Direction::Horizontal, + body: true, + borderless: false, + split_size: None, + run: None, + parts: vec![], + }], + split_size: None, + run: None, + } + } +} + +impl Default for LayoutFromYaml { + fn default() -> Self { + Self { + template: LayoutTemplate::default(), + borderless: false, + tabs: vec![], + } + } +} + // The unit test location. #[cfg(test)] #[path = "./unit/layout_test.rs"] diff --git a/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml b/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml index 633a1fae..6b599373 100644 --- a/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml +++ b/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml @@ -22,8 +22,6 @@ template: split_size: Percent: 23 - direction: Vertical - split_size: - Percent: 77 body: true split_size: Percent: 90 diff --git a/zellij-utils/src/input/unit/fixtures/layouts/no-layout-template-specified.yaml b/zellij-utils/src/input/unit/fixtures/layouts/no-layout-template-specified.yaml new file mode 100644 index 00000000..7794c912 --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/no-layout-template-specified.yaml @@ -0,0 +1,6 @@ +--- +tabs: + - direction: Vertical + parts: + - direction: Horizontal + - direction: Horizontal diff --git a/zellij-utils/src/input/unit/fixtures/layouts/no-tab-section-specified.yaml b/zellij-utils/src/input/unit/fixtures/layouts/no-tab-section-specified.yaml new file mode 100644 index 00000000..8b0f3daf --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/no-tab-section-specified.yaml @@ -0,0 +1,6 @@ +--- +template: + direction: Horizontal + parts: + - direction: Horizontal + body: true diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs index 67b9fe4f..23c57b3d 100644 --- a/zellij-utils/src/input/unit/layout_test.rs +++ b/zellij-utils/src/input/unit/layout_test.rs @@ -23,44 +23,27 @@ fn default_layout_is_ok() { fn default_layout_has_one_tab() { let path = default_layout_dir("default.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); + let layout_template = layout.as_ref().unwrap(); assert_eq!(layout_template.tabs.len(), 1); } -#[test] -fn default_layout_has_one_pre_tab() { - let path = default_layout_dir("default.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - assert_eq!(layout_template.pre_tab.parts.len(), 1); -} - -#[test] -fn default_layout_has_one_post_tab() { - let path = default_layout_dir("default.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - assert_eq!(layout_template.post_tab.len(), 1); -} - #[test] fn default_layout_merged_correctly() { let path = default_layout_dir("default.yaml".into()); let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml - .as_ref() - .unwrap() - .construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); + let layout_template = layout_from_yaml.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[0].clone())); let merged_layout = Layout { direction: Direction::Horizontal, borderless: false, parts: vec![ Layout { direction: Direction::Vertical, - borderless: false, + borderless: true, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(1)), run: Some(Run::Plugin(Some("tab-bar".into()))), }, @@ -68,44 +51,37 @@ fn default_layout_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, Layout { direction: Direction::Vertical, - borderless: false, + borderless: true, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(2)), run: Some(Run::Plugin(Some("status-bar".into()))), }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] fn default_layout_new_tab_correct() { let path = default_layout_dir("default.yaml".into()); let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml - .as_ref() - .unwrap() - .construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(None); + let layout_template = layout_from_yaml.as_ref().unwrap(); + let tab_layout = layout_template.template.clone().insert_tab_layout(None); let merged_layout = Layout { direction: Direction::Horizontal, borderless: false, parts: vec![ Layout { direction: Direction::Vertical, - borderless: false, + borderless: true, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(1)), run: Some(Run::Plugin(Some("tab-bar".into()))), }, @@ -113,24 +89,21 @@ fn default_layout_new_tab_correct() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, Layout { direction: Direction::Vertical, - borderless: false, + borderless: true, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(2)), run: Some(Run::Plugin(Some("status-bar".into()))), }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] @@ -151,32 +124,10 @@ fn default_disable_status_layout_is_ok() { fn default_disable_status_layout_has_no_tab() { let path = default_layout_dir("disable-status-bar.yaml".into()); let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml - .as_ref() - .unwrap() - .construct_layout_template(); + let layout_template = layout_from_yaml.as_ref().unwrap(); assert_eq!(layout_template.tabs.len(), 0); } -#[test] -fn default_disable_status_layout_has_one_pre_tab() { - let path = default_layout_dir("disable-status-bar.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml - .as_ref() - .unwrap() - .construct_layout_template(); - assert_eq!(layout_template.pre_tab.parts.len(), 1); -} - -#[test] -fn default_disable_status_layout_has_no_post_tab() { - let path = default_layout_dir("disable-status-bar.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - assert!(layout_template.post_tab.is_empty()); -} - #[test] fn three_panes_with_tab_is_ok() { let path = layout_test_dir("three-panes-with-tab.yaml".into()); @@ -188,32 +139,19 @@ fn three_panes_with_tab_is_ok() { fn three_panes_with_tab_has_one_tab() { let path = layout_test_dir("three-panes-with-tab.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); + let layout_template = layout.unwrap(); assert_eq!(layout_template.tabs.len(), 1); } -#[test] -fn three_panes_with_tab_no_post_tab() { - let path = layout_test_dir("three-panes-with-tab.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); - assert!(layout_template.post_tab.is_empty()); -} - -#[test] -fn three_panes_with_tab_no_pre_tab() { - let path = layout_test_dir("three-panes-with-tab.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); - assert!(layout_template.pre_tab.parts.is_empty()); -} - #[test] fn three_panes_with_tab_merged_correctly() { let path = layout_test_dir("three-panes-with-tab.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); + let layout_template = layout.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[0].clone())); let merged_layout = Layout { direction: Direction::Horizontal, borderless: false, @@ -225,7 +163,6 @@ fn three_panes_with_tab_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -237,7 +174,6 @@ fn three_panes_with_tab_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -245,33 +181,29 @@ fn three_panes_with_tab_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, ], - tabs: vec![], split_size: None, run: None, }, ], - tabs: vec![], split_size: None, run: None, }], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] fn three_panes_with_tab_new_tab_is_correct() { let path = layout_test_dir("three-panes-with-tab.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(None); + let layout_template = layout.as_ref().unwrap(); + let tab_layout = layout_template.template.clone().insert_tab_layout(None); let merged_layout = Layout { direction: Direction::Horizontal, borderless: false, @@ -279,15 +211,13 @@ fn three_panes_with_tab_new_tab_is_correct() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] @@ -301,32 +231,19 @@ fn three_panes_with_tab_and_default_plugins_is_ok() { fn three_panes_with_tab_and_default_plugins_has_one_tab() { let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); + let layout_template = layout.unwrap(); assert_eq!(layout_template.tabs.len(), 1); } -#[test] -fn three_panes_with_tab_and_default_plugins_one_post_tab() { - let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); - assert_eq!(layout_template.post_tab.len(), 1); -} - -#[test] -fn three_panes_with_tab_and_default_plugins_has_pre_tab() { - let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); - assert!(!layout_template.pre_tab.parts.is_empty()); -} - #[test] fn three_panes_with_tab_and_default_plugins_merged_correctly() { let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); + let layout_template = layout.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[0].clone())); let merged_layout = Layout { direction: Direction::Horizontal, borderless: false, @@ -335,7 +252,6 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(1)), run: Some(Run::Plugin(Some("tab-bar".into()))), }, @@ -347,7 +263,6 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -359,7 +274,6 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -367,17 +281,14 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, ], - tabs: vec![], split_size: None, run: None, }, ], - tabs: vec![], split_size: None, run: None, }, @@ -385,24 +296,22 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(2)), run: Some(Run::Plugin(Some("status-bar".into()))), }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() { let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(None); + let layout_template = layout.as_ref().unwrap(); + let tab_layout = layout_template.template.clone().insert_tab_layout(None); let merged_layout = Layout { direction: Direction::Horizontal, borderless: false, @@ -411,7 +320,6 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(1)), run: Some(Run::Plugin(Some("tab-bar".into()))), }, @@ -419,7 +327,6 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, @@ -427,16 +334,14 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Fixed(2)), run: Some(Run::Plugin(Some("status-bar".into()))), }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] @@ -450,32 +355,19 @@ fn deeply_nested_tab_is_ok() { fn deeply_nested_tab_has_one_tab() { let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); + let layout_template = layout.unwrap(); assert_eq!(layout_template.tabs.len(), 1); } -#[test] -fn deeply_nested_tab_three_post_tab() { - let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); - assert_eq!(layout_template.post_tab.len(), 3); -} - -#[test] -fn deeply_nested_tab_has_many_pre_tab() { - let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); - let layout = LayoutFromYaml::new(&path); - let layout_template = layout.unwrap().construct_layout_template(); - assert!(!layout_template.pre_tab.parts.is_empty()); -} - #[test] fn deeply_nested_tab_merged_correctly() { let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); + let layout_template = layout.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[0].clone())); let merged_layout = Layout { direction: Direction::Horizontal, borderless: false, @@ -488,7 +380,6 @@ fn deeply_nested_tab_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(21)), run: None, }, @@ -500,48 +391,43 @@ fn deeply_nested_tab_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(22)), run: None, }, Layout { direction: Direction::Horizontal, borderless: false, - parts: vec![Layout { - direction: Direction::Horizontal, - borderless: false, - parts: vec![], - tabs: vec![], - split_size: Some(SplitSize::Percent(23)), - run: None, - }], - tabs: vec![], + parts: vec![ + Layout { + direction: Direction::Horizontal, + borderless: false, + parts: vec![], + split_size: Some(SplitSize::Percent(23)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + borderless: false, + parts: vec![], + split_size: Some(SplitSize::Percent(24)), + run: None, + }, + ], split_size: Some(SplitSize::Percent(78)), run: None, }, ], - tabs: vec![], split_size: Some(SplitSize::Percent(79)), run: None, }, ], - tabs: vec![], split_size: Some(SplitSize::Percent(90)), run: None, }, - Layout { - direction: Direction::Horizontal, - borderless: false, - parts: vec![], - tabs: vec![], - split_size: Some(SplitSize::Percent(24)), - run: None, - }, Layout { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(15)), run: None, }, @@ -549,7 +435,6 @@ fn deeply_nested_tab_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(15)), run: None, }, @@ -557,16 +442,14 @@ fn deeply_nested_tab_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(15)), run: None, }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] @@ -580,27 +463,19 @@ fn three_tabs_is_ok() { fn three_tabs_has_three_tabs() { let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.unwrap().construct_layout_template(); + let layout_template = layout_from_yaml.unwrap(); assert_eq!(layout_template.tabs.len(), 3); } -#[test] -fn three_tabs_has_one_post_tab() { - let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); - let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml.unwrap().construct_layout_template(); - assert_eq!(layout_template.post_tab.len(), 1); -} - #[test] fn three_tabs_tab_one_merged_correctly() { let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml - .as_ref() - .unwrap() - .construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); + let layout_template = layout_from_yaml.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[0].clone())); let merged_layout = Layout { direction: Direction::Vertical, borderless: false, @@ -609,7 +484,6 @@ fn three_tabs_tab_one_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -617,28 +491,26 @@ fn three_tabs_tab_one_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] fn three_tabs_tab_two_merged_correctly() { let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let layout_from_yaml = LayoutFromYaml::new(&path); - let layout_template = layout_from_yaml - .as_ref() - .unwrap() - .construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[1].clone())); + let layout_template = layout_from_yaml.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[1].clone())); let merged_layout = Layout { direction: Direction::Vertical, borderless: false, @@ -651,7 +523,6 @@ fn three_tabs_tab_two_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -659,12 +530,10 @@ fn three_tabs_tab_two_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, ], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -672,25 +541,26 @@ fn three_tabs_tab_two_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); } #[test] fn three_tabs_tab_three_merged_correctly() { let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let layout = LayoutFromYaml::new(&path); - let layout_template = layout.as_ref().unwrap().construct_layout_template(); - let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[2].clone())); + let layout_template = layout.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[2].clone())); let merged_layout = Layout { direction: Direction::Vertical, borderless: false, @@ -703,7 +573,6 @@ fn three_tabs_tab_three_merged_correctly() { direction: Direction::Vertical, borderless: false, parts: vec![], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -711,12 +580,10 @@ fn three_tabs_tab_three_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, ], - tabs: vec![], split_size: Some(SplitSize::Percent(50)), run: None, }, @@ -724,14 +591,106 @@ fn three_tabs_tab_three_merged_correctly() { direction: Direction::Horizontal, borderless: false, parts: vec![], - tabs: vec![], split_size: None, run: None, }, ], - tabs: vec![], split_size: None, run: None, }; - assert_eq!(merged_layout, tab_layout); + assert_eq!(merged_layout, tab_layout.into()); +} + +#[test] +fn no_tabs_is_ok() { + let path = layout_test_dir("no-tab-section-specified.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + assert!(layout_from_yaml.is_ok()); +} + +#[test] +fn no_tabs_has_no_tabs() { + let path = layout_test_dir("no-tab-section-specified.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + let layout_template = layout_from_yaml.unwrap(); + assert_eq!(layout_template.tabs.len(), 0); +} + +#[test] +fn no_tabs_merged_correctly() { + let path = layout_test_dir("no-tab-section-specified.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + let layout_template = layout_from_yaml.as_ref().unwrap(); + let tab_layout = layout_template.template.clone().insert_tab_layout(None); + let merged_layout = Layout { + direction: Direction::Horizontal, + borderless: false, + parts: vec![Layout { + direction: Direction::Horizontal, + borderless: false, + parts: vec![], + split_size: None, + run: None, + }], + split_size: None, + run: None, + }; + + assert_eq!(merged_layout, tab_layout.into()); +} + +#[test] +fn no_layout_template_specified_is_ok() { + let path = layout_test_dir("no-layout-template-specified.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + assert!(layout_from_yaml.is_ok()); +} + +#[test] +fn no_layout_template_has_one_tab() { + let path = layout_test_dir("no-layout-template-specified.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + let layout_template = layout_from_yaml.unwrap(); + assert_eq!(layout_template.tabs.len(), 1); +} + +#[test] +fn no_layout_template_merged_correctly() { + let path = layout_test_dir("no-layout-template-specified.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + let layout_template = layout_from_yaml.as_ref().unwrap(); + let tab_layout = layout_template + .template + .clone() + .insert_tab_layout(Some(layout_template.tabs[0].clone())); + let merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![], + split_size: None, + run: None, + borderless: false, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + split_size: None, + run: None, + borderless: false, + }, + ], + split_size: None, + run: None, + borderless: false, + }], + split_size: None, + run: None, + borderless: false, + }; + + assert_eq!(merged_layout, tab_layout.into()); } diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index d0799d4b..009d99a3 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -3,7 +3,7 @@ use crate::{ cli::CliArgs, errors::{get_current_ctx, ErrorContext}, - input::{actions::Action, layout::LayoutTemplate, options::Options}, + input::{actions::Action, layout::LayoutFromYaml, options::Options}, pane_size::PositionAndSize, }; use interprocess::local_socket::LocalSocketStream; @@ -62,7 +62,7 @@ pub enum ClientToServerMsg { ClientAttributes, Box, Box, - Option, + Option, ), AttachClient(ClientAttributes, bool, Options), Action(Action), diff --git a/zellij-utils/src/setup.rs b/zellij-utils/src/setup.rs index c680822d..0d9855ab 100644 --- a/zellij-utils/src/setup.rs +++ b/zellij-utils/src/setup.rs @@ -6,7 +6,7 @@ use crate::{ }, input::{ config::{Config, ConfigError}, - layout::{LayoutFromYaml, LayoutTemplate}, + layout::LayoutFromYaml, options::Options, }, }; @@ -153,7 +153,7 @@ impl Setup { /// 2. config options (`config.yaml`) pub fn from_options( opts: &CliArgs, - ) -> Result<(Config, Option, Options), ConfigError> { + ) -> Result<(Config, Option, Options), ConfigError> { let clean = match &opts.command { Some(Command::Setup(ref setup)) => setup.clean, _ => false, @@ -187,8 +187,8 @@ impl Setup { Some(Err(e)) => { return Err(e); } - } - .map(|layout| layout.construct_layout_template()); + }; + //.map(|layout| layout.template); if let Some(Command::Setup(ref setup)) = &opts.command { setup.from_cli(opts, &config_options).map_or_else(