Repository: zellij-org/zellij
File: zellij-utils/src/kdl/kdl_layout_parser.rs (Rust)

Code before:
                }
                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")
                .and_then(|cwd| match shellexpand::env(cwd) {
                    Ok(cwd) => Some(cwd.to_string()),
                    Err(e) => {
                        log::error!("when parsing `cwd`: {}", e);
                        None
                    },
                })
                .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,

Review comment (bug):
Let's return a proper error here so that it can be displayed nicely to the user. You can look at the various places we return a `ConfigError` in this file for examples.

Code after:
                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_path(
        &self,
        kdl_node: &KdlNode,
        name: &'static str,
    ) -> Result<Option<PathBuf>, ConfigError> {
        match kdl_get_string_property_or_child_value_with_error!(kdl_node, name) {
            Some(s) => match shellexpand::full(s) {
                Ok(s) => Ok(Some(PathBuf::from(s.as_ref()))),
                Err(e) => Err(kdl_parsing_error!(e.to_string(), kdl_node)),
            },
            None => Ok(None),
        }
    }
    fn parse_pane_command(
        &self,
        pane_node: &KdlNode,
        is_template: bool,
    ) -> Result<Option<Run>, ConfigError> {
        let command = self.parse_path(pane_node, "command")?;
        let edit = self.parse_path(pane_node, "edit")?;
        let cwd = self.parse_path(pane_node, "cwd")?;
        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,