diff options
| author | Aram Drevekenin <aram@poor.dev> | 2021-08-24 10:58:36 +0200 |
|---|---|---|
| committer | Aram Drevekenin <aram@poor.dev> | 2021-08-24 10:58:36 +0200 |
| commit | 618c2c376bb4edca8693ea4b871279bc04501559 (patch) | |
| tree | b4d4426b353955e8af1ed8ad6531f95860eda5f6 /zellij-utils | |
| parent | docs(changelog): add `ToggleTab` action (diff) | |
| parent | Add `template` section in `layout` file (diff) | |
| download | sl0ppij-618c2c376bb4edca8693ea4b871279bc04501559.tar.gz sl0ppij-618c2c376bb4edca8693ea4b871279bc04501559.tar.xz sl0ppij-618c2c376bb4edca8693ea4b871279bc04501559.zip | |
Merge branch 'tab-layout' of https://github.com/a-kenji/zellij into a-kenji-tab-layout
Diffstat (limited to 'zellij-utils')
17 files changed, 1316 insertions, 82 deletions
diff --git a/zellij-utils/assets/config/default.yaml b/zellij-utils/assets/config/default.yaml index 94f12f33..42f2287b 100644 --- a/zellij-utils/assets/config/default.yaml +++ b/zellij-utils/assets/config/default.yaml @@ -136,7 +136,7 @@ keybinds: key: [ Char: 'h', Left, Up, Char: 'k',] - action: [GoToNextTab,] key: [ Char: 'l', Right,Down, Char: 'j'] - - action: [NewTab,] + - action: [NewTab: ,] key: [ Char: 'n',] - action: [CloseTab,] key: [ Char: 'x',] diff --git a/zellij-utils/assets/layouts/default.yaml b/zellij-utils/assets/layouts/default.yaml index b163821d..e0a28da1 100644 --- a/zellij-utils/assets/layouts/default.yaml +++ b/zellij-utils/assets/layouts/default.yaml @@ -1,16 +1,20 @@ --- -direction: Horizontal -parts: +template: + direction: Horizontal + parts: + - direction: Vertical + borderless: true + split_size: + Fixed: 1 + run: + plugin: tab-bar + - direction: Vertical + body: true + - direction: Vertical + borderless: true + split_size: + Fixed: 2 + run: + plugin: status-bar +tabs: - direction: Vertical - borderless: true - split_size: - Fixed: 1 - run: - plugin: tab-bar - - direction: Vertical - - direction: Vertical - borderless: true - split_size: - Fixed: 2 - run: - plugin: status-bar diff --git a/zellij-utils/assets/layouts/disable-status-bar.yaml b/zellij-utils/assets/layouts/disable-status-bar.yaml index a03c71c3..a58ef4cf 100644 --- a/zellij-utils/assets/layouts/disable-status-bar.yaml +++ b/zellij-utils/assets/layouts/disable-status-bar.yaml @@ -1,10 +1,12 @@ --- -direction: Horizontal -parts: - - direction: Vertical - borderless: true - split_size: - Fixed: 1 - run: - plugin: tab-bar - - direction: Vertical +template: + direction: Horizontal + parts: + - direction: Vertical + borderless: true + split_size: + Fixed: 1 + run: + plugin: tab-bar + - direction: Vertical + body: true diff --git a/zellij-utils/assets/layouts/strider.yaml b/zellij-utils/assets/layouts/strider.yaml index 28814389..96e3c290 100644 --- a/zellij-utils/assets/layouts/strider.yaml +++ b/zellij-utils/assets/layouts/strider.yaml @@ -1,12 +1,22 @@ --- -direction: Horizontal -parts: - - direction: Vertical - borderless: true - split_size: - Fixed: 1 - run: - plugin: tab-bar +template: + direction: Horizontal + parts: + - direction: Vertical + borderless: true + split_size: + Fixed: 1 + run: + plugin: tab-bar + - direction: Vertical + body: true + - direction: Vertical + borderless: true + split_size: + Fixed: 2 + run: + plugin: status-bar +tabs: - direction: Vertical parts: - direction: Horizontal @@ -15,9 +25,3 @@ parts: run: plugin: strider - direction: Horizontal - - direction: Vertical - borderless: true - split_size: - Fixed: 2 - run: - plugin: status-bar diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 23c01eef..cd4ca464 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -1,6 +1,7 @@ //! Definition of the actions that can be bound to keys. use super::command::RunCommandAction; +use super::layout::TabLayout; use crate::input::options::OnForceClose; use serde::{Deserialize, Serialize}; use zellij_tile::data::InputMode; @@ -19,7 +20,7 @@ pub enum Direction { // As these actions are bound to the default config, please // do take care when refactoring - or renaming. // They might need to be adjusted in the default config -// as well `../../../assets/config/default.yaml` +// as well `../../assets/config/default.yaml` /// Actions that can be bound to keys. #[derive(Eq, Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum Action { @@ -65,8 +66,8 @@ pub enum Action { NewPane(Option<Direction>), /// Close the focus pane. CloseFocus, - /// Create a new tab. - NewTab, + /// Create a new tab, optionally with a specified tab layout. + NewTab(Option<TabLayout>), /// Do nothing. NoOp, /// Go to the next tab. diff --git a/zellij-utils/src/input/config.rs b/zellij-utils/src/input/config.rs index 6a65109a..930fe07a 100644 --- a/zellij-utils/src/input/config.rs +++ b/zellij-utils/src/input/config.rs @@ -45,6 +45,9 @@ pub enum ConfigError { IoPath(io::Error, PathBuf), // Internal Deserialization Error FromUtf8(std::string::FromUtf8Error), + // Missing the tab section in the layout. + Layout(LayoutMissingTabSectionError), + LayoutPartAndTab(LayoutPartAndTabError), } impl Default for Config { @@ -129,6 +132,75 @@ impl Config { } } +// TODO: Split errors up into separate modules +#[derive(Debug, Clone)] +pub struct LayoutMissingTabSectionError; +#[derive(Debug, Clone)] +pub struct LayoutPartAndTabError; + +impl fmt::Display for LayoutMissingTabSectionError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "MissingTabSectionError: +There needs to be exactly one `tabs` section specified in the layout file, for example: +--- +direction: Horizontal +parts: + - direction: Vertical + - direction: Vertical + tabs: + - direction: Vertical + - direction: Vertical + - direction: Vertical +" + ) + } +} + +impl std::error::Error for LayoutMissingTabSectionError { + fn description(&self) -> &str { + "One tab must be specified per Layout." + } +} + +impl fmt::Display for LayoutPartAndTabError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "LayoutPartAndTabError: +The `tabs` and `parts` section should not be specified on the same level in the layout file, for example: +--- +direction: Horizontal +parts: + - direction: Vertical + - direction: Vertical +tabs: + - direction: Vertical + - direction: Vertical + - direction: Vertical + +should rather be specified as: +--- +direction: Horizontal +parts: + - direction: Vertical + - direction: Vertical + tabs: + - direction: Vertical + - direction: Vertical + - direction: Vertical +" + ) + } +} + +impl std::error::Error for LayoutPartAndTabError { + fn description(&self) -> &str { + "The `tabs` and parts section should not be specified on the same level." + } +} + impl Display for ConfigError { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self { @@ -138,6 +210,12 @@ impl Display for ConfigError { } ConfigError::Serde(ref err) => write!(formatter, "Deserialization error: {}", err), ConfigError::FromUtf8(ref err) => write!(formatter, "FromUtf8Error: {}", err), + ConfigError::Layout(ref err) => { + write!(formatter, "There was an error in the layout file, {}", err) + } + ConfigError::LayoutPartAndTab(ref err) => { + write!(formatter, "There was an error in the layout file, {}", err) + } } } } @@ -149,6 +227,8 @@ impl std::error::Error for ConfigError { ConfigError::IoPath(ref err, _) => Some(err), ConfigError::Serde(ref err) => Some(err), ConfigError::FromUtf8(ref err) => Some(err), + ConfigError::Layout(ref err) => Some(err), + ConfigError::LayoutPartAndTab(ref err) => Some(err), } } } @@ -171,6 +251,18 @@ impl From<std::string::FromUtf8Error> for ConfigError { } } +impl From<LayoutMissingTabSectionError> for ConfigError { + fn from(err: LayoutMissingTabSectionError) -> ConfigError { + ConfigError::Layout(err) + } +} + +impl From<LayoutPartAndTabError> for ConfigError { + fn from(err: LayoutPartAndTabError) -> ConfigError { + ConfigError::LayoutPartAndTab(err) + } +} + // The unit test location. #[cfg(test)] mod config_test { diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 33e08bfd..96f6189c 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -17,23 +17,26 @@ 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)] +use super::config::{LayoutMissingTabSectionError, LayoutPartAndTabError}; + +#[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,35 +45,49 @@ pub enum Run { Command(RunCommand), } -#[derive(Debug, Serialize, Deserialize, Clone)] +// The layout struct 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<Layout>, + #[serde(default)] + pub tabs: Vec<TabLayout>, pub split_size: Option<SplitSize>, pub run: Option<Run>, #[serde(default)] pub borderless: bool, } -type LayoutResult = Result<Layout, ConfigError>; +// 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 LayoutFromYaml { + //#[serde(default)] + pub template: LayoutTemplateFromYaml, + #[serde(default)] + pub tabs: Vec<TabLayout>, +} -impl Layout { - pub fn new(layout_path: &Path) -> LayoutResult { +type LayoutFromYamlResult = Result<LayoutFromYaml, ConfigError>; + +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())), @@ -82,22 +99,31 @@ impl Layout { layout: Option<&PathBuf>, layout_path: Option<&PathBuf>, layout_dir: Option<PathBuf>, - ) -> Option<Result<Layout, ConfigError>> { + ) -> Option<LayoutFromYamlResult> { 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<u8>> - 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(), @@ -111,24 +137,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<LayoutTemplateFromYaml>, + #[serde(default)] + pub body: bool, + pub split_size: Option<SplitSize>, + pub run: Option<Run>, +} + +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<LayoutTemplateFromYaml>), 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<TabLayout>, + pub split_size: Option<SplitSize>, + pub run: Option<Run>, +} + +// 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<Layout>, + pub tabs: Vec<TabLayout>, +} + +impl LayoutTemplate { + pub fn construct_tab_layout(&self, tab_layout: Option<TabLayout>) -> 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(); @@ -169,6 +294,101 @@ 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, + ) -> Result<(Layout, Vec<Layout>, Vec<TabLayout>), 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()); + } + + pub fn merge_layout_parts(&mut self, mut parts: Vec<Layout>) { + self.parts.append(&mut parts); + } + + pub fn construct_layout_template(&self) -> Result<LayoutTemplate, ConfigError> { + 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<TabLayout>) -> Vec<Self> { + tab_layout + .iter() + .map(|tab_layout| Layout::from(tab_layout.to_owned())) + .collect() + } + + fn from_vec_template_layout(layout_template: Vec<LayoutTemplateFromYaml>) -> Vec<Self> { + layout_template + .iter() + .map(|layout_template| Layout::from(layout_template.to_owned())) + .collect() + } } fn split_space_to_parts_vertically( @@ -323,3 +543,43 @@ fn split_space( } pane_positions } + +impl From<TabLayout> 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 From<LayoutTemplateFromYaml> 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 { + direction: Direction::Horizontal, + parts: vec![], + split_size: None, + run: None, + } + } +} + +// The unit test location. +#[cfg(test)] +#[path = "./unit/layout_test.rs"] +mod layout_test; diff --git a/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml b/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml new file mode 100644 index 00000000..633a1fae --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/deeply-nested-tab-layout.yaml @@ -0,0 +1,43 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + parts: + - direction: Horizontal + split_size: + Percent: 21 + - direction: Vertical + split_size: + Percent: 79 + parts: + - direction: Horizontal + split_size: + Percent: 22 + - direction: Horizontal + split_size: + Percent: 78 + parts: + - direction: Horizontal + split_size: + Percent: 23 + - direction: Vertical + split_size: + Percent: 77 + body: true + split_size: + Percent: 90 + - direction: Vertical + split_size: + Percent: 15 + - direction: Vertical + split_size: + Percent: 15 + - direction: Vertical + split_size: + Percent: 15 + +tabs: + - direction: Horizontal + split_size: + Percent: 24 diff --git a/zellij-utils/src/input/unit/fixtures/layouts/multiple-tabs-should-not-error.yaml b/zellij-utils/src/input/unit/fixtures/layouts/multiple-tabs-should-not-error.yaml new file mode 100644 index 00000000..65378759 --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/multiple-tabs-should-not-error.yaml @@ -0,0 +1,18 @@ +--- +direction: Horizontal +parts: + - direction: Horizontal + parts: + - direction: Vertical + parts: + - direction: Horizontal + split_size: + Percent: 50 + - direction: Horizontal + tabs: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-command.yaml b/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-command.yaml new file mode 100644 index 00000000..9ad1034d --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-command.yaml @@ -0,0 +1,35 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: tab-bar + - direction: Horizontal + body: true + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: status-bar + +tabs: + - direction: Vertical + parts: + - direction: Horizontal + split_size: + Percent: 50 + - direction: Horizontal + parts: + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop} + - direction: Vertical + split_size: + Percent: 50 + run: + command: {cmd: htop, args: ["-C"]} diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-default-plugins.yaml b/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-default-plugins.yaml new file mode 100644 index 00000000..88046395 --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab-and-default-plugins.yaml @@ -0,0 +1,31 @@ +--- +template: + direction: Horizontal + parts: + - direction: Vertical + split_size: + Fixed: 1 + run: + plugin: tab-bar + - direction: Horizontal + body: true + - direction: Vertical + split_size: + Fixed: 2 + run: + plugin: status-bar + +tabs: + - direction: Vertical + parts: + - direction: Horizontal + split_size: + Percent: 50 + - direction: Horizontal + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab.yaml b/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab.yaml new file mode 100644 index 00000000..83f05076 --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/three-panes-with-tab.yaml @@ -0,0 +1,21 @@ +--- +template: + direction: Horizontal + parts: + - direction: Horizontal + body: true + +tabs: + - direction: Vertical + parts: + - direction: Horizontal + split_size: + Percent: 50 + - direction: Horizontal + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Vertical + split_size: + Percent: 50 diff --git a/zellij-utils/src/input/unit/fixtures/layouts/three-tabs-merged-correctly.yaml b/zellij-utils/src/input/unit/fixtures/layouts/three-tabs-merged-correctly.yaml new file mode 100644 index 00000000..e2a09a73 --- /dev/null +++ b/zellij-utils/src/input/unit/fixtures/layouts/three-tabs-merged-correctly.yaml @@ -0,0 +1,29 @@ +--- +template: + direction: Vertical + parts: + - direction: Horizontal + body: true + - direction: Horizontal + + +tabs: + - direction: Horizontal + split_size: + Percent: 50 + - direction: Horizontal + split_size: + Percent: 50 + parts: + - direction: Horizontal + split_size: + Percent: 50 + - direction: Horizontal + - direction: Vertical + split_size: + Percent: 50 + parts: + - direction: Vertical + split_size: + Percent: 50 + - direction: Horizontal diff --git a/zellij-utils/src/input/unit/keybinds_test.rs b/zellij-utils/src/input/unit/keybinds_test.rs index 4767fc15..e8a776d7 100644 --- a/zellij-utils/src/input/unit/keybinds_test.rs +++ b/zellij-utils/src/input/unit/keybinds_test.rs @@ -150,7 +150,7 @@ fn no_unbind_unbinds_none() { #[test] fn last_keybind_is_taken() { - let actions_1 = vec![Action::NoOp, Action::NewTab]; + let actions_1 = vec![Action::NoOp, Action::NewTab(None)]; let keyaction_1 = KeyActionFromYaml { action: actions_1.clone(), key: vec![Key::F(1), Key::Backspace, Key::Char('t')], @@ -171,7 +171,7 @@ fn last_keybind_is_taken() { #[test] fn last_keybind_overwrites() { - let actions_1 = vec![Action::NoOp, Action::NewTab]; + let actions_1 = vec![Action::NoOp, Action::NewTab(None)]; let keyaction_1 = KeyActionFromYaml { action: actions_1.clone(), key: vec![Key::F(1), Key::Backspace, Key::Char('t')], @@ -764,7 +764,7 @@ fn unbind_single_toplevel_multiple_keys_multiple_modes() { fn uppercase_and_lowercase_are_distinct() { let key_action_n = KeyActionFromYaml { key: vec![Key::Char('n')], - action: vec![Action::NewTab], + action: vec![Action::NewTab(None)], }; let key_action_large_n = KeyActionFromYaml { key: vec![Key::Char('N')], diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs new file mode 100644 index 00000000..d09d328c --- /dev/null +++ b/zellij-utils/src/input/unit/layout_test.rs @@ -0,0 +1,685 @@ +use super::super::layout::*; + +fn layout_test_dir(layout: String) -> PathBuf { + let root = Path::new(env!("CARGO_MANIFEST_DIR")); + let layout_dir = root.join("src/input/unit/fixtures/layouts"); + layout_dir.join(layout) +} + +fn default_layout_dir(layout: String) -> PathBuf { + let root = Path::new(env!("CARGO_MANIFEST_DIR")); + let layout_dir = root.join("assets/layouts"); + layout_dir.join(layout) +} + +#[test] +fn default_layout_is_ok() { + let path = default_layout_dir("default.yaml".into()); + let layout = LayoutFromYaml::new(&path); + assert!(layout.is_ok()); +} + +#[test] +fn default_layout_has_one_tab() { + let path = default_layout_dir("default.yaml".into()); + let layout = LayoutFromYaml::new(&path); + let layout_template = layout.as_ref().unwrap().construct_layout_template(); + 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 merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Fixed(1)), + run: Some(Run::Plugin(Some("tab-bar".into()))), + }, + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + Layout { + direction: Direction::Vertical, + 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); +} + +#[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 merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Fixed(1)), + run: Some(Run::Plugin(Some("tab-bar".into()))), + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + Layout { + direction: Direction::Vertical, + 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); +} + +#[test] +fn default_strider_layout_is_ok() { + let path = default_layout_dir("strider.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + assert!(layout_from_yaml.is_ok()); +} + +#[test] +fn default_disable_status_layout_is_ok() { + let path = default_layout_dir("disable-status-bar.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + assert!(layout_from_yaml.is_ok()); +} + +#[test] +fn default_disable_status_layout_has_no_tab() { + let path = default_layout_dir("disable-status-bar.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + let layout_template = layout_from_yaml + .as_ref() + .unwrap() + .construct_layout_template(); + 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()); + let layout = LayoutFromYaml::new(&path); + assert!(layout.is_ok()); +} + +#[test] +fn three_panes_with_tab_has_one_tab() { + let path = layout_test_dir("three-panes-with-tab.yaml".into()); + let layout = LayoutFromYaml::new(&path); + let layout_template = layout.unwrap().construct_layout_template(); + 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 merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Vertical, + 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); +} + +#[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 merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }], + tabs: vec![], + split_size: None, + run: None, + }; + assert_eq!(merged_layout, tab_layout); +} + +#[test] +fn three_panes_with_tab_and_default_plugins_is_ok() { + let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); + let layout = LayoutFromYaml::new(&path); + assert!(layout.is_ok()); +} + +#[test] +fn three_panes_with_tab_and_default_plugins_has_one_tab() { + let path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into()); + let layout = LayoutFromYaml::new(&path); + let layout_template = layout.unwrap().construct_layout_template(); + 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 merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Fixed(1)), + run: Some(Run::Plugin(Some("tab-bar".into()))), + }, + Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Vertical, + 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, + }, + Layout { + direction: Direction::Vertical, + 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); +} + +#[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 merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Fixed(1)), + run: Some(Run::Plugin(Some("tab-bar".into()))), + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + Layout { + direction: Direction::Vertical, + 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); +} + +#[test] +fn deeply_nested_tab_is_ok() { + let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); + let layout = LayoutFromYaml::new(&path); + assert!(layout.is_ok()); +} + +#[test] +fn deeply_nested_tab_has_one_tab() { + let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); + let layout = LayoutFromYaml::new(&path); + let layout_template = layout.unwrap().construct_layout_template(); + 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 merged_layout = Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(21)), + run: None, + }, + Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(22)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(23)), + run: None, + }], + tabs: vec![], + 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, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(24)), + run: None, + }, + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(15)), + run: None, + }, + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(15)), + run: None, + }, + Layout { + direction: Direction::Vertical, + 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); +} + +#[test] +fn three_tabs_is_ok() { + let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + assert!(layout_from_yaml.is_ok()); +} + +#[test] +fn three_tabs_has_three_tabs() { + let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); + let layout_from_yaml = LayoutFromYaml::new(&path); + let layout_template = layout_from_yaml.unwrap().construct_layout_template(); + 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 merged_layout = Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + ], + tabs: vec![], + split_size: None, + run: None, + }; + + assert_eq!(merged_layout, tab_layout); +} + +#[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 merged_layout = Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![ + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + ], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + ], + tabs: vec![], + split_size: None, + run: None, + }; + + assert_eq!(merged_layout, tab_layout); +} + +#[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 merged_layout = Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![ + Layout { + direction: Direction::Vertical, + parts: vec![], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + ], + tabs: vec![], + split_size: Some(SplitSize::Percent(50)), + run: None, + }, + Layout { + direction: Direction::Horizontal, + parts: vec![], + tabs: vec![], + split_size: None, + run: None, + }, + ], + tabs: vec![], + split_size: None, + run: None, + }; + assert_eq!(merged_layout, tab_layout); +} diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index cf952bdc..d0799d4b 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -1,18 +1,20 @@ //! IPC stuff for starting to split things into a client and server model. -use crate::cli::CliArgs; -use crate::pane_size::PositionAndSize; use crate::{ + cli::CliArgs, errors::{get_current_ctx, ErrorContext}, - input::{actions::Action, layout::Layout, options::Options}, + input::{actions::Action, layout::LayoutTemplate, options::Options}, + pane_size::PositionAndSize, }; use interprocess::local_socket::LocalSocketStream; use nix::unistd::dup; use serde::{Deserialize, Serialize}; -use std::fmt::{Display, Error, Formatter}; -use std::io::{self, Write}; -use std::marker::PhantomData; -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::{ + fmt::{Display, Error, Formatter}, + io::{self, Write}, + marker::PhantomData, + os::unix::io::{AsRawFd, FromRawFd}, +}; use zellij_tile::data::Palette; @@ -56,7 +58,12 @@ pub enum ClientToServerMsg { // Disconnect from the session we're connected to DisconnectFromSession,*/ TerminalResize(PositionAndSize), - NewClient(ClientAttributes, Box<CliArgs>, Box<Options>, Option<Layout>), + NewClient( + ClientAttributes, + Box<CliArgs>, + Box<Options>, + Option<LayoutTemplate>, + ), AttachClient(ClientAttributes, bool, Options), Action(Action), ClientExited, diff --git a/zellij-utils/src/setup.rs b/zellij-utils/src/setup.rs index e3960951..c680822d 100644 --- a/zellij-utils/src/setup.rs +++ b/zellij-utils/src/setup.rs @@ -1,12 +1,13 @@ -use crate::consts::{ - FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, ZELLIJ_PROJ_DIR, -}; -use crate::input::options::Options; use crate::{ cli::{CliArgs, Command}, + consts::{ + FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, + ZELLIJ_PROJ_DIR, + }, input::{ config::{Config, ConfigError}, - layout::Layout, + layout::{LayoutFromYaml, LayoutTemplate}, + options::Options, }, }; use directories_next::BaseDirs; @@ -150,7 +151,9 @@ impl Setup { /// file options: /// 1. command line options (`zellij options`) /// 2. config options (`config.yaml`) - pub fn from_options(opts: &CliArgs) -> Result<(Config, Option<Layout>, Options), ConfigError> { + pub fn from_options( + opts: &CliArgs, + ) -> Result<(Config, Option<LayoutTemplate>, Options), ConfigError> { let clean = match &opts.command { Some(Command::Setup(ref setup)) => setup.clean, _ => false, @@ -160,7 +163,6 @@ impl Setup { match Config::try_from(opts) { Ok(config) => config, Err(e) => { - eprintln!("There was an error in the config file:"); return Err(e); } } @@ -174,7 +176,7 @@ impl Setup { .layout_dir .clone() .or_else(|| get_layout_dir(opts.config_dir.clone().or_else(find_default_config_dir))); - let layout_result = crate::input::layout::Layout::from_path_or_default( + let layout_result = LayoutFromYaml::from_path_or_default( opts.layout.as_ref(), opts.layout_path.as_ref(), layout_dir, @@ -183,10 +185,10 @@ impl Setup { None => None, Some(Ok(layout)) => Some(layout), Some(Err(e)) => { - eprintln!("There was an error in the layout file:"); return Err(e); } - }; + } + .map(|layout| layout.construct_layout_template()); if let Some(Command::Setup(ref setup)) = &opts.command { setup.from_cli(opts, &config_options).map_or_else( |
