leetcode_tui_core/
utils.rs

1use 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            //first window
113            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            // last_window
122            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}