Skip to main content

rmux_core/session/
resize.rs

1use rmux_proto::{ResizePaneAdjustment, RmuxError, SplitDirection};
2
3use super::target_error::{invalid_pane_target, invalid_window_target};
4use super::Session;
5
6impl Session {
7    /// Applies the supported resize adjustment to the session layout.
8    pub fn resize_pane(
9        &mut self,
10        pane_index: u32,
11        adjustment: ResizePaneAdjustment,
12    ) -> Result<(), RmuxError> {
13        self.resize_pane_in_window(self.active_window, pane_index, adjustment)
14    }
15
16    /// Applies the supported resize adjustment to the addressed window.
17    pub fn resize_pane_in_window(
18        &mut self,
19        window_index: u32,
20        pane_index: u32,
21        adjustment: ResizePaneAdjustment,
22    ) -> Result<(), RmuxError> {
23        if adjustment == ResizePaneAdjustment::Zoom {
24            return self.toggle_zoom_in_window(window_index, pane_index);
25        }
26
27        self.ensure_resize_target(window_index, pane_index)?;
28        let window = self
29            .window_at_mut(window_index)
30            .expect("addressed session window must exist");
31
32        match adjustment {
33            ResizePaneAdjustment::NoOp => {}
34            ResizePaneAdjustment::AbsoluteWidth { columns } => {
35                let _ = window.resize_pane_width(pane_index, columns);
36            }
37            ResizePaneAdjustment::AbsoluteHeight { rows } => {
38                let _ = window.resize_pane_height(pane_index, rows);
39            }
40            ResizePaneAdjustment::AbsoluteSize { columns, rows } => {
41                let _ = window.resize_pane_width(pane_index, columns);
42                let _ = window.resize_pane_height(pane_index, rows);
43            }
44            ResizePaneAdjustment::Composite {
45                columns,
46                rows,
47                relative,
48                cells,
49            } => {
50                if let Some(columns) = columns {
51                    let _ = window.resize_pane_width(pane_index, columns);
52                }
53                if let Some(rows) = rows {
54                    let _ = window.resize_pane_height(pane_index, rows);
55                }
56                if let Some(relative) = relative {
57                    let _ = window.resize_pane_by(pane_index, relative.to_adjustment(cells));
58                }
59            }
60            ResizePaneAdjustment::Up { cells } => {
61                let _ = window.resize_pane_by(pane_index, ResizePaneAdjustment::Up { cells });
62            }
63            ResizePaneAdjustment::Down { cells } => {
64                let _ = window.resize_pane_by(pane_index, ResizePaneAdjustment::Down { cells });
65            }
66            ResizePaneAdjustment::Left { cells } => {
67                let _ = window.resize_pane_by(pane_index, ResizePaneAdjustment::Left { cells });
68            }
69            ResizePaneAdjustment::Right { cells } => {
70                let _ = window.resize_pane_by(pane_index, ResizePaneAdjustment::Right { cells });
71            }
72            ResizePaneAdjustment::TrimBelow => {}
73            ResizePaneAdjustment::Zoom => unreachable!("zoom returned early"),
74        }
75        Ok(())
76    }
77
78    /// Resizes the addressed pane to an exact size along the split axis.
79    pub fn resize_pane_to_in_window(
80        &mut self,
81        window_index: u32,
82        pane_index: u32,
83        direction: SplitDirection,
84        size: u32,
85    ) -> Result<(), RmuxError> {
86        self.ensure_resize_target(window_index, pane_index)?;
87        let window = self
88            .window_at_mut(window_index)
89            .expect("addressed session window must exist");
90        let _ = window.resize_pane_to(pane_index, direction, size.max(1));
91        Ok(())
92    }
93
94    /// Resizes the newly split pane while keeping the adjustment inside the
95    /// original target pane cell. Plain `resize_pane_to` follows tmux's normal
96    /// border-selection rules and may borrow size from the next sibling when a
97    /// pane is not last. For `split-window -l`, tmux instead sizes the new pane
98    /// against the pane it just split, leaving unrelated neighbours untouched.
99    pub fn resize_new_split_pane_to_in_window(
100        &mut self,
101        window_index: u32,
102        new_pane_index: u32,
103        direction: SplitDirection,
104        size: u32,
105        inserted_before_target: bool,
106    ) -> Result<(), RmuxError> {
107        self.ensure_resize_target(window_index, new_pane_index)?;
108        let window = self
109            .window_at_mut(window_index)
110            .expect("addressed session window must exist");
111        let _ = window.resize_new_split_pane_to(
112            new_pane_index,
113            direction,
114            size,
115            inserted_before_target,
116        );
117        Ok(())
118    }
119
120    /// Toggles zoom for the addressed pane's window.
121    pub fn toggle_zoom_in_window(
122        &mut self,
123        window_index: u32,
124        pane_index: u32,
125    ) -> Result<(), RmuxError> {
126        self.ensure_resize_target(window_index, pane_index)?;
127        self.window_at_mut(window_index)
128            .expect("addressed session window must exist")
129            .toggle_zoom(pane_index);
130        Ok(())
131    }
132
133    fn ensure_resize_target(&self, window_index: u32, pane_index: u32) -> Result<(), RmuxError> {
134        if self.window_at(window_index).is_none() {
135            return Err(invalid_window_target(&self.name, window_index));
136        }
137
138        if self
139            .window_at(window_index)
140            .and_then(|window| window.pane(pane_index))
141            .is_none()
142        {
143            return Err(invalid_pane_target(
144                &self.name,
145                window_index,
146                pane_index,
147                "pane index does not exist in session",
148            ));
149        }
150
151        Ok(())
152    }
153}