use {
lazy_regex::*,
serde::Deserialize,
std::str::FromStr,
};
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(transparent)]
pub struct LayoutInstructions {
pub instructions: Vec<LayoutInstruction>,
}
#[derive(Debug, Clone, Copy, Deserialize)]
#[serde(untagged)]
pub enum LayoutInstruction {
Clear, MoveDivider { divider: usize, dx: i16 },
SetPanelWidth { panel: usize, width: u16 },
}
#[derive(Debug, Clone, Copy)]
pub struct MoveDividerArgs {
pub divider: usize,
pub dx: i16,
}
impl FromStr for MoveDividerArgs {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some((_, divider, dx)) = regex_captures!(r"^\s*(\d)\s+(-?\d{1,3})\s*$", s) {
Ok(Self {
divider: divider.parse().unwrap(),
dx: dx.parse().unwrap(),
})
} else {
Err("not the expected move_divider args")
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct SetPanelWidthArgs {
pub panel: usize,
pub width: u16,
}
impl FromStr for SetPanelWidthArgs {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some((_, panel, width)) = regex_captures!(r"^\s*(\d)\s+(\d{1,4})\s*$", s) {
Ok(Self {
panel: panel.parse().unwrap(),
width: width.parse().unwrap(),
})
} else {
Err("not the expected set_panel_width args")
}
}
}
impl LayoutInstruction {
pub fn is_moving_divider(
self,
idx: usize,
) -> bool {
match self {
Self::MoveDivider { divider, .. } => divider == idx,
_ => false,
}
}
}
impl LayoutInstructions {
pub fn push(
&mut self,
new_instruction: LayoutInstruction,
) {
use LayoutInstruction::*;
match new_instruction {
Clear => {
self.instructions.clear();
}
SetPanelWidth {
panel: new_panel, ..
} => {
self.instructions.retain(|i| match i {
SetPanelWidth { panel, .. } => *panel != new_panel,
_ => true,
});
}
MoveDivider {
divider: new_divider,
dx: new_dx,
} => {
if let Some(MoveDivider { divider, dx }) = self.instructions.last_mut() {
if *divider == new_divider {
*dx += new_dx;
return;
}
}
}
}
self.instructions.push(new_instruction);
}
}