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