leetcode_tui_core/
utils.rs1use crate::emit;
2pub(crate) mod string_ops;
3
4use rand::{thread_rng, Rng};
5use std::ops::Range;
6
7pub struct Paginate<T> {
8 list: Vec<T>,
9 nth_window: usize,
10 cursor_range: Range<usize>,
11 cursor: usize,
12 hovered: Option<T>,
13}
14
15impl<T> Paginate<T>
16where
17 T: Clone,
18{
19 pub fn new(list: Vec<T>) -> Self {
20 let hovered = list.first().cloned();
21 Self {
22 list,
23 nth_window: Default::default(),
24 cursor_range: Default::default(),
25 cursor: Default::default(),
26 hovered,
27 }
28 }
29
30 pub fn update_list(&mut self, list: Vec<T>) {
31 *self = Self::new(list)
32 }
33}
34
35impl<T> Paginate<T>
36where
37 T: Clone,
38{
39 pub fn next_elem(&mut self, wid_height: usize) -> bool {
40 if self.list.is_empty() {
41 emit!(Popup(vec!["List is empty".into()]));
42 return true;
43 }
44 self.set_cursor_range(wid_height);
45 let old_cursor = self.cursor;
46 let old_window = self.nth_window;
47
48 if self.cursor >= self.cursor_range.end {
49 self.nth_window = self.nth_window.saturating_add(1).min(
50 self.list
51 .windows(self.cursor_upper_bound(wid_height))
52 .count()
53 - 1,
54 );
55 } else {
56 self.cursor = (self.cursor + 1).min(self.cursor_upper_bound(wid_height) - 1);
57 }
58 self.hovered = self.window(wid_height).get(self.cursor).cloned();
59 self.cursor != old_cursor || self.nth_window != old_window
60 }
61
62 pub fn prev_elem(&mut self, wid_height: usize) -> bool {
63 if self.list.is_empty() {
64 emit!(Popup(vec!["List is empty".into()]));
65 return true;
66 }
67 self.set_cursor_range(wid_height);
68 let old_cursor = self.cursor;
69 let old_window = self.nth_window;
70
71 if self.cursor < self.cursor_range.start {
72 self.nth_window = self.nth_window.saturating_sub(1);
73 } else {
74 self.cursor = self.cursor.saturating_sub(1);
75 }
76
77 self.hovered = self.window(wid_height).get(self.cursor).cloned();
78 self.cursor != old_cursor || self.nth_window != old_window
79 }
80
81 pub fn rand_elem(&mut self, wid_height: usize) -> bool {
82 if self.list.is_empty() {
83 emit!(Popup(vec!["List is empty".into()]));
84 return true;
85 }
86 self.set_cursor_range(wid_height);
87 let old_cursor = self.cursor;
88 let old_window = self.nth_window;
89
90 self.cursor = thread_rng().gen_range(0..self.cursor_upper_bound(wid_height));
91
92 let upper = self
93 .list
94 .windows(self.cursor_upper_bound(wid_height))
95 .count()
96 - 1;
97
98 if upper > 0 {
99 self.nth_window = thread_rng().gen_range(0..upper);
100 }
101
102 self.hovered = self.window(wid_height).get(self.cursor).cloned();
103 self.cursor != old_cursor || self.nth_window != old_window
104 }
105
106 fn set_cursor_range(&mut self, wid_height: usize) {
107 let mut b = self.cursor_upper_bound(wid_height);
108 if self.cursor_upper_bound(wid_height) >= wid_height {
109 b = self.cursor_upper_bound(wid_height).saturating_sub(3)
110 }
111 if self.nth_window == 0 {
112 self.cursor_range = 0..b;
114 } else if self.nth_window
115 == (self
116 .list
117 .windows(self.cursor_upper_bound(wid_height))
118 .count()
119 - 1)
120 {
121 self.cursor_range = 3..self.cursor_upper_bound(wid_height);
123 } else {
124 self.cursor_range = 3..self.cursor_upper_bound(wid_height) - 3;
125 }
126 }
127
128 pub fn set_element_by_index(&mut self, index: usize, wid_height: usize) -> bool {
129 if self.list.is_empty() {
130 emit!(Popup(vec!["List is empty".into()]));
131 return false;
132 }
133
134 if index >= self.list.len() {
135 emit!(Popup(vec!["Index out of bounds".into()]));
136 return false;
137 }
138
139 let old_cursor = self.cursor;
140 let old_window = self.nth_window;
141
142 self.nth_window = index / self.cursor_upper_bound(wid_height);
143 self.cursor = index % self.cursor_upper_bound(wid_height);
144
145 self.set_cursor_range(wid_height);
146 self.hovered = self.window(wid_height).get(self.cursor).cloned();
147
148 self.cursor != old_cursor || self.nth_window != old_window
149 }
150
151 fn cursor_upper_bound(&self, wid_height: usize) -> usize {
152 wid_height.min(self.list.len())
153 }
154
155 pub fn window(&self, wid_height: usize) -> &[T] {
156 self.list
157 .windows(self.cursor_upper_bound(wid_height))
158 .nth(self.nth_window)
159 .unwrap_or(&[])
160 }
161 pub fn hovered(&self) -> Option<&T> {
162 self.hovered.as_ref()
163 }
164}