feat(layout): specify only tab name in tabs section (#722)

Allow specifying only the tab name in the `tabs` section

- For example this is now possible:
```
tabs:
  - name: first
    parts:
      - direction: Vertical
      - direction: Vertical
  - name: second
  - name: third
```
  For that the tab section defaults the direction to
  `direction::Horizontal`

- Adds an error upon specifying a tab name inside the `parts` section
  of the tab-layout
This commit is contained in:
a-kenji 2021-09-21 16:39:37 +02:00 committed by GitHub
parent 71b600b821
commit bbe2583904
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 69 deletions

View file

@ -45,9 +45,8 @@ pub enum ConfigError {
IoPath(io::Error, PathBuf), IoPath(io::Error, PathBuf),
// Internal Deserialization Error // Internal Deserialization Error
FromUtf8(std::string::FromUtf8Error), FromUtf8(std::string::FromUtf8Error),
// Missing the tab section in the layout. // Naming a part in a tab is unsupported
Layout(LayoutMissingTabSectionError), LayoutNameInTab(LayoutNameInTabError),
LayoutPartAndTab(LayoutPartAndTabError),
} }
impl Default for Config { impl Default for Config {
@ -139,70 +138,32 @@ impl Config {
// TODO: Split errors up into separate modules // TODO: Split errors up into separate modules
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LayoutMissingTabSectionError; pub struct LayoutNameInTabError;
#[derive(Debug, Clone)]
pub struct LayoutPartAndTabError;
impl fmt::Display for LayoutMissingTabSectionError { impl fmt::Display for LayoutNameInTabError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(
f, f,
"MissingTabSectionError: "LayoutNameInTabError:
There needs to be exactly one `tabs` section specified in the layout file, for example: The `parts` inside the `tabs` can't be named. For example:
--- ---
direction: Horizontal
parts:
- direction: Vertical
- direction: Vertical
tabs: tabs:
- direction: Vertical - direction: Vertical
name: main
parts:
- direction: Vertical
name: section # <== The part section can't be named.
- direction: Vertical - direction: Vertical
- direction: Vertical - direction: Vertical
name: test
" "
) )
} }
} }
impl std::error::Error for LayoutMissingTabSectionError { impl std::error::Error for LayoutNameInTabError {
fn description(&self) -> &str { fn description(&self) -> &str {
"One tab must be specified per Layout." "The `parts` inside the `tabs` can't be named."
}
}
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."
} }
} }
@ -215,10 +176,7 @@ impl Display for ConfigError {
} }
ConfigError::Serde(ref err) => write!(formatter, "Deserialization error: {}", err), ConfigError::Serde(ref err) => write!(formatter, "Deserialization error: {}", err),
ConfigError::FromUtf8(ref err) => write!(formatter, "FromUtf8Error: {}", err), ConfigError::FromUtf8(ref err) => write!(formatter, "FromUtf8Error: {}", err),
ConfigError::Layout(ref err) => { ConfigError::LayoutNameInTab(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) write!(formatter, "There was an error in the layout file, {}", err)
} }
} }
@ -232,8 +190,7 @@ impl std::error::Error for ConfigError {
ConfigError::IoPath(ref err, _) => Some(err), ConfigError::IoPath(ref err, _) => Some(err),
ConfigError::Serde(ref err) => Some(err), ConfigError::Serde(ref err) => Some(err),
ConfigError::FromUtf8(ref err) => Some(err), ConfigError::FromUtf8(ref err) => Some(err),
ConfigError::Layout(ref err) => Some(err), ConfigError::LayoutNameInTab(ref err) => Some(err),
ConfigError::LayoutPartAndTab(ref err) => Some(err),
} }
} }
} }
@ -256,15 +213,9 @@ impl From<std::string::FromUtf8Error> for ConfigError {
} }
} }
impl From<LayoutMissingTabSectionError> for ConfigError { impl From<LayoutNameInTabError> for ConfigError {
fn from(err: LayoutMissingTabSectionError) -> ConfigError { fn from(err: LayoutNameInTabError) -> ConfigError {
ConfigError::Layout(err) ConfigError::LayoutNameInTab(err)
}
}
impl From<LayoutPartAndTabError> for ConfigError {
fn from(err: LayoutPartAndTabError) -> ConfigError {
ConfigError::LayoutPartAndTab(err)
} }
} }

View file

@ -9,7 +9,10 @@
// If plugins should be able to depend on the layout system // If plugins should be able to depend on the layout system
// then [`zellij-utils`] could be a proper place. // then [`zellij-utils`] could be a proper place.
use crate::{ use crate::{
input::{command::RunCommand, config::ConfigError}, input::{
command::RunCommand,
config::{ConfigError, LayoutNameInTabError},
},
pane_size::{Dimension, PaneGeom}, pane_size::{Dimension, PaneGeom},
setup, setup,
}; };
@ -106,7 +109,12 @@ impl LayoutFromYaml {
let layout: Option<LayoutFromYaml> = serde_yaml::from_str(&layout)?; let layout: Option<LayoutFromYaml> = serde_yaml::from_str(&layout)?;
match layout { match layout {
Some(layout) => Ok(layout), Some(layout) => {
for tab in layout.tabs.clone() {
tab.check()?;
}
Ok(layout)
}
None => Ok(LayoutFromYaml::default()), None => Ok(LayoutFromYaml::default()),
} }
} }
@ -220,6 +228,7 @@ impl LayoutTemplate {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(crate = "self::serde")] #[serde(crate = "self::serde")]
pub struct TabLayout { pub struct TabLayout {
#[serde(default)]
pub direction: Direction, pub direction: Direction,
#[serde(default)] #[serde(default)]
pub borderless: bool, pub borderless: bool,
@ -231,6 +240,18 @@ pub struct TabLayout {
pub name: String, pub name: String,
} }
impl TabLayout {
fn check(&self) -> Result<TabLayout, ConfigError> {
for part in self.parts.iter() {
part.check()?;
if !part.name.is_empty() {
return Err(ConfigError::LayoutNameInTab(LayoutNameInTabError));
}
}
Ok(self.clone())
}
}
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;
@ -467,6 +488,12 @@ impl Default for LayoutFromYaml {
} }
} }
impl Default for Direction {
fn default() -> Self {
Direction::Horizontal
}
}
// The unit test location. // The unit test location.
#[cfg(test)] #[cfg(test)]
#[path = "./unit/layout_test.rs"] #[path = "./unit/layout_test.rs"]