diff options
author | Aram Drevekenin <aram@poor.dev> | 2023-02-17 11:17:48 +0100 |
---|---|---|
committer | Aram Drevekenin <aram@poor.dev> | 2023-02-17 11:17:48 +0100 |
commit | 2ba33eacd27ab7dc4e6b1f939f36102ac39ce541 (patch) | |
tree | ec026802bea551ce047cb40a9553167fb4669388 /2 | |
parent | 0bbba005602ebf6c41fa54525933b60207b476da (diff) |
chore(repo): remove garbage fileapply-layouts-at-runtime
Diffstat (limited to '2')
-rw-r--r-- | 2 | 1838 |
1 files changed, 0 insertions, 1838 deletions
@@ -1,1838 +0,0 @@ -use crate::input::{ - command::RunCommand, - config::ConfigError, - layout::{ - FloatingPaneLayout, Layout, TiledPaneLayout, PercentOrFixed, Run, RunPlugin, RunPluginLocation, - SplitDirection, SplitSize, - }, -}; - -use kdl::*; - -use std::collections::{HashMap, HashSet}; -use std::str::FromStr; - -use crate::{ - kdl_child_with_name, kdl_children_nodes, kdl_get_bool_property_or_child_value, - kdl_get_bool_property_or_child_value_with_error, kdl_get_child, - kdl_get_int_property_or_child_value, kdl_get_property_or_child, - kdl_get_string_property_or_child_value, kdl_get_string_property_or_child_value_with_error, - kdl_name, kdl_parsing_error, kdl_property_names, kdl_property_or_child_value_node, - kdl_string_arguments, -}; - -use std::convert::TryFrom; -use std::path::PathBuf; -use std::vec::Vec; -use url::Url; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum PaneOrFloatingPane { - Pane(TiledPaneLayout), - FloatingPane(FloatingPaneLayout), - Either(TiledPaneLayout), -} - -pub struct KdlLayoutParser<'a> { - global_cwd: Option<PathBuf>, - raw_layout: &'a str, - tab_templates: HashMap<String, (TiledPaneLayout, Vec<FloatingPaneLayout>, KdlNode)>, - pane_templates: HashMap<String, (PaneOrFloatingPane, KdlNode)>, - default_tab_template: Option<(TiledPaneLayout, Vec<FloatingPaneLayout>, KdlNode)>, -} - -impl<'a> KdlLayoutParser<'a> { - pub fn new(raw_layout: &'a str, global_cwd: Option<PathBuf>) -> Self { - KdlLayoutParser { - raw_layout, - tab_templates: HashMap::new(), - pane_templates: HashMap::new(), - default_tab_template: None, - global_cwd, - } - } - fn is_a_reserved_word(&self, word: &str) -> bool { - word == "pane" - || word == "layout" - || word == "pane_template" - || word == "tab_template" - || word == "default_tab_template" - || word == "command" - || word == "edit" - || word == "plugin" - || word == "children" - || word == "tab" - || word == "args" - || word == "close_on_exit" - || word == "start_suspended" - || word == "borderless" - || word == "focus" - || word == "name" - || word == "size" - || word == "cwd" - || word == "split_direction" - } - fn is_a_valid_pane_property(&self, property_name: &str) -> bool { - property_name == "borderless" - || property_name == "focus" - || property_name == "name" - || property_name == "size" - || property_name == "plugin" - || property_name == "command" - || property_name == "edit" - || property_name == "cwd" - || property_name == "args" - || property_name == "close_on_exit" - || property_name == "start_suspended" - || property_name == "split_direction" - || property_name == "pane" - || property_name == "children" - } - fn is_a_valid_floating_pane_property(&self, property_name: &str) -> bool { - property_name == "borderless" - || property_name == "focus" - || property_name == "name" - || property_name == "plugin" - || property_name == "command" - || property_name == "edit" - || property_name == "cwd" - || property_name == "args" - || property_name == "close_on_exit" - || property_name == "start_suspended" - || property_name == "x" - || property_name == "y" - || property_name == "width" - || property_name == "height" - } - fn is_a_valid_tab_property(&self, property_name: &str) -> bool { - property_name == "focus" - || property_name == "name" - || property_name == "split_direction" - || property_name == "cwd" - || property_name == "floating_panes" - } - fn assert_legal_node_name(&self, name: &str, kdl_node: &KdlNode) -> Result<(), ConfigError> { - if name.contains(char::is_whitespace) { - Err(ConfigError::new_layout_kdl_error( - format!("Node names ({}) cannot contain whitespace.", name), - kdl_node.span().offset(), - kdl_node.span().len(), - )) - } else if self.is_a_reserved_word(&name) { - Err(ConfigError::new_layout_kdl_error( - format!("Node name '{}' is a reserved word.", name), - kdl_node.span().offset(), - kdl_node.span().len(), - )) - } else { - Ok(()) - } - } - fn assert_legal_template_name( - &self, - name: &str, - kdl_node: &KdlNode, - ) -> Result<(), ConfigError> { - if name.is_empty() { - Err(ConfigError::new_layout_kdl_error( - format!("Template names cannot be empty"), - kdl_node.span().offset(), - kdl_node.span().len(), - )) - } else if name.contains(')') || name.contains('(') { - Err(ConfigError::new_layout_kdl_error( - format!("Template names cannot contain parantheses"), - kdl_node.span().offset(), - kdl_node.span().len(), - )) - } else if name - .chars() - .next() - .map(|first_char| first_char.is_numeric()) - .unwrap_or(false) - { - Err(ConfigError::new_layout_kdl_error( - format!("Template names cannot start with numbers"), - kdl_node.span().offset(), - kdl_node.span().len(), - )) - } else { - Ok(()) - } - } - fn parse_split_size(&self, kdl_node: &KdlNode) -> Result<Option<SplitSize>, ConfigError> { - if let Some(size) = kdl_get_string_property_or_child_value!(kdl_node, "size") { - match SplitSize::from_str(size) { - Ok(size) => Ok(Some(size)), - Err(_e) => Err(kdl_parsing_error!( - format!( - "size should be a fixed number (eg. 1) or a quoted percent (eg. \"50%\")" - ), - kdl_node - )), - } - } else if let Some(size) = kdl_get_int_property_or_child_value!(kdl_node, "size") { - if size == 0 { - return Err(kdl_parsing_error!( - format!("size should be greater than 0"), - kdl_node - )); - } - Ok(Some(SplitSize::Fixed(size as usize))) - } else if let Some(node) = kdl_property_or_child_value_node!(kdl_node, "size") { - Err(kdl_parsing_error!( - format!("size should be a fixed number (eg. 1) or a quoted percent (eg. \"50%\")"), - node - )) - } else if let Some(node) = kdl_child_with_name!(kdl_node, "size") { - Err(kdl_parsing_error!( - format!( - "size cannot be bare, it should have a value (eg. 'size 1', or 'size \"50%\"')" - ), - node - )) - } else { - Ok(None) - } - } - fn parse_percent_or_fixed( - &self, - kdl_node: &KdlNode, - value_name: &str, - can_be_zero: bool, - ) -> Result<Option<PercentOrFixed>, ConfigError> { - if let Some(size) = kdl_get_string_property_or_child_value!(kdl_node, value_name) { - match PercentOrFixed::from_str(size) { - Ok(size) => { - if !can_be_zero && size.is_zero() { - Err(kdl_parsing_error!( - format!("{} should be greater than 0", value_name), - kdl_node - )) - } else { - Ok(Some(size)) - } - }, - Err(_e) => Err(kdl_parsing_error!( - format!( - "{} should be a fixed number (eg. 1) or a quoted percent (eg. \"50%\")", - value_name - ), - kdl_node - )), - } - } else if let Some(size) = kdl_get_int_property_or_child_value!(kdl_node, value_name) { - if size == 0 && !can_be_zero { - return Err(kdl_parsing_error!( - format!("{} should be greater than 0", value_name), - kdl_node - )); - } - Ok(Some(PercentOrFixed::Fixed(size as usize))) - } else if let Some(node) = kdl_property_or_child_value_node!(kdl_node, "size") { - Err(kdl_parsing_error!( - format!( - "{} should be a fixed number (eg. 1) or a quoted percent (eg. \"50%\")", - value_name - ), - node - )) - } else if let Some(node) = kdl_child_with_name!(kdl_node, "size") { - Err(kdl_parsing_error!( - format!( - "{} cannot be bare, it should have a value (eg. 'size 1', or 'size \"50%\"')", - value_name - ), - node - )) - } else { - Ok(None) - } - } - fn parse_plugin_block(&self, plugin_block: &KdlNode) -> Result<Option<Run>, ConfigError> { - let _allow_exec_host_cmd = - kdl_get_bool_property_or_child_value_with_error!(plugin_block, "_allow_exec_host_cmd") - .unwrap_or(false); - let string_url = - kdl_get_string_property_or_child_value_with_error!(plugin_block, "location").ok_or( - ConfigError::new_layout_kdl_error( - "Plugins must have a location".into(), - plugin_block.span().offset(), - plugin_block.span().len(), - ), - )?; - let url_node = kdl_get_property_or_child!(plugin_block, "location").ok_or( - ConfigError::new_layout_kdl_error( - "Plugins must have a location".into(), - plugin_block.span().offset(), - plugin_block.span().len(), - ), - )?; - let url = Url::parse(string_url).map_err(|e| { - ConfigError::new_layout_kdl_error( - format!("Failed to parse url: {:?}", e), - url_node.span().offset(), - url_node.span().len(), - ) - })?; - let location = RunPluginLocation::try_from(url)?; - Ok(Some(Run::Plugin(RunPlugin { - _allow_exec_host_cmd, - location, - }))) - } - fn parse_args(&self, pane_node: &KdlNode) -> Result<Option<Vec<String>>, ConfigError> { - match kdl_get_child!(pane_node, "args") { - Some(kdl_args) => { - if kdl_args.entries().is_empty() { - return Err(kdl_parsing_error!(format!("args cannot be empty and should contain one or more command arguments (eg. args \"-h\" \"-v\")"), kdl_args)); - } - Ok(Some( - kdl_string_arguments!(kdl_args) - .iter() - .map(|s| String::from(*s)) - .collect(), - )) - }, - None => Ok(None), - } - } - fn cwd_prefix(&self, tab_cwd: Option<&PathBuf>) -> Result<Option<PathBuf>, ConfigError> { - Ok(match (&self.global_cwd, tab_cwd) { - (Some(global_cwd), Some(tab_cwd)) => Some(global_cwd.join(tab_cwd)), - (None, Some(tab_cwd)) => Some(tab_cwd.clone()), - (Some(global_cwd), None) => Some(global_cwd.clone()), - (None, None) => None, - }) - } - fn parse_cwd(&self, kdl_node: &KdlNode) -> Result<Option<PathBuf>, ConfigError> { - Ok( - kdl_get_string_property_or_child_value_with_error!(kdl_node, "cwd") - .map(|cwd| PathBuf::from(cwd)), - ) - } - fn parse_pane_command( - &self, - pane_node: &KdlNode, - is_template: bool, - ) -> Result<Option<Run>, ConfigError> { - let command = kdl_get_string_property_or_child_value_with_error!(pane_node, "command") - .map(|c| PathBuf::from(c)); - let edit = kdl_get_string_property_or_child_value_with_error!(pane_node, "edit") - .map(|c| PathBuf::from(c)); - let cwd = self.parse_cwd(pane_node)?; - let args = self.parse_args(pane_node)?; - let close_on_exit = - kdl_get_bool_property_or_child_value_with_error!(pane_node, "close_on_exit"); - let start_suspended = - kdl_get_bool_property_or_child_value_with_error!(pane_node, "start_suspended"); - if !is_template { - self.assert_no_bare_attributes_in_pane_node( - &command, - &args, - &close_on_exit, - &start_suspended, - pane_node, - )?; - } - let hold_on_close = close_on_exit.map(|c| !c).unwrap_or(true); - let hold_on_start = start_suspended.map(|c| c).unwrap_or(false); - match (command, edit, cwd) { - (None, None, Some(cwd)) => Ok(Some(Run::Cwd(cwd))), - (Some(command), None, cwd) => Ok(Some(Run::Command(RunCommand { - command, - args: args.unwrap_or_else(|| vec![]), - cwd, - hold_on_close, - hold_on_start, - }))), - (None, Some(edit), Some(cwd)) => Ok(Some(Run::EditFile(cwd.join(edit), None))), - (None, Some(edit), None) => Ok(Some(Run::EditFile(edit, None))), - (Some(_command), Some(_edit), _) => Err(ConfigError::new_layout_kdl_error( - "cannot have both a command and an edit instruction for the same pane".into(), - pane_node.span().offset(), - pane_node.span().len(), - )), - _ => Ok(None), - } - } - fn parse_command_plugin_or_edit_block( - &self, - kdl_node: &KdlNode, - ) -> Result<Option<Run>, ConfigError> { - let mut run = self.parse_pane_command(kdl_node, false)?; - if let Some(plugin_block) = kdl_get_child!(kdl_node, "plugin") { - let has_non_cwd_run_prop = run - .map(|r| match r { - Run::Cwd(_) => false, - _ => true, - }) - .unwrap_or(false); - if has_non_cwd_run_prop { - return Err(ConfigError::new_layout_kdl_error( - "Cannot have both a command/edit and a plugin block for a single pane".into(), - plugin_block.span().offset(), - plugin_block.span().len(), - )); - } - run = self.parse_plugin_block(plugin_block)?; - } - Ok(run) - } - fn parse_command_plugin_or_edit_block_for_template( - &self, - kdl_node: &KdlNode, - ) -> Result<Option<Run>, ConfigError> { - let mut run = self.parse_pane_command(kdl_node, true)?; - if let Some(plugin_block) = kdl_get_child!(kdl_node, "plugin") { - let has_non_cwd_run_prop = run - .map(|r| match r { - Run::Cwd(_) => false, - _ => true, - }) - .unwrap_or(false); - if has_non_cwd_run_prop { - return Err(ConfigError::new_layout_kdl_error( - "Cannot have both a command/edit and a plugin block for a single pane".into(), - plugin_block.span().offset(), - plugin_block.span().len(), - )); - } - run = self.parse_plugin_block(plugin_block)?; - } - Ok(run) - } - fn parse_pane_node(&self, kdl_node: &KdlNode) -> Result<TiledPaneLayout, ConfigError> { - self.assert_valid_pane_properties(kdl_node)?; - let borderless = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless"); - let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); - let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") - .map(|name| name.to_string()); - let split_size = self.parse_split_size(kdl_node)?; - let run = self.parse_command_plugin_or_edit_block(kdl_node)?; - let children_split_direction = self.parse_split_direction(kdl_node)?; - let (external_children_index, children) = match kdl_children_nodes!(kdl_node) { - Some(children) => self.parse_child_pane_nodes_for_pane(&children)?, - None => (None, vec![]), - }; - self.assert_no_mixed_children_and_properties(kdl_node)?; - Ok(TiledPaneLayout { - borderless: borderless.unwrap_or_default(), - focus, - name, - split_size, - run, - children_split_direction, - external_children_index, - children, - ..Default::default() - }) - } - fn parse_floating_pane_node( - &self, - kdl_node: &KdlNode, - ) -> Result<FloatingPaneLayout, ConfigError> { - self.assert_valid_floating_pane_properties(kdl_node)?; - let height = self.parse_percent_or_fixed(kdl_node, "height", false)?; - let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; - let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; - let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; - let run = self.parse_command_plugin_or_edit_block(kdl_node)?; - let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); - let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") - .map(|name| name.to_string()); - self.assert_no_mixed_children_and_properties(kdl_node)?; - Ok(FloatingPaneLayout { - name, - height, - width, - x, - y, - run, - focus, - ..Default::default() - }) - } - fn insert_children_to_pane_template( - &self, - kdl_node: &KdlNode, - pane_template: &mut TiledPaneLayout, - pane_template_kdl_node: &KdlNode, - ) -> Result<(), ConfigError> { - let children_split_direction = self.parse_split_direction(kdl_node)?; - let (external_children_index, pane_parts) = match kdl_children_nodes!(kdl_node) { - Some(children) => self.parse_child_pane_nodes_for_pane(&children)?, - None => (None, vec![]), - }; - if pane_parts.len() > 0 { - let child_panes_layout = TiledPaneLayout { - children_split_direction, - children: pane_parts, - external_children_index, - ..Default::default() - }; - self.assert_one_children_block(&pane_template, pane_template_kdl_node)?; - self.insert_layout_children_or_error( - pane_template, - child_panes_layout, - pane_template_kdl_node, - )?; - } - Ok(()) - } - fn parse_pane_node_with_template( - &self, - kdl_node: &KdlNode, - pane_template: PaneOrFloatingPane, - pane_template_kdl_node: &KdlNode, - ) -> Result<TiledPaneLayout, ConfigError> { - match pane_template { - PaneOrFloatingPane::Pane(mut pane_template) - | PaneOrFloatingPane::Either(mut pane_template) => { - let borderless = - kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless"); - let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); - let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") - .map(|name| name.to_string()); - let args = self.parse_args(kdl_node)?; - let close_on_exit = - kdl_get_bool_property_or_child_value_with_error!(kdl_node, "close_on_exit"); - let start_suspended = - kdl_get_bool_property_or_child_value_with_error!(kdl_node, "start_suspended"); - let split_size = self.parse_split_size(kdl_node)?; - let run = self.parse_command_plugin_or_edit_block_for_template(kdl_node)?; - self.assert_no_bare_attributes_in_pane_node_with_template( - &run, - &pane_template.run, - &args, - &close_on_exit, - &start_suspended, - kdl_node, - )?; - self.insert_children_to_pane_template( - kdl_node, - &mut pane_template, - pane_template_kdl_node, - )?; - pane_template.run = Run::merge(&pane_template.run, &run); - if let Some(pane_template_run_command) = pane_template.run.as_mut() { - // we need to do this because panes consuming a pane_template - // can have bare args without a command - pane_template_run_command.add_args(args); - pane_template_run_command.add_close_on_exit(close_on_exit); - pane_template_run_command.add_start_suspended(start_suspended); - }; - if let Some(borderless) = borderless { - pane_template.borderless = borderless; - } - if let Some(focus) = focus { - pane_template.focus = Some(focus); - } - if let Some(name) = name { - pane_template.name = Some(name); - } - if let Some(split_size) = split_size { - pane_template.split_size = Some(split_size); - } - if let Some(index_of_children) = pane_template.external_children_index { - pane_template - .children - .insert(index_of_children, TiledPaneLayout::default()); - } - pane_template.external_children_index = None; - Ok(pane_template) - }, - PaneOrFloatingPane::FloatingPane(_) => { - let pane_template_name = kdl_get_string_property_or_child_value_with_error!( - pane_template_kdl_node, - "name" - ) - .map(|name| name.to_string()); - Err(ConfigError::new_layout_kdl_error( - format!("pane_template {}, is a floating pane template (derived from its properties) and cannot be applied to a tiled pane", pane_template_name.unwrap_or("".into())), - kdl_node.span().offset(), - kdl_node.span().len(), - )) - }, - } - } - fn parse_floating_pane_node_with_template( - &self, - kdl_node: &KdlNode, - pane_template: PaneOrFloatingPane, - pane_template_kdl_node: &KdlNode, - ) -> Result<FloatingPaneLayout, ConfigError> { - match pane_template { - PaneOrFloatingPane::Pane(_) => { - let pane_template_name = kdl_get_string_property_or_child_value_with_error!( - pane_template_kdl_node, - "name" - ) - .map(|name| name.to_string()); - Err(ConfigError::new_layout_kdl_error( - format!("pane_template {}, is a non-floating pane template (derived from its properties) and cannot be applied to a floating pane", pane_template_name.unwrap_or("".into())), - kdl_node.span().offset(), - kdl_node.span().len(), - )) - }, - PaneOrFloatingPane::FloatingPane(mut pane_template) => { - let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); - let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") - .map(|name| name.to_string()); - let args = self.parse_args(kdl_node)?; - let close_on_exit = - kdl_get_bool_property_or_child_value_with_error!(kdl_node, "close_on_exit"); - let start_suspended = - kdl_get_bool_property_or_child_value_with_error!(kdl_node, "start_suspended"); - let run = self.parse_command_plugin_or_edit_block_for_template(kdl_node)?; - self.assert_no_bare_attributes_in_pane_node_with_template( - &run, - &pane_template.run, - &args, - &close_on_exit, - &start_suspended, - kdl_node, - )?; - pane_template.run = Run::merge(&pane_template.run, &run); - if let Some(pane_template_run_command) = pane_template.run.as_mut() { - // we need to do this because panes consuming a pane_template - // can have bare args without a command - pane_template_run_command.add_args(args); - pane_template_run_command.add_close_on_exit(close_on_exit); - pane_template_run_command.add_start_suspended(start_suspended); - }; - if let Some(focus) = focus { - pane_template.focus = Some(focus); - } - if let Some(name) = name { - pane_template.name = Some(name); - } - let height = self.parse_percent_or_fixed(kdl_node, "height", false)?; - let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; - let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; - let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; - // let mut floating_pane = FloatingPaneLayout::from(&pane_template); - if let Some(height) = height { - pane_template.height = Some(height); - } - if let Some(width) = width { - pane_template.width = Some(width); - } - if let Some(y) = y { - pane_template.y = Some(y); - } - if let Some(x) = x { - pane_template.x = Some(x); - } - Ok(pane_template) - }, - PaneOrFloatingPane::Either(mut pane_template) => { - let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); - let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") - .map(|name| name.to_string()); - let args = self.parse_args(kdl_node)?; - let close_on_exit = - kdl_get_bool_property_or_child_value_with_error!(kdl_node, "close_on_exit"); - let start_suspended = - kdl_get_bool_property_or_child_value_with_error!(kdl_node, "start_suspended"); - let run = self.parse_command_plugin_or_edit_block_for_template(kdl_node)?; - self.assert_no_bare_attributes_in_pane_node_with_template( - &run, - &pane_template.run, - &args, - &close_on_exit, - &start_suspended, - kdl_node, - )?; - pane_template.run = Run::merge(&pane_template.run, &run); - if let Some(pane_template_run_command) = pane_template.run.as_mut() { - // we need to do this because panes consuming a pane_template - // can have bare args without a command - pane_template_run_command.add_args(args); - pane_template_run_command.add_close_on_exit(close_on_exit); - pane_template_run_command.add_start_suspended(start_suspended); - }; - if let Some(focus) = focus { - pane_template.focus = Some(focus); - } - if let Some(name) = name { - |