pyc_shell/shell/
history.rs1use std::collections::VecDeque;
27
28pub struct ShellHistory {
29 history: VecDeque<String>
30}
31
32impl ShellHistory {
33
34 pub fn new() -> ShellHistory {
38 ShellHistory {
39 history: VecDeque::with_capacity(2048)
40 }
41 }
42
43 pub fn at(&self, index: usize) -> Option<String> {
48 match self.history.get(index) {
49 Some(s) => Some(s.clone()),
50 None => None
51 }
52 }
53
54 pub fn clear(&mut self) {
58 self.history.clear();
59 }
60
61 pub fn dump(&mut self) -> Vec<String> {
65 let mut history: Vec<String> = Vec::with_capacity(self.history.len());
66 for entry in self.history.iter().rev() {
67 history.push(entry.clone());
68 }
69 history
70 }
71
72 pub fn len(&self) -> usize {
76 self.history.len()
77 }
78
79 pub fn load(&mut self, lines: Vec<String>) {
84 self.clear();
86 for line in lines.iter() {
88 self.push(line.clone());
89 }
90 }
91
92 pub fn push(&mut self, mut line: String) {
97 while line.ends_with("\n") {
99 line.pop();
100 }
101 if line.is_empty() {
103 return;
104 }
105 if let Some(last_line) = self.at(0) {
107 if last_line == line {
108 return
109 }
110 }
111 let size: usize = (self.history.capacity() + 1) / 2;
113 if self.history.len() + 1 > size {
114 self.history.pop_back();
115 }
116 self.history.push_front(line);
117 }
118
119}
120
121#[cfg(test)]
124mod tests {
125
126 use super::*;
127
128 #[test]
129 fn test_shell_history() {
130 let mut history: ShellHistory = ShellHistory::new();
131 assert_eq!(history.history.capacity(), (2048 * 2 - 1)); history.load(vec![String::from("ls"), String::from("cd /tmp/")]);
134 assert_eq!(history.len(), 2);
135 assert_eq!(history.at(0).unwrap(), String::from("cd /tmp/"));
137 assert_eq!(history.at(1).unwrap(), String::from("ls"));
138 assert!(history.at(2).is_none());
139 history.push(String::from("pwd\n\n\n")); assert_eq!(history.len(), 3);
142 assert_eq!(history.at(0).unwrap(), String::from("pwd"));
143 history.push(String::from("pwd"));
145 assert_eq!(history.len(), 3);
146 history.push(String::from("\n"));
148 assert_eq!(history.len(), 3);
149 let mut history_vec: Vec<String> = Vec::with_capacity(2048);
151 for i in 0..2048 {
152 history_vec.push(format!("echo {}", i));
153 }
154 history.load(history_vec);
155 assert_eq!(history.len(), 2048);
156 assert_eq!(history.at(0).unwrap(), String::from("echo 2047"));
157 assert_eq!(history.at(2047).unwrap(), String::from("echo 0"));
158 history.push(String::from("echo 2048"));
160 assert_eq!(history.len(), 2048);
161 assert_eq!(history.at(0).unwrap(), String::from("echo 2048"));
162 assert_eq!(history.at(2047).unwrap(), String::from("echo 1"));
163 history.clear();
165 assert_eq!(history.len(), 0);
166 history.push(String::from("ls -l"));
168 history.push(String::from("cd /tmp/"));
169 let dump: Vec<String> = history.dump();
171 assert_eq!(dump.len(), 2);
172 assert_eq!(*dump.get(0).unwrap(), String::from("ls -l"));
174 assert_eq!(*dump.get(1).unwrap(), String::from("cd /tmp/"));
175 }
176
177}