dialoguer_ext/history.rs
1use std::collections::VecDeque;
2
3/// Trait for history handling.
4pub trait History<T> {
5 /// This is called with the current position that should
6 /// be read from history. The `pos` represents the number
7 /// of times the `Up`/`Down` arrow key has been pressed.
8 /// This would normally be used as an index to some sort
9 /// of vector. If the `pos` does not have an entry, [`None`](Option::None)
10 /// should be returned.
11 fn read(&self, pos: usize) -> Option<String>;
12
13 /// This is called with the next value you should store
14 /// in history at the first location. Normally history
15 /// is implemented as a FIFO queue.
16 fn write(&mut self, val: &T);
17}
18
19pub struct BasicHistory {
20 max_entries: Option<usize>,
21 deque: VecDeque<String>,
22 no_duplicates: bool,
23}
24
25impl BasicHistory {
26 /// Creates a new basic history value which has no limit on the number of
27 /// entries and allows for duplicates.
28 ///
29 /// # Example
30 ///
31 /// A history with at most 8 entries and no duplicates:
32 ///
33 /// ```rs
34 /// let mut history = BasicHistory::new().max_entries(8).no_duplicates(true);
35 /// ```
36 pub fn new() -> Self {
37 Self {
38 max_entries: None,
39 deque: VecDeque::new(),
40 no_duplicates: false,
41 }
42 }
43
44 /// Limit the number of entries stored in the history.
45 pub fn max_entries(self, max_entries: usize) -> Self {
46 Self {
47 max_entries: Some(max_entries),
48 ..self
49 }
50 }
51
52 /// Prevent duplicates in the history. This means that any previous entries
53 /// that are equal to a new entry are removed before the new entry is added.
54 pub fn no_duplicates(self, no_duplicates: bool) -> Self {
55 Self {
56 no_duplicates,
57 ..self
58 }
59 }
60}
61
62impl<T: ToString> History<T> for BasicHistory {
63 fn read(&self, pos: usize) -> Option<String> {
64 self.deque.get(pos).cloned()
65 }
66
67 fn write(&mut self, val: &T) {
68 let val = val.to_string();
69
70 if self.no_duplicates {
71 self.deque.retain(|v| v != &val);
72 }
73
74 self.deque.push_front(val);
75
76 if let Some(max_entries) = self.max_entries {
77 self.deque.truncate(max_entries);
78 }
79 }
80}
81
82impl Default for BasicHistory {
83 fn default() -> Self {
84 Self::new()
85 }
86}