rmux_core/session/window_ops/
navigation.rs1use rmux_proto::RmuxError;
2
3use super::super::target_error::invalid_window_target;
4use super::super::Session;
5
6impl Session {
7 pub fn select_window(&mut self, window_index: u32) -> Result<(), RmuxError> {
9 if !self.windows.contains_key(&window_index) {
10 return Err(invalid_window_target(&self.name, window_index));
11 }
12
13 if self.active_window != window_index {
14 self.last_window = Some(self.active_window);
15 self.active_window = window_index;
16 self.group_initial_window_id = None;
17 let _ = self.clear_all_winlink_alert_flags(window_index);
18 }
19
20 Ok(())
21 }
22
23 pub fn next_window(&mut self) -> Result<u32, RmuxError> {
25 self.next_window_alert_mode(false)
26 }
27
28 pub fn next_window_with_alerts(&mut self) -> Result<u32, RmuxError> {
30 self.next_window_alert_mode(true)
31 }
32
33 fn next_window_alert_mode(&mut self, alerts_only: bool) -> Result<u32, RmuxError> {
34 if self.windows.len() <= 1 {
35 return Err(RmuxError::Message("no next window".to_owned()));
36 }
37
38 let next_window = self
39 .ordered_window_indexes_after(self.active_window, true)
40 .find(|window_index| {
41 !alerts_only
42 || self
43 .winlink_alert_flags(*window_index)
44 .intersects(crate::WINLINK_ALERTFLAGS)
45 })
46 .ok_or_else(|| RmuxError::Message("no next window".to_owned()))?;
47 self.select_window(next_window)?;
48 Ok(next_window)
49 }
50
51 pub fn previous_window(&mut self) -> Result<u32, RmuxError> {
53 self.previous_window_alert_mode(false)
54 }
55
56 pub fn previous_window_with_alerts(&mut self) -> Result<u32, RmuxError> {
58 self.previous_window_alert_mode(true)
59 }
60
61 fn previous_window_alert_mode(&mut self, alerts_only: bool) -> Result<u32, RmuxError> {
62 if self.windows.len() <= 1 {
63 return Err(RmuxError::Message("no previous window".to_owned()));
64 }
65
66 let previous_window = self
67 .ordered_window_indexes_after(self.active_window, false)
68 .find(|window_index| {
69 !alerts_only
70 || self
71 .winlink_alert_flags(*window_index)
72 .intersects(crate::WINLINK_ALERTFLAGS)
73 })
74 .ok_or_else(|| RmuxError::Message("no previous window".to_owned()))?;
75 self.select_window(previous_window)?;
76 Ok(previous_window)
77 }
78
79 pub fn last_window(&mut self) -> Result<u32, RmuxError> {
81 let last_window = self
82 .last_window
83 .ok_or_else(|| RmuxError::Message("no last window".to_owned()))?;
84 self.select_window(last_window)?;
85 Ok(last_window)
86 }
87
88 pub fn restore_last_window_after_active_unlink(&mut self) {
90 if self.last_window.is_some() {
91 return;
92 }
93 let next_last = self
94 .ordered_window_indexes_after(self.active_window, true)
95 .next();
96 self.last_window = next_last;
97 }
98
99 fn ordered_window_indexes_after(
100 &self,
101 start_window: u32,
102 forward: bool,
103 ) -> impl Iterator<Item = u32> + '_ {
104 let ordered = self.windows.keys().copied().collect::<Vec<_>>();
105 let Some(start_index) = ordered
106 .iter()
107 .position(|window_index| *window_index == start_window)
108 else {
109 return Vec::new().into_iter();
110 };
111
112 let len = ordered.len();
113 let mut next = Vec::with_capacity(len.saturating_sub(1));
114 for offset in 1..len {
115 let index = if forward {
116 (start_index + offset) % len
117 } else {
118 (start_index + len - offset) % len
119 };
120 next.push(ordered[index]);
121 }
122 next.into_iter()
123 }
124}