Skip to main content

yazi_core/tab/
backstack.rs

1use yazi_shared::url::{Url, UrlBuf};
2
3#[derive(Default)]
4pub struct Backstack {
5	cursor: usize,
6	stack:  Vec<UrlBuf>,
7}
8
9impl Backstack {
10	pub fn push(&mut self, url: Url) {
11		if self.stack.is_empty() {
12			self.stack.push(url.to_owned());
13			return;
14		}
15
16		if self.stack[self.cursor] == url {
17			return;
18		}
19
20		self.cursor += 1;
21		if self.cursor == self.stack.len() {
22			self.stack.push(url.to_owned());
23		} else {
24			self.stack[self.cursor] = url.to_owned();
25			self.stack.truncate(self.cursor + 1);
26		}
27
28		// Only keep 30 URLs before the cursor, the cleanup threshold is 60
29		if self.stack.len() > 60 {
30			let start = self.cursor.saturating_sub(30);
31			self.stack.drain(..start);
32			self.cursor -= start;
33		}
34	}
35
36	pub fn current(&self) -> Option<&UrlBuf> { self.stack.get(self.cursor) }
37
38	pub fn shift_backward(&mut self) -> Option<&UrlBuf> {
39		if self.cursor > 0 {
40			self.cursor -= 1;
41			Some(&self.stack[self.cursor])
42		} else {
43			None
44		}
45	}
46
47	pub fn shift_forward(&mut self) -> Option<&UrlBuf> {
48		if self.cursor + 1 >= self.stack.len() {
49			None
50		} else {
51			self.cursor += 1;
52			Some(&self.stack[self.cursor])
53		}
54	}
55}
56
57#[cfg(test)]
58mod tests {
59	use super::*;
60
61	#[test]
62	fn test_backstack() {
63		let mut bs: Backstack = Backstack::default();
64		assert_eq!(bs.shift_forward(), None);
65
66		bs.push(Url::regular("1"));
67		assert_eq!(bs.stack[bs.cursor], Url::regular("1"));
68
69		bs.push(Url::regular("2"));
70		bs.push(Url::regular("3"));
71		assert_eq!(bs.stack[bs.cursor], Url::regular("3"));
72
73		assert_eq!(bs.shift_backward().unwrap(), Url::regular("2"));
74		assert_eq!(bs.shift_backward().unwrap(), Url::regular("1"));
75		assert_eq!(bs.shift_backward(), None);
76		assert_eq!(bs.shift_backward(), None);
77		assert_eq!(bs.stack[bs.cursor], Url::regular("1"));
78		assert_eq!(bs.shift_forward().unwrap(), Url::regular("2"));
79		assert_eq!(bs.shift_forward().unwrap(), Url::regular("3"));
80		assert_eq!(bs.shift_forward(), None);
81
82		bs.shift_backward();
83		bs.push(Url::regular("4"));
84
85		assert_eq!(bs.stack[bs.cursor], Url::regular("4"));
86		assert_eq!(bs.shift_forward(), None);
87		assert_eq!(bs.shift_backward().unwrap(), Url::regular("2"));
88	}
89}