diff options
author | Aram Drevekenin <aram@poor.dev> | 2022-10-14 17:44:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-14 17:44:23 +0200 |
commit | efceb562dec562babd90c711b30a5471e026fd3d (patch) | |
tree | 0d98a00319023c1f9724fc39cff018513413c6ee /zellij-utils | |
parent | 8c2b576b670a98d891186c1cf469ca438dfd8a45 (diff) |
feat(layouts): edit panes (#1799)
* feat(layouts): edit panes
* style(fmt): rustfmt
Diffstat (limited to 'zellij-utils')
5 files changed, 147 insertions, 13 deletions
diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 8299c0bc2..8e317a8e0 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -62,11 +62,15 @@ pub enum Run { Plugin(RunPlugin), #[serde(rename = "command")] Command(RunCommand), + EditFile(PathBuf, Option<usize>), // TODO: merge this with TerminalAction::OpenFile Cwd(PathBuf), } impl Run { pub fn merge(base: &Option<Run>, other: &Option<Run>) -> Option<Run> { + // This method is necessary to merge between pane_templates and their consumers + // TODO: reconsider the way we parse command/edit/plugin pane_templates from layouts to prevent this + // madness // TODO: handle Plugin variants once there's a need match (base, other) { (Some(Run::Command(base_run_command)), Some(Run::Command(other_run_command))) => { @@ -91,6 +95,16 @@ impl Run { } Some(Run::Command(merged)) }, + ( + Some(Run::Command(base_run_command)), + Some(Run::EditFile(file_to_edit, line_number)), + ) => match &base_run_command.cwd { + Some(cwd) => Some(Run::EditFile(cwd.join(&file_to_edit), *line_number)), + None => Some(Run::EditFile(file_to_edit.clone(), *line_number)), + }, + (Some(Run::Cwd(cwd)), Some(Run::EditFile(file_to_edit, line_number))) => { + Some(Run::EditFile(cwd.join(&file_to_edit), *line_number)) + }, (Some(_base), Some(other)) => Some(other.clone()), (Some(base), _) => Some(base.clone()), (None, Some(other)) => Some(other.clone()), diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs index 82a221e2e..6155024b2 100644 --- a/zellij-utils/src/input/unit/layout_test.rs +++ b/zellij-utils/src/input/unit/layout_test.rs @@ -1283,6 +1283,38 @@ fn pane_template_with_bare_propagated_to_its_consumer_command_with_cwd() { } #[test] +fn pane_template_with_bare_propagated_to_its_consumer_edit() { + let kdl_layout = r#" + layout { + cwd "/tmp" + pane_template name="tail" { + cwd "foo" + } + tail edit="bar" + // pane should have /tmp/foo/bar with the edit file variant + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] +fn pane_template_with_command_propagated_to_its_consumer_edit() { + let kdl_layout = r#" + layout { + cwd "/tmp" + pane_template name="tail" command="not-vim" { + cwd "foo" + } + tail edit="bar" + // pane should have /tmp/foo/bar with the edit file variant + } + "#; + let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap(); + assert_snapshot!(format!("{:#?}", layout)); +} + +#[test] fn global_cwd_given_to_panes_without_cwd() { let kdl_layout = r#" layout { diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap new file mode 100644 index 000000000..32bc6880c --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap @@ -0,0 +1,37 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 1298 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: Some( + EditFile( + "/tmp/foo/bar", + None, + ), + ), + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap new file mode 100644 index 000000000..f5f50be11 --- /dev/null +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap @@ -0,0 +1,37 @@ +--- +source: zellij-utils/src/input/./unit/layout_test.rs +assertion_line: 1314 +expression: "format!(\"{:#?}\", layout)" +--- +Layout { + tabs: [], + focused_tab_index: None, + template: Some( + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + PaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: Some( + EditFile( + "/tmp/foo/bar", + None, + ), + ), + borderless: false, + focus: None, + external_children_index: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + }, + ), +} diff --git a/zellij-utils/src/kdl/kdl_layout_parser.rs b/zellij-utils/src/kdl/kdl_layout_parser.rs index d7df58890..514a80e42 100644 --- a/zellij-utils/src/kdl/kdl_layout_parser.rs +++ b/zellij-utils/src/kdl/kdl_layout_parser.rs @@ -48,6 +48,7 @@ impl<'a> KdlLayoutParser<'a> { || word == "tab_template" || word == "default_tab_template" || word == "command" + || word == "edit" || word == "plugin" || word == "children" || word == "tab" @@ -66,6 +67,7 @@ impl<'a> KdlLayoutParser<'a> { || property_name == "size" || property_name == "plugin" || property_name == "command" + || property_name == "edit" || property_name == "cwd" || property_name == "args" || property_name == "split_direction" @@ -192,6 +194,8 @@ impl<'a> KdlLayoutParser<'a> { ) -> 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 = if is_template { // we fill the global_cwd for templates later kdl_get_string_property_or_child_value_with_error!(pane_node, "cwd") @@ -200,23 +204,30 @@ impl<'a> KdlLayoutParser<'a> { self.parse_cwd(pane_node)? }; let args = self.parse_args(pane_node)?; - match (command, cwd, args, is_template) { - (None, Some(cwd), _, _) => Ok(Some(Run::Cwd(cwd))), - (None, _, Some(_args), false) => Err(ConfigError::new_kdl_error( + match (command, edit, cwd, args, is_template) { + (None, None, Some(cwd), _, _) => Ok(Some(Run::Cwd(cwd))), + (None, _, _, Some(_args), false) => Err(ConfigError::new_kdl_error( "args can only be set if a command was specified".into(), pane_node.span().offset(), pane_node.span().len(), )), - (Some(command), cwd, args, _) => Ok(Some(Run::Command(RunCommand { + (Some(command), None, cwd, args, _) => Ok(Some(Run::Command(RunCommand { command, args: args.unwrap_or_else(|| vec![]), cwd, hold_on_close: true, }))), + (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_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_or_plugin_block( + fn parse_command_plugin_or_edit_block( &self, kdl_node: &KdlNode, ) -> Result<Option<Run>, ConfigError> { @@ -224,7 +235,7 @@ impl<'a> KdlLayoutParser<'a> { if let Some(plugin_block) = kdl_get_child!(kdl_node, "plugin") { if run.is_some() { return Err(ConfigError::new_kdl_error( - "Cannot have both a command and a plugin block for a single pane".into(), + "Cannot have both a command/edit and a plugin block for a single pane".into(), plugin_block.span().offset(), plugin_block.span().len(), )); @@ -233,7 +244,7 @@ impl<'a> KdlLayoutParser<'a> { } Ok(run) } - fn parse_command_or_plugin_block_for_template( + fn parse_command_plugin_or_edit_block_for_template( &self, kdl_node: &KdlNode, ) -> Result<Option<Run>, ConfigError> { @@ -241,7 +252,7 @@ impl<'a> KdlLayoutParser<'a> { if let Some(plugin_block) = kdl_get_child!(kdl_node, "plugin") { if run.is_some() { return Err(ConfigError::new_kdl_error( - "Cannot have both a command and a plugin block for a single pane".into(), + "Cannot have both a command/edit and a plugin block for a single pane".into(), plugin_block.span().offset(), plugin_block.span().len(), )); @@ -257,7 +268,7 @@ impl<'a> KdlLayoutParser<'a> { 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_or_plugin_block(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)?, @@ -315,7 +326,7 @@ impl<'a> KdlLayoutParser<'a> { .map(|name| name.to_string()); let args = self.parse_args(kdl_node)?; let split_size = self.parse_split_size(kdl_node)?; - let run = self.parse_command_or_plugin_block_for_template(kdl_node)?; + let run = self.parse_command_plugin_or_edit_block_for_template(kdl_node)?; self.assert_no_bare_args_in_pane_node_with_template( &run, &pane_template.run, @@ -370,6 +381,9 @@ impl<'a> KdlLayoutParser<'a> { run_command.cwd = Some(global_cwd.clone()); }, }, + Some(Run::EditFile(path_to_file, _line_number)) => { + *path_to_file = global_cwd.join(&path_to_file); + }, Some(Run::Cwd(pane_template_cwd)) => { *pane_template_cwd = global_cwd.join(&pane_template_cwd); }, @@ -406,7 +420,7 @@ impl<'a> KdlLayoutParser<'a> { 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 split_size = self.parse_split_size(kdl_node)?; - let run = self.parse_command_or_plugin_block(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, pane_parts) = match kdl_children_nodes!(kdl_node) { Some(children) => self.parse_child_pane_nodes_for_pane(&children)?, @@ -625,7 +639,7 @@ impl<'a> KdlLayoutParser<'a> { let has_cwd_prop = kdl_get_string_property_or_child_value_with_error!(kdl_node, "cwd").is_some(); let has_non_cwd_run_prop = self - .parse_command_or_plugin_block(kdl_node)? + .parse_command_plugin_or_edit_block(kdl_node)? .map(|r| match r { Run::Cwd(_) => false, _ => true, @@ -643,7 +657,7 @@ impl<'a> KdlLayoutParser<'a> { offending_nodes.push("focus"); } if has_non_cwd_run_prop { - offending_nodes.push("command/plugin"); + offending_nodes.push("command/edit/plugin"); } if has_cwd_prop { offending_nodes.push("cwd"); |