From 5ede25dc37ceb192032524ac9200bb1ca95e5863 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Fri, 9 Jul 2021 23:37:36 +0200 Subject: Add `tabs` to `layouts` fixes #603, fixes #349 * The layout has now a unique `tabs` section, that can be used, like the `parts` section, everything that is not inside the tabs section is assumed to be present on every single tab that is opened. This is a BREAKING CHANGE for people that use custom `layouts` already, since the `tabs` section is not optional - for clarity and intentionality reasons. The functionality to specify multiple tabs is already there, but is still gated behind a panic, until #621 is fixed. So for now one tab can be specified to load on startup. * The `NewTab` action can optionally be bound to open a layout that is assumed to be in the new `tabs` section This is a BREAKING CHANGE for people that have the `NewTab` action already bound in the config file: ``` - action: [NewTab, ] key: [F: 5,] ``` must now be specified as: ``` - action: [NewTab: ,] key: [F: 5,] ``` Optionally a layout that should be opened on the new tab can be specified: ``` - action: [NewTab: { direction: Vertical, parts: [ {direction: Horizontal, split_size: {Percent: 50}}, {direction: Horizontal, run: {command: {cmd: "htop"}}},], key: [F: 6,] ``` or: ``` - action: [NewTab: {direction: Vertical, run: {command: {cmd: "htop"} }},] key: [F: 7,] ``` or ``` - action: [NewTab: { direction: Vertical, parts: [ {direction: Vertical, split_size: {Percent: 25},run: {plugin: "strider" }}, {direction: Horizontal}],}, MoveFocus: Left,] key: [F: 8,] ``` --- zellij-utils/src/input/layout.rs | 186 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 4 deletions(-) (limited to 'zellij-utils/src/input/layout.rs') diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index a48c35219..713605e9c 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -17,23 +17,24 @@ use crate::{serde, serde_yaml}; use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; +use std::vec::Vec; use std::{fs::File, io::prelude::*}; -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] pub enum Direction { Horizontal, Vertical, } -#[derive(Debug, Serialize, Deserialize, Clone, Copy)] +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[serde(crate = "self::serde")] pub enum SplitSize { Percent(u8), // 1 to 100 Fixed(u16), // An absolute number of columns or rows } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] pub enum Run { #[serde(rename = "plugin")] @@ -42,16 +43,58 @@ pub enum Run { Command(RunCommand), } -#[derive(Debug, Serialize, Deserialize, Clone)] +// The layout struct that is ultimately used to build the layouts +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] pub struct Layout { pub direction: Direction, #[serde(default)] pub parts: Vec, + #[serde(default)] + pub tabs: Vec, + pub split_size: Option, + pub run: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +#[serde(crate = "self::serde")] +pub struct TabLayout { + pub direction: Direction, + #[serde(default)] + pub parts: Vec, pub split_size: Option, pub run: Option, } +// Main layout struct, that carries information based on +// position of tabs +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +#[serde(crate = "self::serde")] +pub struct MainLayout { + pub pre_tab: Layout, + pub post_tab: Vec, + pub tabs: Vec, +} + +impl MainLayout { + 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 + } + } +} + type LayoutResult = Result; impl Layout { @@ -168,6 +211,113 @@ impl Layout { ) -> Vec<(Layout, PositionAndSize)> { 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) -> (Layout, Vec, Vec) { + 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; + } + + 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); + } + + // Todo: Convert into actual Error, or use the future logging system. + if !part.tabs.is_empty() && !part.parts.is_empty() { + panic!("Tabs and Parts need to be specified separately."); + } + + // Todo: Convert into actual Error, or use the future logging system. + if (!part.tabs.is_empty() || !curr_tabs.is_empty()) && post_tab { + panic!("Only one tab section should be specified."); + } + + // 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); + } + } + } + (pre_tab_layout, post_tab_layout, tabs) + } + + pub fn merge_tab_layout(&mut self, tab: TabLayout) { + self.parts.push(tab.into()); + } + + pub fn merge_layout_parts(&mut self, mut parts: Vec) { + self.parts.append(&mut parts); + } + + pub fn construct_full_layout(&self, tab_layout: Option) -> Self { + if let Some(tab_layout) = tab_layout { + let (mut pre_tab_layout, post_tab_layout, _) = self.split_main_and_tab_layout(); + pre_tab_layout.merge_tab_layout(tab_layout); + pre_tab_layout.merge_layout_parts(post_tab_layout); + pre_tab_layout + } else { + let (mut pre_tab_layout, post_tab_layout, _) = self.split_main_and_tab_layout(); + let default_tab_layout = TabLayout::default(); + pre_tab_layout.merge_tab_layout(default_tab_layout); + pre_tab_layout.merge_layout_parts(post_tab_layout); + pre_tab_layout + } + } + + pub fn construct_main_layout(&self) -> MainLayout { + let (pre_tab, post_tab, tabs) = self.split_main_and_tab_layout(); + + if tabs.is_empty() { + panic!("The layout file should have a `tabs` section specified"); + } + + if tabs.len() > 1 { + panic!("The layout file should have one single tab in the `tabs` section specified"); + } + + MainLayout { + pre_tab, + post_tab, + tabs, + } + } + + fn from_vec_tab_layout(tab_layout: Vec) -> Vec { + tab_layout + .iter() + .map(|tab_layout| Layout::from(tab_layout.to_owned())) + .collect() + } } fn split_space_to_parts_vertically( @@ -322,3 +472,31 @@ fn split_space( } pane_positions } + +impl From for Layout { + fn from(tab: TabLayout) -> Self { + Layout { + direction: tab.direction, + parts: Layout::from_vec_tab_layout(tab.parts), + tabs: vec![], + split_size: tab.split_size, + run: tab.run, + } + } +} + +impl Default for TabLayout { + fn default() -> Self { + Self { + direction: Direction::Horizontal, + parts: vec![], + split_size: None, + run: None, + } + } +} + +// The unit test location. +#[cfg(test)] +#[path = "./unit/layout_test.rs"] +mod layout_test; -- cgit v1.2.3 From f323880fb7129cd74b9d156e9688fac9654480b5 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Fri, 23 Jul 2021 17:25:05 +0200 Subject: !fixup cargo fmt --- zellij-utils/src/input/layout.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'zellij-utils/src/input/layout.rs') diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 713605e9c..26d967646 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -258,14 +258,14 @@ impl Layout { 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); - } + 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); + } } } (pre_tab_layout, post_tab_layout, tabs) -- cgit v1.2.3 From 2e1775678577e8587ca0830a15810212c4b209f7 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Mon, 2 Aug 2021 12:03:42 +0200 Subject: Change layout panics to errors * Adjust and add tests for the change --- zellij-utils/src/input/layout.rs | 51 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) (limited to 'zellij-utils/src/input/layout.rs') diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 887350fb0..c795cb55b 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -20,6 +20,8 @@ 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 { @@ -43,7 +45,7 @@ pub enum Run { Command(RunCommand), } -// The layout struct that is ultimately used to build the layouts +// The layout struct ultimately used to build the layouts. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] pub struct Layout { @@ -56,6 +58,7 @@ pub struct Layout { pub run: Option, } +// The tab-layout struct used to specify each individual tab. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] pub struct TabLayout { @@ -66,8 +69,8 @@ pub struct TabLayout { pub run: Option, } -// Main layout struct, that carries information based on -// position of tabs +// Main 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 MainLayout { @@ -205,7 +208,9 @@ impl Layout { // 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) -> (Layout, Vec, Vec) { + 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![]; @@ -220,23 +225,21 @@ impl Layout { 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(); + part.split_main_and_tab_layout()?; // Leaf if !post_tab && part.tabs.is_empty() { pre_tab_layout.parts.push(curr_pre_layout); } - // Todo: Convert into actual Error, or use the future logging system. if !part.tabs.is_empty() && !part.parts.is_empty() { - panic!("Tabs and Parts need to be specified separately."); - } - - // Todo: Convert into actual Error, or use the future logging system. - if (!part.tabs.is_empty() || !curr_tabs.is_empty()) && post_tab { - panic!("Only one tab section should be specified."); + return Err(LayoutPartAndTabError); } // Node @@ -259,7 +262,7 @@ impl Layout { } } } - (pre_tab_layout, post_tab_layout, tabs) + Ok((pre_tab_layout, post_tab_layout, tabs)) } pub fn merge_tab_layout(&mut self, tab: TabLayout) { @@ -271,33 +274,31 @@ impl Layout { } pub fn construct_full_layout(&self, tab_layout: Option) -> Self { + // The `split_main_and_tab_layout()` error should have returned + // already from deserialisation, so we can assume it is `Ok()`. + let (mut pre_tab_layout, post_tab_layout, _) = self.split_main_and_tab_layout().unwrap(); if let Some(tab_layout) = tab_layout { - let (mut pre_tab_layout, post_tab_layout, _) = self.split_main_and_tab_layout(); pre_tab_layout.merge_tab_layout(tab_layout); - pre_tab_layout.merge_layout_parts(post_tab_layout); - pre_tab_layout } else { - let (mut pre_tab_layout, post_tab_layout, _) = self.split_main_and_tab_layout(); let default_tab_layout = TabLayout::default(); pre_tab_layout.merge_tab_layout(default_tab_layout); - pre_tab_layout.merge_layout_parts(post_tab_layout); - pre_tab_layout } + pre_tab_layout.merge_layout_parts(post_tab_layout); + pre_tab_layout } - pub fn construct_main_layout(&self) -> MainLayout { - let (pre_tab, post_tab, tabs) = self.split_main_and_tab_layout(); + pub fn construct_main_layout(&self) -> Result { + let (pre_tab, post_tab, tabs) = self.split_main_and_tab_layout()?; - // Todo: A proper LayoutError if tabs.is_empty() { - panic!("The layout file should have a [`tabs`] section specified"); + return Err(ConfigError::Layout(LayoutMissingTabSectionError)); } - MainLayout { + Ok(MainLayout { pre_tab, post_tab, tabs, - } + }) } fn from_vec_tab_layout(tab_layout: Vec) -> Vec { -- cgit v1.2.3 From 88b4063879845cf53397f60201473ce386280cfe Mon Sep 17 00:00:00 2001 From: a-kenji Date: Sat, 21 Aug 2021 23:27:23 +0200 Subject: Add `template` section in `layout` file It works as follows: ``` --- template: direction: Horizontal parts: - direction: Vertical split_size: Fixed: 1 run: plugin: tab-bar - direction: Vertical body: true - direction: Vertical split_size: Fixed: 2 run: plugin: status-bar tabs: - direction: Vertical ``` The tabs are created in the body section of the template. --- zellij-utils/src/input/layout.rs | 216 +++++++++++++++++++++++++++------------ 1 file changed, 150 insertions(+), 66 deletions(-) (limited to 'zellij-utils/src/input/layout.rs') diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index c795cb55b..6baa5122c 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -58,63 +58,34 @@ pub struct Layout { pub run: Option, } -// The tab-layout struct used to specify each individual tab. +// The struct that is used to deserialize the layout from +// a yaml configuration file #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(crate = "self::serde")] -pub struct TabLayout { - pub direction: Direction, +pub struct LayoutFromYaml { + //#[serde(default)] + pub template: LayoutTemplateFromYaml, #[serde(default)] - pub parts: Vec, - pub split_size: Option, - pub run: Option, -} - -// Main 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 MainLayout { - pub pre_tab: Layout, - pub post_tab: Vec, pub tabs: Vec, } -impl MainLayout { - 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 - } - } -} - -type LayoutResult = Result; +type LayoutFromYamlResult = Result; -impl Layout { - pub fn new(layout_path: &Path) -> LayoutResult { +impl LayoutFromYaml { + pub fn new(layout_path: &Path) -> LayoutFromYamlResult { let mut layout_file = File::open(&layout_path) .or_else(|_| File::open(&layout_path.with_extension("yaml"))) .map_err(|e| ConfigError::IoPath(e, layout_path.into()))?; let mut layout = String::new(); layout_file.read_to_string(&mut layout)?; - let layout: Layout = serde_yaml::from_str(&layout)?; + let layout: LayoutFromYaml = serde_yaml::from_str(&layout)?; Ok(layout) } // It wants to use Path here, but that doesn't compile. #[allow(clippy::ptr_arg)] - pub fn from_dir(layout: &PathBuf, layout_dir: Option<&PathBuf>) -> LayoutResult { + pub fn from_dir(layout: &PathBuf, layout_dir: Option<&PathBuf>) -> LayoutFromYamlResult { match layout_dir { Some(dir) => Self::new(&dir.join(layout)) .or_else(|_| Self::from_default_assets(layout.as_path())), @@ -126,22 +97,31 @@ impl Layout { layout: Option<&PathBuf>, layout_path: Option<&PathBuf>, layout_dir: Option, - ) -> Option> { + ) -> Option { layout - .map(|p| Layout::from_dir(p, layout_dir.as_ref())) - .or_else(|| layout_path.map(|p| Layout::new(p))) + .map(|p| LayoutFromYaml::from_dir(p, layout_dir.as_ref())) + .or_else(|| layout_path.map(|p| LayoutFromYaml::new(p))) .or_else(|| { - Some(Layout::from_dir( + Some(LayoutFromYaml::from_dir( &std::path::PathBuf::from("default"), layout_dir.as_ref(), )) }) } + 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> - pub fn from_default_assets(path: &Path) -> LayoutResult { + pub fn from_default_assets(path: &Path) -> LayoutFromYamlResult { match path.to_str() { Some("default") => Self::default_from_assets(), Some("strider") => Self::strider_from_assets(), @@ -155,24 +135,123 @@ impl Layout { // TODO Deserialize the assets from bytes &[u8], // once serde-yaml supports zero-copy - pub fn default_from_assets() -> LayoutResult { - let layout: Layout = + pub fn default_from_assets() -> LayoutFromYamlResult { + let layout: LayoutFromYaml = serde_yaml::from_str(String::from_utf8(setup::DEFAULT_LAYOUT.to_vec())?.as_str())?; Ok(layout) } - pub fn strider_from_assets() -> LayoutResult { - let layout: Layout = + pub fn strider_from_assets() -> LayoutFromYamlResult { + let layout: LayoutFromYaml = serde_yaml::from_str(String::from_utf8(setup::STRIDER_LAYOUT.to_vec())?.as_str())?; Ok(layout) } - pub fn disable_status_from_assets() -> LayoutResult { - let layout: Layout = + pub fn disable_status_from_assets() -> LayoutFromYamlResult { + let layout: LayoutFromYaml = serde_yaml::from_str(String::from_utf8(setup::NO_STATUS_LAYOUT.to_vec())?.as_str())?; Ok(layout) } +} + +// The struct that carries the information template that is used to +// construct the layout +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +#[serde(crate = "self::serde")] +pub struct LayoutTemplateFromYaml { + pub direction: Direction, + #[serde(default)] + 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; + } + + 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 + 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); + } + } + } + Ok((pre_tab_layout, post_tab_layout)) + } +} + +// The tab-layout struct used to specify each individual tab. +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +#[serde(crate = "self::serde")] +pub struct TabLayout { + pub direction: Direction, + #[serde(default)] + pub parts: Vec, + pub split_size: Option, + 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; total_panes += self.parts.len(); @@ -273,28 +352,14 @@ impl Layout { self.parts.append(&mut parts); } - pub fn construct_full_layout(&self, tab_layout: Option) -> Self { - // The `split_main_and_tab_layout()` error should have returned - // already from deserialisation, so we can assume it is `Ok()`. - let (mut pre_tab_layout, post_tab_layout, _) = self.split_main_and_tab_layout().unwrap(); - if let Some(tab_layout) = tab_layout { - pre_tab_layout.merge_tab_layout(tab_layout); - } else { - let default_tab_layout = TabLayout::default(); - pre_tab_layout.merge_tab_layout(default_tab_layout); - } - pre_tab_layout.merge_layout_parts(post_tab_layout); - pre_tab_layout - } - - pub fn construct_main_layout(&self) -> Result { + 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(MainLayout { + Ok(LayoutTemplate { pre_tab, post_tab, tabs, @@ -307,6 +372,13 @@ impl Layout { .map(|tab_layout| Layout::from(tab_layout.to_owned())) .collect() } + + fn from_vec_template_layout(layout_template: Vec) -> Vec { + layout_template + .iter() + .map(|layout_template| Layout::from(layout_template.to_owned())) + .collect() + } } fn split_space_to_parts_vertically( @@ -474,6 +546,18 @@ impl From for Layout { } } +impl From for Layout { + fn from(template: LayoutTemplateFromYaml) -> Self { + Layout { + direction: template.direction, + parts: Layout::from_vec_template_layout(template.parts), + tabs: vec![], + split_size: template.split_size, + run: template.run, + } + } +} + impl Default for TabLayout { fn default() -> Self { Self { -- cgit v1.2.3