feat(layouts): global cwd (#1798)
* feat(layouts): allow defining a global cwd * feat(layouts): allow passing global cwd from cli * style(fmt): rustfmt * fix(layouts): error on mixed cwd and pane children
This commit is contained in:
parent
5c43a59e00
commit
d074bb1cda
22 changed files with 1061 additions and 151 deletions
|
|
@ -140,8 +140,14 @@ fn handle_openpty(
|
||||||
let cmd = cmd.clone();
|
let cmd = cmd.clone();
|
||||||
let command = &mut Command::new(cmd.command);
|
let command = &mut Command::new(cmd.command);
|
||||||
if let Some(current_dir) = cmd.cwd {
|
if let Some(current_dir) = cmd.cwd {
|
||||||
if current_dir.exists() {
|
if current_dir.exists() && current_dir.is_dir() {
|
||||||
command.current_dir(current_dir);
|
command.current_dir(current_dir);
|
||||||
|
} else {
|
||||||
|
// TODO: propagate this to the user
|
||||||
|
log::error!(
|
||||||
|
"Failed to set CWD for new pane. {} does not exist or is not a folder",
|
||||||
|
current_dir.display()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
command
|
command
|
||||||
|
|
|
||||||
|
|
@ -364,11 +364,11 @@ impl Pty {
|
||||||
default_editor,
|
default_editor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_default_terminal(&self) -> TerminalAction {
|
pub fn get_default_terminal(&self, cwd: Option<PathBuf>) -> TerminalAction {
|
||||||
TerminalAction::RunCommand(RunCommand {
|
TerminalAction::RunCommand(RunCommand {
|
||||||
args: vec![],
|
args: vec![],
|
||||||
command: PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")),
|
command: PathBuf::from(env::var("SHELL").expect("Could not find the SHELL variable")),
|
||||||
cwd: None, // this should be filled by the calling function, eg. spawn_terminal
|
cwd, // note: this might also be filled by the calling function, eg. spawn_terminal
|
||||||
hold_on_close: false,
|
hold_on_close: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -400,12 +400,12 @@ impl Pty {
|
||||||
let terminal_action = match client_or_tab_index {
|
let terminal_action = match client_or_tab_index {
|
||||||
ClientOrTabIndex::ClientId(client_id) => {
|
ClientOrTabIndex::ClientId(client_id) => {
|
||||||
let mut terminal_action =
|
let mut terminal_action =
|
||||||
terminal_action.unwrap_or_else(|| self.get_default_terminal());
|
terminal_action.unwrap_or_else(|| self.get_default_terminal(None));
|
||||||
self.fill_cwd(&mut terminal_action, client_id);
|
self.fill_cwd(&mut terminal_action, client_id);
|
||||||
terminal_action
|
terminal_action
|
||||||
},
|
},
|
||||||
ClientOrTabIndex::TabIndex(_) => {
|
ClientOrTabIndex::TabIndex(_) => {
|
||||||
terminal_action.unwrap_or_else(|| self.get_default_terminal())
|
terminal_action.unwrap_or_else(|| self.get_default_terminal(None))
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let hold_on_close = match &terminal_action {
|
let hold_on_close = match &terminal_action {
|
||||||
|
|
@ -454,7 +454,7 @@ impl Pty {
|
||||||
default_shell: Option<TerminalAction>,
|
default_shell: Option<TerminalAction>,
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
) {
|
) {
|
||||||
let mut default_shell = default_shell.unwrap_or_else(|| self.get_default_terminal());
|
let mut default_shell = default_shell.unwrap_or_else(|| self.get_default_terminal(None));
|
||||||
self.fill_cwd(&mut default_shell, client_id);
|
self.fill_cwd(&mut default_shell, client_id);
|
||||||
let extracted_run_instructions = layout.extract_run_instructions();
|
let extracted_run_instructions = layout.extract_run_instructions();
|
||||||
let mut new_pane_pids: Vec<(u32, Option<RunCommand>, Result<RawFd, SpawnTerminalError>)> =
|
let mut new_pane_pids: Vec<(u32, Option<RunCommand>, Result<RawFd, SpawnTerminalError>)> =
|
||||||
|
|
@ -513,6 +513,29 @@ impl Pty {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Some(Run::Cwd(cwd)) => {
|
||||||
|
let shell = self.get_default_terminal(Some(cwd));
|
||||||
|
match self.bus.os_input.as_mut().unwrap().spawn_terminal(
|
||||||
|
shell,
|
||||||
|
quit_cb,
|
||||||
|
self.default_editor.clone(),
|
||||||
|
) {
|
||||||
|
Ok((terminal_id, pid_primary, child_fd)) => {
|
||||||
|
self.id_to_child_pid.insert(terminal_id, child_fd);
|
||||||
|
new_pane_pids.push((terminal_id, None, Ok(pid_primary)));
|
||||||
|
},
|
||||||
|
Err(SpawnTerminalError::CommandNotFound(terminal_id)) => {
|
||||||
|
new_pane_pids.push((
|
||||||
|
terminal_id,
|
||||||
|
None,
|
||||||
|
Err(SpawnTerminalError::CommandNotFound(terminal_id)),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to spawn terminal: {}", e);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
None => {
|
None => {
|
||||||
match self.bus.os_input.as_mut().unwrap().spawn_terminal(
|
match self.bus.os_input.as_mut().unwrap().spawn_terminal(
|
||||||
default_shell.clone(),
|
default_shell.clone(),
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str)
|
||||||
let copy_options = CopyOptions::default();
|
let copy_options = CopyOptions::default();
|
||||||
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
|
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
|
||||||
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
|
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
|
||||||
let layout = Layout::from_str(layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_str(layout, "layout_file_name".into(), None).unwrap();
|
||||||
let tab_layout = layout.new_tab();
|
let tab_layout = layout.new_tab();
|
||||||
let mut tab = Tab::new(
|
let mut tab = Tab::new(
|
||||||
index,
|
index,
|
||||||
|
|
|
||||||
|
|
@ -2207,6 +2207,7 @@ pub fn send_cli_new_tab_action_default_params() {
|
||||||
let new_tab_action = CliAction::NewTab {
|
let new_tab_action = CliAction::NewTab {
|
||||||
name: None,
|
name: None,
|
||||||
layout: None,
|
layout: None,
|
||||||
|
cwd: None,
|
||||||
};
|
};
|
||||||
send_cli_action_to_server(
|
send_cli_action_to_server(
|
||||||
&session_metadata,
|
&session_metadata,
|
||||||
|
|
@ -2242,6 +2243,7 @@ pub fn send_cli_new_tab_action_with_name_and_layout() {
|
||||||
"{}/src/unit/fixtures/layout-with-three-panes.kdl",
|
"{}/src/unit/fixtures/layout-with-three-panes.kdl",
|
||||||
env!("CARGO_MANIFEST_DIR")
|
env!("CARGO_MANIFEST_DIR")
|
||||||
))),
|
))),
|
||||||
|
cwd: None,
|
||||||
};
|
};
|
||||||
send_cli_action_to_server(
|
send_cli_action_to_server(
|
||||||
&session_metadata,
|
&session_metadata,
|
||||||
|
|
|
||||||
|
|
@ -253,5 +253,7 @@ pub enum CliAction {
|
||||||
layout: Option<PathBuf>,
|
layout: Option<PathBuf>,
|
||||||
#[clap(short, long, value_parser)]
|
#[clap(short, long, value_parser)]
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
|
#[clap(short, long, value_parser, requires("layout"))]
|
||||||
|
cwd: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -344,12 +344,12 @@ impl Action {
|
||||||
Action::TabNameInput(name.as_bytes().to_vec()),
|
Action::TabNameInput(name.as_bytes().to_vec()),
|
||||||
]),
|
]),
|
||||||
CliAction::UndoRenameTab => Ok(vec![Action::UndoRenameTab]),
|
CliAction::UndoRenameTab => Ok(vec![Action::UndoRenameTab]),
|
||||||
CliAction::NewTab { name, layout } => {
|
CliAction::NewTab { name, layout, cwd } => {
|
||||||
if let Some(layout_path) = layout {
|
if let Some(layout_path) = layout {
|
||||||
let (path_to_raw_layout, raw_layout) =
|
let (path_to_raw_layout, raw_layout) =
|
||||||
Layout::stringified_from_path_or_default(Some(&layout_path), None)
|
Layout::stringified_from_path_or_default(Some(&layout_path), None)
|
||||||
.map_err(|e| format!("Failed to load layout: {}", e))?;
|
.map_err(|e| format!("Failed to load layout: {}", e))?;
|
||||||
let layout = Layout::from_str(&raw_layout, path_to_raw_layout).map_err(|e| {
|
let layout = Layout::from_str(&raw_layout, path_to_raw_layout, cwd).map_err(|e| {
|
||||||
let stringified_error = match e {
|
let stringified_error = match e {
|
||||||
ConfigError::KdlError(kdl_error) => {
|
ConfigError::KdlError(kdl_error) => {
|
||||||
let error = kdl_error.add_src(layout_path.as_path().as_os_str().to_string_lossy().to_string(), String::from(raw_layout));
|
let error = kdl_error.add_src(layout_path.as_path().as_os_str().to_string_lossy().to_string(), String::from(raw_layout));
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,41 @@ pub enum Run {
|
||||||
Plugin(RunPlugin),
|
Plugin(RunPlugin),
|
||||||
#[serde(rename = "command")]
|
#[serde(rename = "command")]
|
||||||
Command(RunCommand),
|
Command(RunCommand),
|
||||||
|
Cwd(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Run {
|
||||||
|
pub fn merge(base: &Option<Run>, other: &Option<Run>) -> Option<Run> {
|
||||||
|
// TODO: handle Plugin variants once there's a need
|
||||||
|
match (base, other) {
|
||||||
|
(Some(Run::Command(base_run_command)), Some(Run::Command(other_run_command))) => {
|
||||||
|
let mut merged = other_run_command.clone();
|
||||||
|
if merged.cwd.is_none() && base_run_command.cwd.is_some() {
|
||||||
|
merged.cwd = base_run_command.cwd.clone();
|
||||||
|
}
|
||||||
|
if merged.args.is_empty() && !base_run_command.args.is_empty() {
|
||||||
|
merged.args = base_run_command.args.clone();
|
||||||
|
}
|
||||||
|
Some(Run::Command(merged))
|
||||||
|
},
|
||||||
|
(Some(Run::Command(base_run_command)), Some(Run::Cwd(other_cwd))) => {
|
||||||
|
let mut merged = base_run_command.clone();
|
||||||
|
merged.cwd = Some(other_cwd.clone());
|
||||||
|
Some(Run::Command(merged))
|
||||||
|
},
|
||||||
|
(Some(Run::Cwd(base_cwd)), Some(Run::Command(other_command))) => {
|
||||||
|
let mut merged = other_command.clone();
|
||||||
|
if merged.cwd.is_none() {
|
||||||
|
merged.cwd = Some(base_cwd.clone());
|
||||||
|
}
|
||||||
|
Some(Run::Command(merged))
|
||||||
|
},
|
||||||
|
(Some(_base), Some(other)) => Some(other.clone()),
|
||||||
|
(Some(base), _) => Some(base.clone()),
|
||||||
|
(None, Some(other)) => Some(other.clone()),
|
||||||
|
(None, None) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
|
@ -252,12 +287,16 @@ impl Layout {
|
||||||
) -> Result<(Layout, Config), ConfigError> {
|
) -> Result<(Layout, Config), ConfigError> {
|
||||||
let (path_to_raw_layout, raw_layout) =
|
let (path_to_raw_layout, raw_layout) =
|
||||||
Layout::stringified_from_path_or_default(layout_path, layout_dir)?;
|
Layout::stringified_from_path_or_default(layout_path, layout_dir)?;
|
||||||
let layout = Layout::from_kdl(&raw_layout, path_to_raw_layout)?;
|
let layout = Layout::from_kdl(&raw_layout, path_to_raw_layout, None)?;
|
||||||
let config = Config::from_kdl(&raw_layout, Some(config))?; // this merges the two config, with
|
let config = Config::from_kdl(&raw_layout, Some(config))?; // this merges the two config, with
|
||||||
Ok((layout, config))
|
Ok((layout, config))
|
||||||
}
|
}
|
||||||
pub fn from_str(raw: &str, path_to_raw_layout: String) -> Result<Layout, ConfigError> {
|
pub fn from_str(
|
||||||
Layout::from_kdl(raw, path_to_raw_layout)
|
raw: &str,
|
||||||
|
path_to_raw_layout: String,
|
||||||
|
cwd: Option<PathBuf>,
|
||||||
|
) -> Result<Layout, ConfigError> {
|
||||||
|
Layout::from_kdl(raw, path_to_raw_layout, cwd)
|
||||||
}
|
}
|
||||||
pub fn stringified_from_dir(
|
pub fn stringified_from_dir(
|
||||||
layout: &PathBuf,
|
layout: &PathBuf,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use insta::assert_snapshot;
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_layout() {
|
fn empty_layout() {
|
||||||
let kdl_layout = "layout";
|
let kdl_layout = "layout";
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout::default()),
|
template: Some(PaneLayout::default()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
@ -19,7 +19,7 @@ fn layout_with_one_pane() {
|
||||||
pane
|
pane
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![PaneLayout::default()],
|
children: vec![PaneLayout::default()],
|
||||||
|
|
@ -39,7 +39,7 @@ fn layout_with_multiple_panes() {
|
||||||
pane
|
pane
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![
|
children: vec![
|
||||||
|
|
@ -68,7 +68,7 @@ fn layout_with_nested_panes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![
|
children: vec![
|
||||||
|
|
@ -96,7 +96,7 @@ fn layout_with_tabs() {
|
||||||
tab
|
tab
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
tabs: vec![(None, PaneLayout::default())],
|
tabs: vec![(None, PaneLayout::default())],
|
||||||
template: Some(PaneLayout::default()),
|
template: Some(PaneLayout::default()),
|
||||||
|
|
@ -120,7 +120,7 @@ fn layout_with_nested_differing_tabs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
tabs: vec![
|
tabs: vec![
|
||||||
(
|
(
|
||||||
|
|
@ -160,7 +160,7 @@ fn layout_with_panes_in_different_mixed_split_sizes() {
|
||||||
pane size=2;
|
pane size=2;
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![
|
children: vec![
|
||||||
|
|
@ -195,7 +195,7 @@ fn layout_with_command_panes() {
|
||||||
pane command="htop"
|
pane command="htop"
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![PaneLayout {
|
children: vec![PaneLayout {
|
||||||
|
|
@ -220,7 +220,7 @@ fn layout_with_command_panes_and_cwd() {
|
||||||
pane command="htop" cwd="/path/to/my/cwd"
|
pane command="htop" cwd="/path/to/my/cwd"
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![PaneLayout {
|
children: vec![PaneLayout {
|
||||||
|
|
@ -248,7 +248,7 @@ fn layout_with_command_panes_and_cwd_and_args() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![PaneLayout {
|
children: vec![PaneLayout {
|
||||||
|
|
@ -280,7 +280,7 @@ fn layout_with_plugin_panes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![
|
children: vec![
|
||||||
|
|
@ -313,7 +313,7 @@ fn layout_with_borderless_panes() {
|
||||||
pane borderless=true
|
pane borderless=true
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![PaneLayout {
|
children: vec![PaneLayout {
|
||||||
|
|
@ -334,7 +334,7 @@ fn layout_with_focused_panes() {
|
||||||
pane focus=true
|
pane focus=true
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![PaneLayout {
|
children: vec![PaneLayout {
|
||||||
|
|
@ -355,7 +355,7 @@ fn layout_with_pane_names() {
|
||||||
pane name="my awesome pane"
|
pane name="my awesome pane"
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
template: Some(PaneLayout {
|
template: Some(PaneLayout {
|
||||||
children: vec![PaneLayout {
|
children: vec![PaneLayout {
|
||||||
|
|
@ -377,7 +377,7 @@ fn layout_with_tab_names() {
|
||||||
tab name="my cool tab name 2"
|
tab name="my cool tab name 2"
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
tabs: vec![
|
tabs: vec![
|
||||||
(
|
(
|
||||||
|
|
@ -410,7 +410,7 @@ fn layout_with_focused_tab() {
|
||||||
tab
|
tab
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
tabs: vec![
|
tabs: vec![
|
||||||
(None, PaneLayout::default()),
|
(None, PaneLayout::default()),
|
||||||
|
|
@ -444,7 +444,7 @@ fn layout_with_tab_templates() {
|
||||||
one-above-one-below
|
one-above-one-below
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
let expected_layout = Layout {
|
let expected_layout = Layout {
|
||||||
tabs: vec![
|
tabs: vec![
|
||||||
(
|
(
|
||||||
|
|
@ -518,7 +518,7 @@ fn layout_with_default_tab_template() {
|
||||||
tab
|
tab
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -545,7 +545,7 @@ fn layout_with_pane_templates() {
|
||||||
left-and-right
|
left-and-right
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -566,7 +566,7 @@ fn layout_with_tab_and_pane_templates() {
|
||||||
left-right-and-htop
|
left-right-and-htop
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -587,7 +587,7 @@ fn layout_with_nested_pane_templates() {
|
||||||
left-and-right
|
left-and-right
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -613,7 +613,7 @@ fn layout_with_nested_branched_pane_templates() {
|
||||||
left-and-right
|
left-and-right
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -637,7 +637,7 @@ fn circular_dependency_pane_templates_error() {
|
||||||
one
|
one
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(layout.is_err(), "circular dependency detected");
|
assert!(layout.is_err(), "circular dependency detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -659,7 +659,7 @@ fn children_not_as_first_child_of_tab_template() {
|
||||||
horizontal-with-vertical-top
|
horizontal-with-vertical-top
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -682,7 +682,7 @@ fn error_on_more_than_one_children_block_in_tab_template() {
|
||||||
horizontal-with-vertical-top
|
horizontal-with-vertical-top
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(
|
assert!(
|
||||||
layout.is_err(),
|
layout.is_err(),
|
||||||
"error provided for more than one children block"
|
"error provided for more than one children block"
|
||||||
|
|
@ -707,7 +707,7 @@ fn children_not_as_first_child_of_pane_template() {
|
||||||
horizontal-with-vertical-top
|
horizontal-with-vertical-top
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -730,7 +730,7 @@ fn error_on_more_than_one_children_block_in_pane_template() {
|
||||||
horizontal-with-vertical-top
|
horizontal-with-vertical-top
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(
|
assert!(
|
||||||
layout.is_err(),
|
layout.is_err(),
|
||||||
"error provided for more than one children block"
|
"error provided for more than one children block"
|
||||||
|
|
@ -759,7 +759,7 @@ fn combined_tab_and_pane_template_both_with_children() {
|
||||||
horizontal-with-vertical-top
|
horizontal-with-vertical-top
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -775,7 +775,7 @@ fn cannot_define_tab_template_name_with_space() {
|
||||||
pane
|
pane
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(layout.is_err(), "error provided for tab name with space");
|
assert!(layout.is_err(), "error provided for tab name with space");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -791,7 +791,7 @@ fn cannot_define_pane_template_name_with_space() {
|
||||||
pane
|
pane
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(layout.is_err(), "error provided for tab name with space");
|
assert!(layout.is_err(), "error provided for tab name with space");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -805,7 +805,7 @@ fn cannot_define_panes_and_tabs_on_same_level() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(
|
assert!(
|
||||||
layout.is_err(),
|
layout.is_err(),
|
||||||
"error provided for tab and pane on the same level"
|
"error provided for tab and pane on the same level"
|
||||||
|
|
@ -839,7 +839,7 @@ fn cannot_define_tab_template_names_as_keywords() {
|
||||||
",
|
",
|
||||||
keyword
|
keyword
|
||||||
);
|
);
|
||||||
let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(
|
assert!(
|
||||||
layout.is_err(),
|
layout.is_err(),
|
||||||
"{}",
|
"{}",
|
||||||
|
|
@ -877,7 +877,7 @@ fn cannot_define_pane_template_names_as_keywords() {
|
||||||
",
|
",
|
||||||
keyword
|
keyword
|
||||||
);
|
);
|
||||||
let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(
|
assert!(
|
||||||
layout.is_err(),
|
layout.is_err(),
|
||||||
"{}",
|
"{}",
|
||||||
|
|
@ -897,7 +897,7 @@ fn error_on_multiple_layout_nodes_in_file() {
|
||||||
layout
|
layout
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -912,7 +912,7 @@ fn error_on_unknown_layout_node() {
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -925,7 +925,7 @@ fn error_on_unknown_layout_pane_property() {
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -938,7 +938,7 @@ fn error_on_unknown_layout_pane_template_property() {
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -951,7 +951,7 @@ fn error_on_unknown_layout_tab_property() {
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -964,7 +964,7 @@ fn error_on_unknown_layout_tab_template_property() {
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -981,7 +981,7 @@ fn error_on_pane_templates_without_a_name() {
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -998,7 +998,7 @@ fn error_on_tab_templates_without_a_name() {
|
||||||
}}
|
}}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1011,7 +1011,7 @@ fn error_on_more_than_one_focused_tab() {
|
||||||
tab
|
tab
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout_error = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap_err();
|
let layout_error = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap_err();
|
||||||
assert_snapshot!(format!("{:?}", layout_error));
|
assert_snapshot!(format!("{:?}", layout_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1029,7 +1029,7 @@ fn args_override_args_in_template() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1046,7 +1046,7 @@ fn args_added_to_args_in_template() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1064,7 +1064,7 @@ fn cwd_override_cwd_in_template() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1081,7 +1081,7 @@ fn cwd_added_to_cwd_in_template() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into()).unwrap();
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
assert_snapshot!(format!("{:#?}", layout));
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1094,7 +1094,21 @@ fn error_on_mixed_command_and_child_panes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
|
assert!(layout.is_err(), "error provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn error_on_mixed_cwd_and_child_panes() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
pane cwd="/tmp" {
|
||||||
|
pane
|
||||||
|
pane
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(layout.is_err(), "error provided");
|
assert!(layout.is_err(), "error provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1107,34 +1121,7 @@ fn error_on_bare_args_without_command() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(layout.is_err(), "error provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error_on_bare_cwd_without_command() {
|
|
||||||
let kdl_layout = r#"
|
|
||||||
layout {
|
|
||||||
pane {
|
|
||||||
cwd "/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
|
||||||
assert!(layout.is_err(), "error provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error_on_bare_cwd_in_template_without_command() {
|
|
||||||
let kdl_layout = r#"
|
|
||||||
layout {
|
|
||||||
pane_template name="my_template"
|
|
||||||
my_template {
|
|
||||||
cwd "/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
|
||||||
assert!(layout.is_err(), "error provided");
|
assert!(layout.is_err(), "error provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1148,6 +1135,215 @@ fn error_on_bare_args_in_template_without_command() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into());
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
|
||||||
assert!(layout.is_err(), "error provided");
|
assert!(layout.is_err(), "error provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
command "tail"
|
||||||
|
cwd "bar"
|
||||||
|
}
|
||||||
|
tail command="pwd" {
|
||||||
|
cwd "foo"
|
||||||
|
}
|
||||||
|
// pane should have /tmp/foo and not /tmp/bar as cwd
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_have_a_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
command "tail"
|
||||||
|
cwd "bar"
|
||||||
|
}
|
||||||
|
tail command="pwd"
|
||||||
|
// pane should have /tmp/bar as its cwd with the pwd command
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
command "tail"
|
||||||
|
}
|
||||||
|
tail command="pwd" {
|
||||||
|
cwd "bar"
|
||||||
|
}
|
||||||
|
// pane should have /tmp/bar as its cwd with the pwd command
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
command "tail"
|
||||||
|
cwd "foo"
|
||||||
|
}
|
||||||
|
tail {
|
||||||
|
cwd "bar"
|
||||||
|
}
|
||||||
|
// pane should have /tmp/bar as its cwd with the tail command
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_command_without_cwd_receives_its_consumers_bare_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
command "tail"
|
||||||
|
}
|
||||||
|
tail {
|
||||||
|
cwd "bar"
|
||||||
|
}
|
||||||
|
// pane should have /tmp/bar as its cwd with the tail command
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_with_bare_cwd_overriden_by_its_consumers_bare_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
cwd "foo"
|
||||||
|
}
|
||||||
|
tail {
|
||||||
|
cwd "bar"
|
||||||
|
}
|
||||||
|
// pane should have /tmp/foo without a command
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_with_bare_propagated_to_its_consumer_command_without_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
cwd "foo"
|
||||||
|
}
|
||||||
|
tail command="tail"
|
||||||
|
// pane should have /tmp/foo with the tail command
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pane_template_with_bare_propagated_to_its_consumer_command_with_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane_template name="tail" {
|
||||||
|
cwd "foo"
|
||||||
|
}
|
||||||
|
tail command="tail" {
|
||||||
|
cwd "bar"
|
||||||
|
}
|
||||||
|
// pane should have /tmp/bar with the tail command
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
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 {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane
|
||||||
|
pane command="tail"
|
||||||
|
// both should have the /tmp cwd
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_cwd_prepended_to_panes_with_cwd() {
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/tmp"
|
||||||
|
pane cwd="foo" // should be /tmp/foo
|
||||||
|
pane command="tail" cwd="/home/foo" // should be /home/foo because its an absolute path
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_cwd_passed_from_layout_constructor() {
|
||||||
|
// this is used by the new-tab cli action with --cwd
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
pane
|
||||||
|
pane command="tail"
|
||||||
|
// both should have the /tmp cwd
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(
|
||||||
|
kdl_layout,
|
||||||
|
"layout_file_name".into(),
|
||||||
|
Some(PathBuf::from("/tmp")),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file() {
|
||||||
|
// this is used by the new-tab cli action with --cwd
|
||||||
|
let kdl_layout = r#"
|
||||||
|
layout {
|
||||||
|
cwd "/home"
|
||||||
|
pane
|
||||||
|
pane command="tail"
|
||||||
|
// both should have the /tmp cwd
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let layout = Layout::from_kdl(
|
||||||
|
kdl_layout,
|
||||||
|
"layout_file_name".into(),
|
||||||
|
Some(PathBuf::from("/tmp")),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_snapshot!(format!("{:#?}", layout));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1283
|
||||||
|
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(
|
||||||
|
Cwd(
|
||||||
|
"/tmp",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
PaneLayout {
|
||||||
|
children_split_direction: Horizontal,
|
||||||
|
name: None,
|
||||||
|
children: [],
|
||||||
|
split_size: None,
|
||||||
|
run: Some(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1309
|
||||||
|
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(
|
||||||
|
Cwd(
|
||||||
|
"/tmp",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
PaneLayout {
|
||||||
|
children_split_direction: Horizontal,
|
||||||
|
name: None,
|
||||||
|
children: [],
|
||||||
|
split_size: None,
|
||||||
|
run: Some(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1324
|
||||||
|
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(
|
||||||
|
Cwd(
|
||||||
|
"/tmp",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
PaneLayout {
|
||||||
|
children_split_direction: Horizontal,
|
||||||
|
name: None,
|
||||||
|
children: [],
|
||||||
|
split_size: None,
|
||||||
|
run: Some(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1295
|
||||||
|
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(
|
||||||
|
Cwd(
|
||||||
|
"/tmp/foo",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
PaneLayout {
|
||||||
|
children_split_direction: Horizontal,
|
||||||
|
name: None,
|
||||||
|
children: [],
|
||||||
|
split_size: None,
|
||||||
|
run: Some(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/home/foo",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1199
|
||||||
|
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(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp/bar",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1144
|
||||||
|
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(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "pwd",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp/foo",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1161
|
||||||
|
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(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "pwd",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp/bar",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1180
|
||||||
|
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(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "pwd",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp/bar",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1216
|
||||||
|
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(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp/bar",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1235
|
||||||
|
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(
|
||||||
|
Cwd(
|
||||||
|
"/tmp/bar",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1269
|
||||||
|
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(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp/bar",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/input/./unit/layout_test.rs
|
||||||
|
assertion_line: 1251
|
||||||
|
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(
|
||||||
|
Command(
|
||||||
|
RunCommand {
|
||||||
|
command: "tail",
|
||||||
|
args: [],
|
||||||
|
cwd: Some(
|
||||||
|
"/tmp/foo",
|
||||||
|
),
|
||||||
|
hold_on_close: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split_size: None,
|
||||||
|
run: None,
|
||||||
|
borderless: false,
|
||||||
|
focus: None,
|
||||||
|
external_children_index: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@ use std::vec::Vec;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub struct KdlLayoutParser<'a> {
|
pub struct KdlLayoutParser<'a> {
|
||||||
|
global_cwd: Option<PathBuf>,
|
||||||
raw_layout: &'a str,
|
raw_layout: &'a str,
|
||||||
tab_templates: HashMap<String, (PaneLayout, KdlNode)>,
|
tab_templates: HashMap<String, (PaneLayout, KdlNode)>,
|
||||||
pane_templates: HashMap<String, (PaneLayout, KdlNode)>,
|
pane_templates: HashMap<String, (PaneLayout, KdlNode)>,
|
||||||
|
|
@ -31,12 +32,13 @@ pub struct KdlLayoutParser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> KdlLayoutParser<'a> {
|
impl<'a> KdlLayoutParser<'a> {
|
||||||
pub fn new(raw_layout: &'a str) -> Self {
|
pub fn new(raw_layout: &'a str, global_cwd: Option<PathBuf>) -> Self {
|
||||||
KdlLayoutParser {
|
KdlLayoutParser {
|
||||||
raw_layout,
|
raw_layout,
|
||||||
tab_templates: HashMap::new(),
|
tab_templates: HashMap::new(),
|
||||||
pane_templates: HashMap::new(),
|
pane_templates: HashMap::new(),
|
||||||
default_tab_template: None,
|
default_tab_template: None,
|
||||||
|
global_cwd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn is_a_reserved_word(&self, word: &str) -> bool {
|
fn is_a_reserved_word(&self, word: &str) -> bool {
|
||||||
|
|
@ -173,6 +175,16 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
None => Ok(None),
|
None => Ok(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(|c| match &self.global_cwd {
|
||||||
|
Some(global_cwd) => Some(global_cwd.join(c)),
|
||||||
|
None => Some(PathBuf::from(c)),
|
||||||
|
})
|
||||||
|
.or_else(|| self.global_cwd.as_ref().map(|g| g.clone())),
|
||||||
|
)
|
||||||
|
}
|
||||||
fn parse_pane_command(
|
fn parse_pane_command(
|
||||||
&self,
|
&self,
|
||||||
pane_node: &KdlNode,
|
pane_node: &KdlNode,
|
||||||
|
|
@ -180,15 +192,16 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
) -> Result<Option<Run>, ConfigError> {
|
) -> Result<Option<Run>, ConfigError> {
|
||||||
let command = kdl_get_string_property_or_child_value_with_error!(pane_node, "command")
|
let command = kdl_get_string_property_or_child_value_with_error!(pane_node, "command")
|
||||||
.map(|c| PathBuf::from(c));
|
.map(|c| PathBuf::from(c));
|
||||||
let cwd = kdl_get_string_property_or_child_value_with_error!(pane_node, "cwd")
|
let cwd = if is_template {
|
||||||
.map(|c| PathBuf::from(c));
|
// we fill the global_cwd for templates later
|
||||||
|
kdl_get_string_property_or_child_value_with_error!(pane_node, "cwd")
|
||||||
|
.map(|c| PathBuf::from(c))
|
||||||
|
} else {
|
||||||
|
self.parse_cwd(pane_node)?
|
||||||
|
};
|
||||||
let args = self.parse_args(pane_node)?;
|
let args = self.parse_args(pane_node)?;
|
||||||
match (command, cwd, args, is_template) {
|
match (command, cwd, args, is_template) {
|
||||||
(None, Some(_cwd), _, false) => Err(ConfigError::new_kdl_error(
|
(None, Some(cwd), _, _) => Ok(Some(Run::Cwd(cwd))),
|
||||||
"cwd can only be set if a command was specified".into(),
|
|
||||||
pane_node.span().offset(),
|
|
||||||
pane_node.span().len(),
|
|
||||||
)),
|
|
||||||
(None, _, Some(_args), false) => Err(ConfigError::new_kdl_error(
|
(None, _, Some(_args), false) => Err(ConfigError::new_kdl_error(
|
||||||
"args can only be set if a command was specified".into(),
|
"args can only be set if a command was specified".into(),
|
||||||
pane_node.span().offset(),
|
pane_node.span().offset(),
|
||||||
|
|
@ -263,39 +276,13 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn parse_pane_node_with_template(
|
fn insert_children_to_pane_template(
|
||||||
&self,
|
&self,
|
||||||
kdl_node: &KdlNode,
|
kdl_node: &KdlNode,
|
||||||
mut pane_layout: PaneLayout,
|
pane_template: &mut PaneLayout,
|
||||||
pane_layout_kdl_node: &KdlNode,
|
pane_template_kdl_node: &KdlNode,
|
||||||
) -> Result<PaneLayout, ConfigError> {
|
) -> Result<(), ConfigError> {
|
||||||
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 cwd = kdl_get_string_property_or_child_value_with_error!(kdl_node, "cwd")
|
|
||||||
.map(|c| PathBuf::from(c));
|
|
||||||
let split_size = self.parse_split_size(kdl_node)?;
|
|
||||||
let run = self.parse_command_or_plugin_block_for_template(kdl_node)?;
|
|
||||||
if let (None, None, true, true) | (None, None, false, true) | (None, None, true, false) =
|
|
||||||
(&run, &pane_layout.run, args.is_some(), cwd.is_some())
|
|
||||||
{
|
|
||||||
let mut offending_nodes = vec![];
|
|
||||||
if args.is_some() {
|
|
||||||
offending_nodes.push("args");
|
|
||||||
}
|
|
||||||
if cwd.is_some() {
|
|
||||||
offending_nodes.push("cwd");
|
|
||||||
}
|
|
||||||
return Err(kdl_parsing_error!(
|
|
||||||
format!("{} can only be specified if a command was specified either in the pane_template or in the pane", offending_nodes.join(" and ")),
|
|
||||||
kdl_node
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let children_split_direction = self.parse_split_direction(kdl_node)?;
|
let children_split_direction = self.parse_split_direction(kdl_node)?;
|
||||||
|
|
||||||
let (external_children_index, pane_parts) = match kdl_children_nodes!(kdl_node) {
|
let (external_children_index, pane_parts) = match kdl_children_nodes!(kdl_node) {
|
||||||
Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
|
Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
|
||||||
None => (None, vec![]),
|
None => (None, vec![]),
|
||||||
|
|
@ -307,41 +294,89 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
external_children_index,
|
external_children_index,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
self.assert_one_children_block(&pane_layout, pane_layout_kdl_node)?;
|
self.assert_one_children_block(&pane_template, pane_template_kdl_node)?;
|
||||||
self.insert_layout_children_or_error(
|
self.insert_layout_children_or_error(
|
||||||
&mut pane_layout,
|
pane_template,
|
||||||
child_panes_layout,
|
child_panes_layout,
|
||||||
pane_layout_kdl_node,
|
pane_template_kdl_node,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn parse_pane_node_with_template(
|
||||||
|
&self,
|
||||||
|
kdl_node: &KdlNode,
|
||||||
|
mut pane_template: PaneLayout,
|
||||||
|
pane_template_kdl_node: &KdlNode,
|
||||||
|
) -> Result<PaneLayout, ConfigError> {
|
||||||
|
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 split_size = self.parse_split_size(kdl_node)?;
|
||||||
|
let run = self.parse_command_or_plugin_block_for_template(kdl_node)?;
|
||||||
|
self.assert_no_bare_args_in_pane_node_with_template(
|
||||||
|
&run,
|
||||||
|
&pane_template.run,
|
||||||
|
&args,
|
||||||
|
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);
|
||||||
|
self.populate_global_cwd_for_pane_run(&mut pane_template.run)?;
|
||||||
|
if let (Some(Run::Command(pane_template_run_command)), Some(args)) =
|
||||||
|
(pane_template.run.as_mut(), args)
|
||||||
|
{
|
||||||
|
if !args.is_empty() {
|
||||||
|
pane_template_run_command.args = args.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(borderless) = borderless {
|
if let Some(borderless) = borderless {
|
||||||
pane_layout.borderless = borderless;
|
pane_template.borderless = borderless;
|
||||||
}
|
}
|
||||||
if let Some(focus) = focus {
|
if let Some(focus) = focus {
|
||||||
pane_layout.focus = Some(focus);
|
pane_template.focus = Some(focus);
|
||||||
}
|
}
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
pane_layout.name = Some(name);
|
pane_template.name = Some(name);
|
||||||
}
|
}
|
||||||
if let Some(split_size) = split_size {
|
if let Some(split_size) = split_size {
|
||||||
pane_layout.split_size = Some(split_size);
|
pane_template.split_size = Some(split_size);
|
||||||
}
|
}
|
||||||
if let Some(run) = run {
|
if let Some(index_of_children) = pane_template.external_children_index {
|
||||||
pane_layout.run = Some(run);
|
pane_template
|
||||||
}
|
|
||||||
if let (Some(args), Some(Run::Command(run_command))) = (args, pane_layout.run.as_mut()) {
|
|
||||||
run_command.args = args.clone();
|
|
||||||
}
|
|
||||||
if let (Some(cwd), Some(Run::Command(run_command))) = (cwd, pane_layout.run.as_mut()) {
|
|
||||||
run_command.cwd = Some(cwd.clone());
|
|
||||||
}
|
|
||||||
if let Some(index_of_children) = pane_layout.external_children_index {
|
|
||||||
pane_layout
|
|
||||||
.children
|
.children
|
||||||
.insert(index_of_children, PaneLayout::default());
|
.insert(index_of_children, PaneLayout::default());
|
||||||
}
|
}
|
||||||
pane_layout.external_children_index = None;
|
pane_template.external_children_index = None;
|
||||||
Ok(pane_layout)
|
Ok(pane_template)
|
||||||
|
}
|
||||||
|
fn populate_global_cwd_for_pane_run(
|
||||||
|
&self,
|
||||||
|
pane_run: &mut Option<Run>,
|
||||||
|
) -> Result<(), ConfigError> {
|
||||||
|
if let Some(global_cwd) = &self.global_cwd {
|
||||||
|
match pane_run.as_mut() {
|
||||||
|
Some(Run::Command(run_command)) => match run_command.cwd.as_mut() {
|
||||||
|
Some(run_command_cwd) => {
|
||||||
|
*run_command_cwd = global_cwd.join(&run_command_cwd);
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
run_command.cwd = Some(global_cwd.clone());
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Some(Run::Cwd(pane_template_cwd)) => {
|
||||||
|
*pane_template_cwd = global_cwd.join(&pane_template_cwd);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
fn parse_split_direction(&self, kdl_node: &KdlNode) -> Result<SplitDirection, ConfigError> {
|
fn parse_split_direction(&self, kdl_node: &KdlNode) -> Result<SplitDirection, ConfigError> {
|
||||||
match kdl_get_string_property_or_child_value_with_error!(kdl_node, "split_direction") {
|
match kdl_get_string_property_or_child_value_with_error!(kdl_node, "split_direction") {
|
||||||
|
|
@ -513,6 +548,21 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
fn assert_no_bare_args_in_pane_node_with_template(
|
||||||
|
&self,
|
||||||
|
pane_run: &Option<Run>,
|
||||||
|
pane_template_run: &Option<Run>,
|
||||||
|
args: &Option<Vec<String>>,
|
||||||
|
pane_node: &KdlNode,
|
||||||
|
) -> Result<(), ConfigError> {
|
||||||
|
if let (None, None, true) = (pane_run, pane_template_run, args.is_some()) {
|
||||||
|
return Err(kdl_parsing_error!(
|
||||||
|
format!("args can only be specified if a command was specified either in the pane_template or in the pane"),
|
||||||
|
pane_node
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn assert_one_children_block(
|
fn assert_one_children_block(
|
||||||
&self,
|
&self,
|
||||||
layout: &PaneLayout,
|
layout: &PaneLayout,
|
||||||
|
|
@ -572,10 +622,18 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless").is_some();
|
kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless").is_some();
|
||||||
let has_focus_prop =
|
let has_focus_prop =
|
||||||
kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus").is_some();
|
kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus").is_some();
|
||||||
let has_run_prop = self.parse_command_or_plugin_block(kdl_node)?.is_some();
|
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)?
|
||||||
|
.map(|r| match r {
|
||||||
|
Run::Cwd(_) => false,
|
||||||
|
_ => true,
|
||||||
|
})
|
||||||
|
.unwrap_or(false);
|
||||||
let has_nested_nodes_or_children_block = self.has_child_panes_tabs_or_templates(kdl_node);
|
let has_nested_nodes_or_children_block = self.has_child_panes_tabs_or_templates(kdl_node);
|
||||||
if has_nested_nodes_or_children_block
|
if has_nested_nodes_or_children_block
|
||||||
&& (has_borderless_prop || has_focus_prop || has_run_prop)
|
&& (has_borderless_prop || has_focus_prop || has_non_cwd_run_prop || has_cwd_prop)
|
||||||
{
|
{
|
||||||
let mut offending_nodes = vec![];
|
let mut offending_nodes = vec![];
|
||||||
if has_borderless_prop {
|
if has_borderless_prop {
|
||||||
|
|
@ -584,9 +642,12 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
if has_focus_prop {
|
if has_focus_prop {
|
||||||
offending_nodes.push("focus");
|
offending_nodes.push("focus");
|
||||||
}
|
}
|
||||||
if has_run_prop {
|
if has_non_cwd_run_prop {
|
||||||
offending_nodes.push("command/plugin");
|
offending_nodes.push("command/plugin");
|
||||||
}
|
}
|
||||||
|
if has_cwd_prop {
|
||||||
|
offending_nodes.push("cwd");
|
||||||
|
}
|
||||||
Err(ConfigError::new_kdl_error(
|
Err(ConfigError::new_kdl_error(
|
||||||
format!(
|
format!(
|
||||||
"Cannot have both properties ({}) and nested children",
|
"Cannot have both properties ({}) and nested children",
|
||||||
|
|
@ -821,6 +882,17 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn populate_global_cwd(&mut self, layout_node: &KdlNode) -> Result<(), ConfigError> {
|
||||||
|
// we only populate global cwd from the layout file if another wasn't explicitly passed to us
|
||||||
|
if self.global_cwd.is_none() {
|
||||||
|
if let Some(global_cwd) =
|
||||||
|
kdl_get_string_property_or_child_value_with_error!(layout_node, "cwd")
|
||||||
|
{
|
||||||
|
self.global_cwd = Some(PathBuf::from(global_cwd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
fn populate_pane_templates(
|
fn populate_pane_templates(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_children: &[KdlNode],
|
layout_children: &[KdlNode],
|
||||||
|
|
@ -1019,6 +1091,7 @@ impl<'a> KdlLayoutParser<'a> {
|
||||||
let mut child_tabs = vec![];
|
let mut child_tabs = vec![];
|
||||||
let mut child_panes = vec![];
|
let mut child_panes = vec![];
|
||||||
if let Some(children) = kdl_children_nodes!(layout_node) {
|
if let Some(children) = kdl_children_nodes!(layout_node) {
|
||||||
|
self.populate_global_cwd(layout_node)?;
|
||||||
self.populate_pane_templates(children, &kdl_layout)?;
|
self.populate_pane_templates(children, &kdl_layout)?;
|
||||||
self.populate_tab_templates(children)?;
|
self.populate_tab_templates(children)?;
|
||||||
for child in children {
|
for child in children {
|
||||||
|
|
|
||||||
|
|
@ -1266,8 +1266,12 @@ impl RunPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Layout {
|
impl Layout {
|
||||||
pub fn from_kdl(raw_layout: &str, file_name: String) -> Result<Self, ConfigError> {
|
pub fn from_kdl(
|
||||||
KdlLayoutParser::new(raw_layout).parse().map_err(|e| {
|
raw_layout: &str,
|
||||||
|
file_name: String,
|
||||||
|
cwd: Option<PathBuf>,
|
||||||
|
) -> Result<Self, ConfigError> {
|
||||||
|
KdlLayoutParser::new(raw_layout, cwd).parse().map_err(|e| {
|
||||||
match e {
|
match e {
|
||||||
ConfigError::KdlError(kdl_error) => ConfigError::KdlError(kdl_error.add_src(file_name, String::from(raw_layout))),
|
ConfigError::KdlError(kdl_error) => ConfigError::KdlError(kdl_error.add_src(file_name, String::from(raw_layout))),
|
||||||
ConfigError::KdlDeserializationError(kdl_error) => {
|
ConfigError::KdlDeserializationError(kdl_error) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue