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
```
This commit is contained in:
a-kenji 2021-08-26 15:06:59 +02:00
parent 06e3be6205
commit cd0b0119a0
19 changed files with 507 additions and 613 deletions

View file

@ -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

View file

@ -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

View file

@ -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}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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}

View file

@ -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

2
nonexistent.yaml Normal file
View file

@ -0,0 +1,2 @@
---
borderless: false

View file

@ -14,14 +14,14 @@ use crate::{
command_is_executing::CommandIsExecuting, input_handler::input_loop, command_is_executing::CommandIsExecuting, input_handler::input_loop,
os_input_output::ClientOsApi, os_input_output::ClientOsApi,
}; };
use zellij_utils::cli::CliArgs;
use zellij_utils::{ use zellij_utils::{
channels::{self, ChannelWithContext, SenderWithContext}, channels::{self, ChannelWithContext, SenderWithContext},
consts::{SESSION_NAME, ZELLIJ_IPC_PIPE}, consts::{SESSION_NAME, ZELLIJ_IPC_PIPE},
errors::{ClientContext, ContextType, ErrorInstruction}, 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}, ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg},
}; };
use zellij_utils::{cli::CliArgs, input::layout::LayoutFromYaml};
/// Instructions related to the client-side application /// Instructions related to the client-side application
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -87,7 +87,7 @@ pub fn start_client(
opts: CliArgs, opts: CliArgs,
config: Config, config: Config,
info: ClientInfo, info: ClientInfo,
layout: Option<LayoutTemplate>, layout: Option<LayoutFromYaml>,
) { ) {
info!("Starting Zellij client!"); 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"; 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";

View file

@ -36,7 +36,7 @@ use zellij_utils::{
input::{ input::{
command::{RunCommand, TerminalAction}, command::{RunCommand, TerminalAction},
get_mode_info, get_mode_info,
layout::LayoutTemplate, layout::LayoutFromYaml,
options::Options, options::Options,
}, },
ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg}, ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg},
@ -50,7 +50,7 @@ pub(crate) enum ServerInstruction {
ClientAttributes, ClientAttributes,
Box<CliArgs>, Box<CliArgs>,
Box<Options>, Box<Options>,
Option<LayoutTemplate>, Option<LayoutFromYaml>,
), ),
Render(Option<String>), Render(Option<String>),
UnblockInputThread, UnblockInputThread,
@ -245,9 +245,6 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
if !&layout.tabs.is_empty() { if !&layout.tabs.is_empty() {
for tab_layout in layout.tabs { for tab_layout in layout.tabs {
spawn_tabs(Some(tab_layout.clone())); 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 { } else {
spawn_tabs(None); spawn_tabs(None);
@ -329,7 +326,7 @@ fn init_session(
to_server: SenderWithContext<ServerInstruction>, to_server: SenderWithContext<ServerInstruction>,
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
session_state: Arc<RwLock<SessionState>>, session_state: Arc<RwLock<SessionState>>,
layout: Option<LayoutTemplate>, layout: Option<LayoutFromYaml>,
) -> SessionMetaData { ) -> SessionMetaData {
let (to_screen, screen_receiver): ChannelWithContext<ScreenInstruction> = channels::unbounded(); let (to_screen, screen_receiver): ChannelWithContext<ScreenInstruction> = channels::unbounded();
let to_screen = SenderWithContext::new(to_screen); let to_screen = SenderWithContext::new(to_screen);

View file

@ -20,7 +20,7 @@ use zellij_utils::{
errors::{get_current_ctx, ContextType, PtyContext}, errors::{get_current_ctx, ContextType, PtyContext},
input::{ input::{
command::TerminalAction, command::TerminalAction,
layout::{Layout, LayoutTemplate, Run, TabLayout}, layout::{Layout, LayoutFromYaml, Run, TabLayout},
}, },
logging::debug_to_file, logging::debug_to_file,
}; };
@ -60,7 +60,7 @@ pub(crate) struct Pty {
task_handles: HashMap<RawFd, JoinHandle<()>>, task_handles: HashMap<RawFd, JoinHandle<()>>,
} }
pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option<LayoutTemplate>) { pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option<LayoutFromYaml>) {
loop { loop {
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel"); let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
err_ctx.add_call(ContextType::Pty((&event).into())); err_ctx.add_call(ContextType::Pty((&event).into()));
@ -88,8 +88,8 @@ pub(crate) fn pty_thread_main(mut pty: Pty, maybe_layout: Option<LayoutTemplate>
} }
PtyInstruction::NewTab(terminal_action, tab_layout) => { PtyInstruction::NewTab(terminal_action, tab_layout) => {
if let Some(layout) = maybe_layout.clone() { if let Some(layout) = maybe_layout.clone() {
let merged_layout = layout.construct_tab_layout(tab_layout); let merged_layout = layout.template.insert_tab_layout(tab_layout);
pty.spawn_terminals_for_layout(merged_layout, terminal_action.clone()); pty.spawn_terminals_for_layout(merged_layout.into(), terminal_action.clone());
} else { } else {
let pid = pty.spawn_terminal(terminal_action.clone()); let pid = pty.spawn_terminal(terminal_action.clone());
pty.bus pty.bus

View file

@ -20,8 +20,6 @@ use std::path::{Path, PathBuf};
use std::vec::Vec; use std::vec::Vec;
use std::{fs::File, io::prelude::*}; use std::{fs::File, io::prelude::*};
use super::config::{LayoutMissingTabSectionError, LayoutPartAndTabError};
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(crate = "self::serde")] #[serde(crate = "self::serde")]
pub enum Direction { pub enum Direction {
@ -52,8 +50,6 @@ pub struct Layout {
pub direction: Direction, pub direction: Direction,
#[serde(default)] #[serde(default)]
pub parts: Vec<Layout>, pub parts: Vec<Layout>,
#[serde(default)]
pub tabs: Vec<TabLayout>,
pub split_size: Option<SplitSize>, pub split_size: Option<SplitSize>,
pub run: Option<Run>, pub run: Option<Run>,
#[serde(default)] #[serde(default)]
@ -64,9 +60,10 @@ pub struct Layout {
// a yaml configuration file // a yaml configuration file
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(crate = "self::serde")] #[serde(crate = "self::serde")]
#[serde(default)]
pub struct LayoutFromYaml { pub struct LayoutFromYaml {
//#[serde(default)] #[serde(default)]
pub template: LayoutTemplateFromYaml, pub template: LayoutTemplate,
#[serde(default)] #[serde(default)]
pub borderless: bool, pub borderless: bool,
#[serde(default)] #[serde(default)]
@ -84,6 +81,7 @@ impl LayoutFromYaml {
let mut layout = String::new(); let mut layout = String::new();
layout_file.read_to_string(&mut layout)?; layout_file.read_to_string(&mut layout)?;
let layout: LayoutFromYaml = serde_yaml::from_str(&layout)?; let layout: LayoutFromYaml = serde_yaml::from_str(&layout)?;
Ok(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 // Currently still needed but on nightly
// this is already possible: // this is already possible:
// HashMap<&'static str, Vec<u8>> // HashMap<&'static str, Vec<u8>>
@ -162,58 +150,43 @@ impl LayoutFromYaml {
// construct the layout // construct the layout
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(crate = "self::serde")] #[serde(crate = "self::serde")]
pub struct LayoutTemplateFromYaml { pub struct LayoutTemplate {
pub direction: Direction, pub direction: Direction,
#[serde(default)] #[serde(default)]
pub borderless: bool, pub borderless: bool,
#[serde(default)] #[serde(default)]
pub parts: Vec<LayoutTemplateFromYaml>, pub parts: Vec<LayoutTemplate>,
#[serde(default)] #[serde(default)]
pub body: bool, pub body: bool,
pub split_size: Option<SplitSize>, pub split_size: Option<SplitSize>,
pub run: Option<Run>, pub run: Option<Run>,
} }
impl LayoutTemplateFromYaml { impl LayoutTemplate {
// Split the layout into parts that can be reassebled per tab // Insert an optional `[TabLayout]` at the correct postion
// returns the layout pre tab and the parts post tab pub fn insert_tab_layout(mut self, tab_layout: Option<TabLayout>) -> Self {
pub fn split_template( if self.body {
&self, return tab_layout.unwrap_or_default().into();
) -> 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 (i, part) in self.parts.clone().iter().enumerate() {
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 { if part.body {
post_tab = true; self.parts.push(tab_layout.unwrap_or_default().into());
// Leaf self.parts.swap_remove(i);
} else if post_tab { break;
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);
}
} }
// 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<TabLayout>) -> Vec<Self> {
tab_layout
.iter()
.map(|tab_layout| Self::from(tab_layout.to_owned()))
.collect()
} }
} }
@ -230,35 +203,6 @@ pub struct TabLayout {
pub run: Option<Run>, 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 { impl Layout {
pub fn total_terminal_panes(&self) -> usize { pub fn total_terminal_panes(&self) -> usize {
let mut total_panes = 0; let mut total_panes = 0;
@ -301,65 +245,6 @@ impl Layout {
split_space(space, self) 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) { pub fn merge_tab_layout(&mut self, tab: TabLayout) {
self.parts.push(tab.into()); self.parts.push(tab.into());
} }
@ -368,20 +253,6 @@ impl Layout {
self.parts.append(&mut parts); 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> { fn from_vec_tab_layout(tab_layout: Vec<TabLayout>) -> Vec<Self> {
tab_layout tab_layout
.iter() .iter()
@ -389,7 +260,7 @@ impl Layout {
.collect() .collect()
} }
fn from_vec_template_layout(layout_template: Vec<LayoutTemplateFromYaml>) -> Vec<Self> { fn from_vec_template_layout(layout_template: Vec<LayoutTemplate>) -> Vec<Self> {
layout_template layout_template
.iter() .iter()
.map(|layout_template| Layout::from(layout_template.to_owned())) .map(|layout_template| Layout::from(layout_template.to_owned()))
@ -555,21 +426,32 @@ impl From<TabLayout> for Layout {
Layout { Layout {
direction: tab.direction, direction: tab.direction,
borderless: tab.borderless, borderless: tab.borderless,
parts: Layout::from_vec_tab_layout(tab.parts), parts: Self::from_vec_tab_layout(tab.parts),
tabs: vec![],
split_size: tab.split_size, split_size: tab.split_size,
run: tab.run, run: tab.run,
} }
} }
} }
impl From<LayoutTemplateFromYaml> for Layout { impl From<TabLayout> for LayoutTemplate {
fn from(template: LayoutTemplateFromYaml) -> Self { 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<LayoutTemplate> for Layout {
fn from(template: LayoutTemplate) -> Self {
Layout { Layout {
direction: template.direction, direction: template.direction,
borderless: template.borderless, borderless: template.borderless,
parts: Layout::from_vec_template_layout(template.parts), parts: Self::from_vec_template_layout(template.parts),
tabs: vec![],
split_size: template.split_size, split_size: template.split_size,
run: template.run, 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. // The unit test location.
#[cfg(test)] #[cfg(test)]
#[path = "./unit/layout_test.rs"] #[path = "./unit/layout_test.rs"]

View file

@ -22,8 +22,6 @@ template:
split_size: split_size:
Percent: 23 Percent: 23
- direction: Vertical - direction: Vertical
split_size:
Percent: 77
body: true body: true
split_size: split_size:
Percent: 90 Percent: 90

View file

@ -0,0 +1,6 @@
---
tabs:
- direction: Vertical
parts:
- direction: Horizontal
- direction: Horizontal

View file

@ -0,0 +1,6 @@
---
template:
direction: Horizontal
parts:
- direction: Horizontal
body: true

View file

@ -23,44 +23,27 @@ fn default_layout_is_ok() {
fn default_layout_has_one_tab() { fn default_layout_has_one_tab() {
let path = default_layout_dir("default.yaml".into()); let path = default_layout_dir("default.yaml".into());
let layout = LayoutFromYaml::new(&path); 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); 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] #[test]
fn default_layout_merged_correctly() { fn default_layout_merged_correctly() {
let path = default_layout_dir("default.yaml".into()); let path = default_layout_dir("default.yaml".into());
let layout_from_yaml = LayoutFromYaml::new(&path); let layout_from_yaml = LayoutFromYaml::new(&path);
let layout_template = layout_from_yaml let layout_template = layout_from_yaml.as_ref().unwrap();
.as_ref() let tab_layout = layout_template
.unwrap() .template
.construct_layout_template(); .clone()
let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); .insert_tab_layout(Some(layout_template.tabs[0].clone()));
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![ parts: vec![
Layout { Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: true,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(1)), split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(Some("tab-bar".into()))), run: Some(Run::Plugin(Some("tab-bar".into()))),
}, },
@ -68,44 +51,37 @@ fn default_layout_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
Layout { Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: true,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(2)), split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(Some("status-bar".into()))), run: Some(Run::Plugin(Some("status-bar".into()))),
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
fn default_layout_new_tab_correct() { fn default_layout_new_tab_correct() {
let path = default_layout_dir("default.yaml".into()); let path = default_layout_dir("default.yaml".into());
let layout_from_yaml = LayoutFromYaml::new(&path); let layout_from_yaml = LayoutFromYaml::new(&path);
let layout_template = layout_from_yaml let layout_template = layout_from_yaml.as_ref().unwrap();
.as_ref() let tab_layout = layout_template.template.clone().insert_tab_layout(None);
.unwrap()
.construct_layout_template();
let tab_layout = layout_template.construct_tab_layout(None);
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![ parts: vec![
Layout { Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: true,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(1)), split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(Some("tab-bar".into()))), run: Some(Run::Plugin(Some("tab-bar".into()))),
}, },
@ -113,24 +89,21 @@ fn default_layout_new_tab_correct() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
Layout { Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: true,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(2)), split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(Some("status-bar".into()))), run: Some(Run::Plugin(Some("status-bar".into()))),
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
@ -151,32 +124,10 @@ fn default_disable_status_layout_is_ok() {
fn default_disable_status_layout_has_no_tab() { fn default_disable_status_layout_has_no_tab() {
let path = default_layout_dir("disable-status-bar.yaml".into()); let path = default_layout_dir("disable-status-bar.yaml".into());
let layout_from_yaml = LayoutFromYaml::new(&path); let layout_from_yaml = LayoutFromYaml::new(&path);
let layout_template = layout_from_yaml let layout_template = layout_from_yaml.as_ref().unwrap();
.as_ref()
.unwrap()
.construct_layout_template();
assert_eq!(layout_template.tabs.len(), 0); 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] #[test]
fn three_panes_with_tab_is_ok() { fn three_panes_with_tab_is_ok() {
let path = layout_test_dir("three-panes-with-tab.yaml".into()); 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() { fn three_panes_with_tab_has_one_tab() {
let path = layout_test_dir("three-panes-with-tab.yaml".into()); let path = layout_test_dir("three-panes-with-tab.yaml".into());
let layout = LayoutFromYaml::new(&path); 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); 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] #[test]
fn three_panes_with_tab_merged_correctly() { fn three_panes_with_tab_merged_correctly() {
let path = layout_test_dir("three-panes-with-tab.yaml".into()); let path = layout_test_dir("three-panes-with-tab.yaml".into());
let layout = LayoutFromYaml::new(&path); let layout = LayoutFromYaml::new(&path);
let layout_template = layout.as_ref().unwrap().construct_layout_template(); let layout_template = layout.as_ref().unwrap();
let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); let tab_layout = layout_template
.template
.clone()
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
@ -225,7 +163,6 @@ fn three_panes_with_tab_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -237,7 +174,6 @@ fn three_panes_with_tab_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -245,33 +181,29 @@ fn three_panes_with_tab_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}], }],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
fn three_panes_with_tab_new_tab_is_correct() { fn three_panes_with_tab_new_tab_is_correct() {
let path = layout_test_dir("three-panes-with-tab.yaml".into()); let path = layout_test_dir("three-panes-with-tab.yaml".into());
let layout = LayoutFromYaml::new(&path); let layout = LayoutFromYaml::new(&path);
let layout_template = layout.as_ref().unwrap().construct_layout_template(); let layout_template = layout.as_ref().unwrap();
let tab_layout = layout_template.construct_tab_layout(None); let tab_layout = layout_template.template.clone().insert_tab_layout(None);
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
@ -279,15 +211,13 @@ fn three_panes_with_tab_new_tab_is_correct() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}], }],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[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() { 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 path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into());
let layout = LayoutFromYaml::new(&path); 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); 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] #[test]
fn three_panes_with_tab_and_default_plugins_merged_correctly() { 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 path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into());
let layout = LayoutFromYaml::new(&path); let layout = LayoutFromYaml::new(&path);
let layout_template = layout.as_ref().unwrap().construct_layout_template(); let layout_template = layout.as_ref().unwrap();
let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); let tab_layout = layout_template
.template
.clone()
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
@ -335,7 +252,6 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(1)), split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(Some("tab-bar".into()))), 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, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -359,7 +274,6 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -367,17 +281,14 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
@ -385,24 +296,22 @@ fn three_panes_with_tab_and_default_plugins_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(2)), split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(Some("status-bar".into()))), run: Some(Run::Plugin(Some("status-bar".into()))),
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() { 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 path = layout_test_dir("three-panes-with-tab-and-default-plugins.yaml".into());
let layout = LayoutFromYaml::new(&path); let layout = LayoutFromYaml::new(&path);
let layout_template = layout.as_ref().unwrap().construct_layout_template(); let layout_template = layout.as_ref().unwrap();
let tab_layout = layout_template.construct_tab_layout(None); let tab_layout = layout_template.template.clone().insert_tab_layout(None);
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
@ -411,7 +320,6 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(1)), split_size: Some(SplitSize::Fixed(1)),
run: Some(Run::Plugin(Some("tab-bar".into()))), 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, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
@ -427,16 +334,14 @@ fn three_panes_with_tab_and_default_plugins_new_tab_is_correct() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Fixed(2)), split_size: Some(SplitSize::Fixed(2)),
run: Some(Run::Plugin(Some("status-bar".into()))), run: Some(Run::Plugin(Some("status-bar".into()))),
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
@ -450,32 +355,19 @@ fn deeply_nested_tab_is_ok() {
fn deeply_nested_tab_has_one_tab() { fn deeply_nested_tab_has_one_tab() {
let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); let path = layout_test_dir("deeply-nested-tab-layout.yaml".into());
let layout = LayoutFromYaml::new(&path); 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); 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] #[test]
fn deeply_nested_tab_merged_correctly() { fn deeply_nested_tab_merged_correctly() {
let path = layout_test_dir("deeply-nested-tab-layout.yaml".into()); let path = layout_test_dir("deeply-nested-tab-layout.yaml".into());
let layout = LayoutFromYaml::new(&path); let layout = LayoutFromYaml::new(&path);
let layout_template = layout.as_ref().unwrap().construct_layout_template(); let layout_template = layout.as_ref().unwrap();
let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); let tab_layout = layout_template
.template
.clone()
.insert_tab_layout(Some(layout_template.tabs[0].clone()));
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
@ -488,7 +380,6 @@ fn deeply_nested_tab_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(21)), split_size: Some(SplitSize::Percent(21)),
run: None, run: None,
}, },
@ -500,48 +391,43 @@ fn deeply_nested_tab_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(22)), split_size: Some(SplitSize::Percent(22)),
run: None, run: None,
}, },
Layout { Layout {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![Layout { parts: vec![
direction: Direction::Horizontal, Layout {
borderless: false, direction: Direction::Horizontal,
parts: vec![], borderless: false,
tabs: vec![], parts: vec![],
split_size: Some(SplitSize::Percent(23)), split_size: Some(SplitSize::Percent(23)),
run: None, run: None,
}], },
tabs: vec![], Layout {
direction: Direction::Horizontal,
borderless: false,
parts: vec![],
split_size: Some(SplitSize::Percent(24)),
run: None,
},
],
split_size: Some(SplitSize::Percent(78)), split_size: Some(SplitSize::Percent(78)),
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: Some(SplitSize::Percent(79)), split_size: Some(SplitSize::Percent(79)),
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: Some(SplitSize::Percent(90)), split_size: Some(SplitSize::Percent(90)),
run: None, run: None,
}, },
Layout {
direction: Direction::Horizontal,
borderless: false,
parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(24)),
run: None,
},
Layout { Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(15)), split_size: Some(SplitSize::Percent(15)),
run: None, run: None,
}, },
@ -549,7 +435,6 @@ fn deeply_nested_tab_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(15)), split_size: Some(SplitSize::Percent(15)),
run: None, run: None,
}, },
@ -557,16 +442,14 @@ fn deeply_nested_tab_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(15)), split_size: Some(SplitSize::Percent(15)),
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
@ -580,27 +463,19 @@ fn three_tabs_is_ok() {
fn three_tabs_has_three_tabs() { fn three_tabs_has_three_tabs() {
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
let layout_from_yaml = LayoutFromYaml::new(&path); 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); 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] #[test]
fn three_tabs_tab_one_merged_correctly() { fn three_tabs_tab_one_merged_correctly() {
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
let layout_from_yaml = LayoutFromYaml::new(&path); let layout_from_yaml = LayoutFromYaml::new(&path);
let layout_template = layout_from_yaml let layout_template = layout_from_yaml.as_ref().unwrap();
.as_ref() let tab_layout = layout_template
.unwrap() .template
.construct_layout_template(); .clone()
let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[0].clone())); .insert_tab_layout(Some(layout_template.tabs[0].clone()));
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
@ -609,7 +484,6 @@ fn three_tabs_tab_one_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -617,28 +491,26 @@ fn three_tabs_tab_one_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
fn three_tabs_tab_two_merged_correctly() { fn three_tabs_tab_two_merged_correctly() {
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
let layout_from_yaml = LayoutFromYaml::new(&path); let layout_from_yaml = LayoutFromYaml::new(&path);
let layout_template = layout_from_yaml let layout_template = layout_from_yaml.as_ref().unwrap();
.as_ref() let tab_layout = layout_template
.unwrap() .template
.construct_layout_template(); .clone()
let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[1].clone())); .insert_tab_layout(Some(layout_template.tabs[1].clone()));
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
@ -651,7 +523,6 @@ fn three_tabs_tab_two_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -659,12 +530,10 @@ fn three_tabs_tab_two_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -672,25 +541,26 @@ fn three_tabs_tab_two_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}; };
assert_eq!(merged_layout, tab_layout); assert_eq!(merged_layout, tab_layout.into());
} }
#[test] #[test]
fn three_tabs_tab_three_merged_correctly() { fn three_tabs_tab_three_merged_correctly() {
let path = layout_test_dir("three-tabs-merged-correctly.yaml".into()); let path = layout_test_dir("three-tabs-merged-correctly.yaml".into());
let layout = LayoutFromYaml::new(&path); let layout = LayoutFromYaml::new(&path);
let layout_template = layout.as_ref().unwrap().construct_layout_template(); let layout_template = layout.as_ref().unwrap();
let tab_layout = layout_template.construct_tab_layout(Some(layout_template.tabs[2].clone())); let tab_layout = layout_template
.template
.clone()
.insert_tab_layout(Some(layout_template.tabs[2].clone()));
let merged_layout = Layout { let merged_layout = Layout {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
@ -703,7 +573,6 @@ fn three_tabs_tab_three_merged_correctly() {
direction: Direction::Vertical, direction: Direction::Vertical,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -711,12 +580,10 @@ fn three_tabs_tab_three_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: Some(SplitSize::Percent(50)), split_size: Some(SplitSize::Percent(50)),
run: None, run: None,
}, },
@ -724,14 +591,106 @@ fn three_tabs_tab_three_merged_correctly() {
direction: Direction::Horizontal, direction: Direction::Horizontal,
borderless: false, borderless: false,
parts: vec![], parts: vec![],
tabs: vec![],
split_size: None, split_size: None,
run: None, run: None,
}, },
], ],
tabs: vec![],
split_size: None, split_size: None,
run: 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());
} }

View file

@ -3,7 +3,7 @@
use crate::{ use crate::{
cli::CliArgs, cli::CliArgs,
errors::{get_current_ctx, ErrorContext}, errors::{get_current_ctx, ErrorContext},
input::{actions::Action, layout::LayoutTemplate, options::Options}, input::{actions::Action, layout::LayoutFromYaml, options::Options},
pane_size::PositionAndSize, pane_size::PositionAndSize,
}; };
use interprocess::local_socket::LocalSocketStream; use interprocess::local_socket::LocalSocketStream;
@ -62,7 +62,7 @@ pub enum ClientToServerMsg {
ClientAttributes, ClientAttributes,
Box<CliArgs>, Box<CliArgs>,
Box<Options>, Box<Options>,
Option<LayoutTemplate>, Option<LayoutFromYaml>,
), ),
AttachClient(ClientAttributes, bool, Options), AttachClient(ClientAttributes, bool, Options),
Action(Action), Action(Action),

View file

@ -6,7 +6,7 @@ use crate::{
}, },
input::{ input::{
config::{Config, ConfigError}, config::{Config, ConfigError},
layout::{LayoutFromYaml, LayoutTemplate}, layout::LayoutFromYaml,
options::Options, options::Options,
}, },
}; };
@ -153,7 +153,7 @@ impl Setup {
/// 2. config options (`config.yaml`) /// 2. config options (`config.yaml`)
pub fn from_options( pub fn from_options(
opts: &CliArgs, opts: &CliArgs,
) -> Result<(Config, Option<LayoutTemplate>, Options), ConfigError> { ) -> Result<(Config, Option<LayoutFromYaml>, Options), ConfigError> {
let clean = match &opts.command { let clean = match &opts.command {
Some(Command::Setup(ref setup)) => setup.clean, Some(Command::Setup(ref setup)) => setup.clean,
_ => false, _ => false,
@ -187,8 +187,8 @@ impl Setup {
Some(Err(e)) => { Some(Err(e)) => {
return Err(e); return Err(e);
} }
} };
.map(|layout| layout.construct_layout_template()); //.map(|layout| layout.template);
if let Some(Command::Setup(ref setup)) = &opts.command { if let Some(Command::Setup(ref setup)) = &opts.command {
setup.from_cli(opts, &config_options).map_or_else( setup.from_cli(opts, &config_options).map_or_else(