tmux_tui/
menu.rs

1//! Context-menu model and the menu-item builder.
2
3/// What a menu entry does when activated. Pane actions act on the menu's
4/// target pane; window actions on its target window.
5#[derive(Clone)]
6pub enum Action {
7    Kill,
8    Layout(&'static str, &'static str),
9    NewPane(&'static str, bool), // (split flag "-h"/"-v", before = left/above)
10    Submenu(&'static str),       // open a nested menu by name
11    RenameWindow,
12    NewWindow,
13    KillWindow,
14}
15
16/// A right-click context menu anchored at (x, y), acting on `target`.
17pub struct Menu {
18    pub x: u16,
19    pub y: u16,
20    pub target: Option<String>,
21    pub title: String,
22    pub items: Vec<(String, Action)>,
23    pub highlight: usize,
24}
25
26/// Build `(title, items)` for a menu screen by name. `n_panes` / `n_windows`
27/// gate destructive entries so we never offer to kill the last one.
28pub fn build_menu_items(
29    name: &str,
30    target: &Option<String>,
31    n_panes: usize,
32    n_windows: usize,
33) -> (String, Vec<(String, Action)>) {
34    match name {
35        "newpane" => (
36            "New pane".into(),
37            vec![
38                ("Right".into(), Action::NewPane("-h", false)),
39                ("Left".into(), Action::NewPane("-h", true)),
40                ("Above".into(), Action::NewPane("-v", true)),
41                ("Below".into(), Action::NewPane("-v", false)),
42                ("‹ back".into(), Action::Submenu("root")),
43            ],
44        ),
45        "win" => {
46            let mut items: Vec<(String, Action)> = Vec::new();
47            if target.is_some() {
48                items.push(("Rename window".into(), Action::RenameWindow));
49            }
50            items.push(("New window".into(), Action::NewWindow));
51            if target.is_some() && n_windows > 1 {
52                items.push(("Close window".into(), Action::KillWindow));
53            }
54            ("window".into(), items)
55        }
56        _ => {
57            let mut items: Vec<(String, Action)> = Vec::new();
58            items.push(("New pane          ▸".into(), Action::Submenu("newpane")));
59            if target.is_some() && n_panes > 1 {
60                items.push(("Kill pane".into(), Action::Kill));
61            }
62            items.push((
63                "Layout: side-by-side".into(),
64                Action::Layout("even-horizontal", "side-by-side"),
65            ));
66            items.push(("Layout: stacked".into(), Action::Layout("even-vertical", "stacked")));
67            items.push(("Layout: tiled".into(), Action::Layout("tiled", "tiled")));
68            items.push(("Rename window".into(), Action::RenameWindow));
69            ("actions".into(), items)
70        }
71    }
72}