Compare commits
No commits in common. "e4b9c41c2219db2f7c8a3b48b9b7e98f0adbee88" and "d0e17b93a32a6dc099791b8ade1a1570ca73b15f" have entirely different histories.
e4b9c41c22
...
d0e17b93a3
@ -4,15 +4,6 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## [0.7.1] - 2026-03-01
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Interactive setup wizard now asks for a tmux layout when a window has 2 or more panes
|
|
||||||
- Layout selection shown in post-wizard summary
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- README: Added ASCII art previews for each available tmux layout
|
|
||||||
|
|
||||||
## [0.7.0] - 2026-03-01
|
## [0.7.0] - 2026-03-01
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -864,7 +864,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tmuxido"
|
name = "tmuxido"
|
||||||
version = "0.7.1"
|
version = "0.7.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tmuxido"
|
name = "tmuxido"
|
||||||
version = "0.7.1"
|
version = "0.7.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
60
README.md
60
README.md
@ -158,61 +158,11 @@ panes = []
|
|||||||
|
|
||||||
### Available Layouts
|
### Available Layouts
|
||||||
|
|
||||||
**`main-horizontal`** — Main pane on top, others below
|
- `main-horizontal` - Main pane on top, others below
|
||||||
|
- `main-vertical` - Main pane on left, others on right
|
||||||
```
|
- `tiled` - All panes tiled
|
||||||
┌──────────────────────┐
|
- `even-horizontal` - All panes in horizontal row
|
||||||
│ │
|
- `even-vertical` - All panes in vertical column
|
||||||
│ main pane │
|
|
||||||
│ │
|
|
||||||
├──────────┬───────────┤
|
|
||||||
│ pane 2 │ pane 3 │
|
|
||||||
└──────────┴───────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**`main-vertical`** — Main pane on left, others on right
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────┬────────┐
|
|
||||||
│ │ pane 2 │
|
|
||||||
│ main pane ├────────┤
|
|
||||||
│ │ pane 3 │
|
|
||||||
│ ├────────┤
|
|
||||||
│ │ pane 4 │
|
|
||||||
└─────────────┴────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**`tiled`** — All panes tiled equally
|
|
||||||
|
|
||||||
```
|
|
||||||
┌───────────┬──────────┐
|
|
||||||
│ pane 1 │ pane 2 │
|
|
||||||
├───────────┼──────────┤
|
|
||||||
│ pane 3 │ pane 4 │
|
|
||||||
└───────────┴──────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**`even-horizontal`** — All panes side by side
|
|
||||||
|
|
||||||
```
|
|
||||||
┌────────┬────────┬────────┐
|
|
||||||
│ │ │ │
|
|
||||||
│ pane 1 │ pane 2 │ pane 3 │
|
|
||||||
│ │ │ │
|
|
||||||
└────────┴────────┴────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**`even-vertical`** — All panes stacked
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────────┐
|
|
||||||
│ pane 1 │
|
|
||||||
├──────────────────────┤
|
|
||||||
│ pane 2 │
|
|
||||||
├──────────────────────┤
|
|
||||||
│ pane 3 │
|
|
||||||
└──────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Panes
|
### Panes
|
||||||
|
|
||||||
|
|||||||
@ -181,19 +181,14 @@ impl Config {
|
|||||||
window_names
|
window_names
|
||||||
};
|
};
|
||||||
|
|
||||||
// Configure panes and layout for each window
|
// Configure panes for each window
|
||||||
let mut windows = Vec::new();
|
let mut windows = Vec::new();
|
||||||
for name in names {
|
for name in names {
|
||||||
let panes = Self::prompt_for_panes(&name)?;
|
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 {
|
windows.push(crate::session::Window {
|
||||||
name,
|
name,
|
||||||
panes,
|
panes,
|
||||||
layout,
|
layout: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,20 +348,6 @@ mod tests {
|
|||||||
assert_eq!(result, vec!["editor", "terminal", "server"]);
|
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]
|
#[test]
|
||||||
fn should_parse_config_with_windows_and_panes() {
|
fn should_parse_config_with_windows_and_panes() {
|
||||||
let toml_str = r#"
|
let toml_str = r#"
|
||||||
|
|||||||
111
src/ui.rs
111
src/ui.rs
@ -133,12 +133,6 @@ pub fn render_config_created(
|
|||||||
println!("{}", label_style.render(" 🪟 Default Windows:"));
|
println!("{}", label_style.render(" 🪟 Default Windows:"));
|
||||||
for window in windows {
|
for window in windows {
|
||||||
println!(" {}", window_style.render(&format!("◦ {}", window.name)));
|
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() {
|
if !window.panes.is_empty() {
|
||||||
for (i, pane) in window.panes.iter().enumerate() {
|
for (i, pane) in window.panes.iter().enumerate() {
|
||||||
let pane_display = if pane.is_empty() {
|
let pane_display = if pane.is_empty() {
|
||||||
@ -305,67 +299,6 @@ pub fn render_panes_prompt(window_name: &str) -> Result<String> {
|
|||||||
Ok(input.trim().to_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
|
/// Renders a prompt for a pane command
|
||||||
pub fn render_pane_command_prompt(pane_name: &str) -> Result<String> {
|
pub fn render_pane_command_prompt(pane_name: &str) -> Result<String> {
|
||||||
let prompt_style = Style::new().bold(true).foreground(color_green());
|
let prompt_style = Style::new().bold(true).foreground(color_green());
|
||||||
@ -598,50 +531,6 @@ mod tests {
|
|||||||
render_config_created(&vec!["~/Projects".to_string()], 5, true, 24, &windows);
|
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]
|
#[test]
|
||||||
fn render_config_created_with_disabled_cache_should_not_panic() {
|
fn render_config_created_with_disabled_cache_should_not_panic() {
|
||||||
let windows = vec![Window {
|
let windows = vec![Window {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user