🐛 fix: ask for layout in interactive wizard when window has multiple panes
Add `render_layout_prompt` and `parse_layout_input` to ui.rs so that the first-run wizard asks the user to choose a tmux layout (1–5 or by name) for each window that has 2 or more panes. Previously, layout was always silently set to None. Also update `render_config_created` to display the chosen layout in the post-setup summary. Closes: layout never being set during interactive setup
This commit is contained in:
parent
4ecdf96db8
commit
db08840b64
@ -181,14 +181,19 @@ impl Config {
|
||||
window_names
|
||||
};
|
||||
|
||||
// Configure panes for each window
|
||||
// Configure panes and layout for each window
|
||||
let mut windows = Vec::new();
|
||||
for name in names {
|
||||
let panes = Self::prompt_for_panes(&name)?;
|
||||
let layout = if panes.len() > 1 {
|
||||
ui::render_layout_prompt(&name, panes.len())?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
windows.push(crate::session::Window {
|
||||
name,
|
||||
panes,
|
||||
layout: None,
|
||||
layout,
|
||||
});
|
||||
}
|
||||
|
||||
@ -348,6 +353,20 @@ mod tests {
|
||||
assert_eq!(result, vec!["editor", "terminal", "server"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_use_ui_parse_functions_for_layout() {
|
||||
assert_eq!(ui::parse_layout_input(""), None);
|
||||
assert_eq!(
|
||||
ui::parse_layout_input("1"),
|
||||
Some("main-horizontal".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
ui::parse_layout_input("main-vertical"),
|
||||
Some("main-vertical".to_string())
|
||||
);
|
||||
assert_eq!(ui::parse_layout_input("invalid"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_config_with_windows_and_panes() {
|
||||
let toml_str = r#"
|
||||
|
||||
111
src/ui.rs
111
src/ui.rs
@ -133,6 +133,12 @@ pub fn render_config_created(
|
||||
println!("{}", label_style.render(" 🪟 Default Windows:"));
|
||||
for window in windows {
|
||||
println!(" {}", window_style.render(&format!("◦ {}", window.name)));
|
||||
if let Some(layout) = &window.layout {
|
||||
println!(
|
||||
"{}",
|
||||
info_style.render(&format!(" └─ layout: {}", layout))
|
||||
);
|
||||
}
|
||||
if !window.panes.is_empty() {
|
||||
for (i, pane) in window.panes.iter().enumerate() {
|
||||
let pane_display = if pane.is_empty() {
|
||||
@ -299,6 +305,67 @@ pub fn render_panes_prompt(window_name: &str) -> Result<String> {
|
||||
Ok(input.trim().to_string())
|
||||
}
|
||||
|
||||
/// Renders a prompt for the layout of a window with multiple panes
|
||||
pub fn render_layout_prompt(window_name: &str, pane_count: usize) -> Result<Option<String>> {
|
||||
let prompt_style = Style::new().bold(true).foreground(color_green());
|
||||
let hint_style = Style::new().italic(true).foreground(color_dark_gray());
|
||||
let window_style = Style::new().bold(true).foreground(color_purple());
|
||||
let label_style = Style::new().foreground(color_blue());
|
||||
|
||||
println!();
|
||||
println!(
|
||||
" Layout for window {} ({} panes):",
|
||||
window_style.render(window_name),
|
||||
label_style.render(&pane_count.to_string())
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
hint_style.render(" Choose a pane layout (leave empty for no layout):")
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
hint_style.render(" 1. main-horizontal — main pane on top, others below")
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
hint_style.render(" 2. main-vertical — main pane on left, others on right")
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
hint_style.render(" 3. tiled — all panes tiled equally")
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
hint_style.render(" 4. even-horizontal — all panes side by side")
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
hint_style.render(" 5. even-vertical — all panes stacked vertically")
|
||||
);
|
||||
print!(" {} ", prompt_style.render("❯ Layout (1-5 or name):"));
|
||||
io::stdout().flush().context("Failed to flush stdout")?;
|
||||
|
||||
let mut input = String::new();
|
||||
io::stdin()
|
||||
.read_line(&mut input)
|
||||
.context("Failed to read input")?;
|
||||
|
||||
Ok(parse_layout_input(input.trim()))
|
||||
}
|
||||
|
||||
/// Parse layout input: accepts number (1-5) or layout name; returns None for empty/invalid
|
||||
pub fn parse_layout_input(input: &str) -> Option<String> {
|
||||
match input.trim() {
|
||||
"" => None,
|
||||
"1" | "main-horizontal" => Some("main-horizontal".to_string()),
|
||||
"2" | "main-vertical" => Some("main-vertical".to_string()),
|
||||
"3" | "tiled" => Some("tiled".to_string()),
|
||||
"4" | "even-horizontal" => Some("even-horizontal".to_string()),
|
||||
"5" | "even-vertical" => Some("even-vertical".to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders a prompt for a pane command
|
||||
pub fn render_pane_command_prompt(pane_name: &str) -> Result<String> {
|
||||
let prompt_style = Style::new().bold(true).foreground(color_green());
|
||||
@ -531,6 +598,50 @@ mod tests {
|
||||
render_config_created(&vec!["~/Projects".to_string()], 5, true, 24, &windows);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_none_for_empty_layout_input() {
|
||||
assert_eq!(parse_layout_input(""), None);
|
||||
assert_eq!(parse_layout_input(" "), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_layout_by_number() {
|
||||
assert_eq!(parse_layout_input("1"), Some("main-horizontal".to_string()));
|
||||
assert_eq!(parse_layout_input("2"), Some("main-vertical".to_string()));
|
||||
assert_eq!(parse_layout_input("3"), Some("tiled".to_string()));
|
||||
assert_eq!(parse_layout_input("4"), Some("even-horizontal".to_string()));
|
||||
assert_eq!(parse_layout_input("5"), Some("even-vertical".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_layout_by_name() {
|
||||
assert_eq!(
|
||||
parse_layout_input("main-horizontal"),
|
||||
Some("main-horizontal".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
parse_layout_input("main-vertical"),
|
||||
Some("main-vertical".to_string())
|
||||
);
|
||||
assert_eq!(parse_layout_input("tiled"), Some("tiled".to_string()));
|
||||
assert_eq!(
|
||||
parse_layout_input("even-horizontal"),
|
||||
Some("even-horizontal".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
parse_layout_input("even-vertical"),
|
||||
Some("even-vertical".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_none_for_invalid_layout_input() {
|
||||
assert_eq!(parse_layout_input("6"), None);
|
||||
assert_eq!(parse_layout_input("0"), None);
|
||||
assert_eq!(parse_layout_input("unknown"), None);
|
||||
assert_eq!(parse_layout_input("horizontal"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_config_created_with_disabled_cache_should_not_panic() {
|
||||
let windows = vec![Window {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user