Skip to main content

rmux_core/
pane.rs

1use rmux_proto::{PaneTarget, SessionName};
2
3pub use rmux_proto::PaneId;
4
5/// A pane rectangle within terminal coordinates.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct PaneGeometry {
8    x: u16,
9    y: u16,
10    cols: u16,
11    rows: u16,
12}
13
14impl PaneGeometry {
15    /// Creates a pane rectangle at the given position and size.
16    #[must_use]
17    pub const fn new(x: u16, y: u16, cols: u16, rows: u16) -> Self {
18        Self { x, y, cols, rows }
19    }
20
21    /// Returns the left-most column of the pane.
22    #[must_use]
23    pub const fn x(&self) -> u16 {
24        self.x
25    }
26
27    /// Returns the top-most row of the pane.
28    #[must_use]
29    pub const fn y(&self) -> u16 {
30        self.y
31    }
32
33    /// Returns the pane width in columns.
34    #[must_use]
35    pub const fn cols(&self) -> u16 {
36        self.cols
37    }
38
39    /// Returns the pane height in rows.
40    #[must_use]
41    pub const fn rows(&self) -> u16 {
42        self.rows
43    }
44}
45
46/// Pure in-memory pane state.
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct Pane {
49    id: PaneId,
50    index: u32,
51    geometry: PaneGeometry,
52    active_point: u64,
53}
54
55impl Pane {
56    /// Returns the pane's stable internal identity.
57    #[must_use]
58    pub const fn id(&self) -> PaneId {
59        self.id
60    }
61
62    /// Returns the stable pane index used by detached targets.
63    #[must_use]
64    pub const fn index(&self) -> u32 {
65        self.index
66    }
67
68    /// Returns the pane's current geometry.
69    #[must_use]
70    pub const fn geometry(&self) -> PaneGeometry {
71        self.geometry
72    }
73
74    pub(crate) const fn active_point(&self) -> u64 {
75        self.active_point
76    }
77
78    /// Builds an exact pane target for this pane in the given session.
79    #[must_use]
80    pub fn target(&self, session_name: &SessionName) -> PaneTarget {
81        PaneTarget::new(session_name.clone(), self.index)
82    }
83
84    #[cfg_attr(not(test), allow(dead_code))]
85    pub(crate) const fn new(index: u32, geometry: PaneGeometry) -> Self {
86        Self::new_with_id(PaneId::new(index), index, geometry)
87    }
88
89    pub(crate) const fn new_with_id(id: PaneId, index: u32, geometry: PaneGeometry) -> Self {
90        Self {
91            id,
92            index,
93            geometry,
94            active_point: 0,
95        }
96    }
97
98    pub(crate) fn set_geometry(&mut self, geometry: PaneGeometry) {
99        self.geometry = geometry;
100    }
101
102    pub(crate) fn set_index(&mut self, index: u32) {
103        self.index = index;
104    }
105
106    pub(crate) fn set_active_point(&mut self, active_point: u64) {
107        self.active_point = active_point;
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::{Pane, PaneGeometry, PaneId};
114    use rmux_proto::SessionName;
115
116    #[test]
117    fn geometry_accessors_match_constructor_values() {
118        let geometry = PaneGeometry::new(4, 7, 80, 24);
119
120        assert_eq!(geometry.x(), 4);
121        assert_eq!(geometry.y(), 7);
122        assert_eq!(geometry.cols(), 80);
123        assert_eq!(geometry.rows(), 24);
124    }
125
126    #[test]
127    fn pane_target_uses_session_name_and_index() {
128        let pane = Pane::new(3, PaneGeometry::new(0, 0, 10, 5));
129        let session_name = SessionName::new("alpha").expect("valid session name");
130
131        assert_eq!(pane.target(&session_name).to_string(), "alpha:0.3");
132    }
133
134    #[test]
135    fn pane_id_is_stable_and_independent_from_display_index() {
136        let pane = Pane::new_with_id(PaneId::new(9), 3, PaneGeometry::new(0, 0, 10, 5));
137
138        assert_eq!(pane.id(), PaneId::new(9));
139        assert_eq!(pane.index(), 3);
140    }
141
142    #[test]
143    fn set_geometry_replaces_the_existing_rectangle() {
144        let mut pane = Pane::new(0, PaneGeometry::new(0, 0, 10, 5));
145        let replacement = PaneGeometry::new(12, 1, 34, 50);
146
147        pane.set_geometry(replacement);
148
149        assert_eq!(pane.geometry(), replacement);
150    }
151}