use std::collections::VecDeque;
pub struct ShellHistory {
history: VecDeque<String>
}
impl ShellHistory {
pub fn new() -> ShellHistory {
ShellHistory {
history: VecDeque::with_capacity(2048)
}
}
pub fn at(&self, index: usize) -> Option<String> {
match self.history.get(index) {
Some(s) => Some(s.clone()),
None => None
}
}
pub fn clear(&mut self) {
self.history.clear();
}
pub fn dump(&mut self) -> Vec<String> {
let mut history: Vec<String> = Vec::with_capacity(self.history.len());
for entry in self.history.iter().rev() {
history.push(entry.clone());
}
history
}
pub fn len(&self) -> usize {
self.history.len()
}
pub fn load(&mut self, lines: Vec<String>) {
self.clear();
for line in lines.iter() {
self.push(line.clone());
}
}
pub fn push(&mut self, mut line: String) {
while line.ends_with("\n") {
line.pop();
}
if line.is_empty() {
return;
}
if let Some(last_line) = self.at(0) {
if last_line == line {
return
}
}
let size: usize = (self.history.capacity() + 1) / 2;
if self.history.len() + 1 > size {
self.history.pop_back();
}
self.history.push_front(line);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shell_history() {
let mut history: ShellHistory = ShellHistory::new();
assert_eq!(history.history.capacity(), (2048 * 2 - 1)); history.load(vec![String::from("ls"), String::from("cd /tmp/")]);
assert_eq!(history.len(), 2);
assert_eq!(history.at(0).unwrap(), String::from("cd /tmp/"));
assert_eq!(history.at(1).unwrap(), String::from("ls"));
assert!(history.at(2).is_none());
history.push(String::from("pwd\n\n\n")); assert_eq!(history.len(), 3);
assert_eq!(history.at(0).unwrap(), String::from("pwd"));
history.push(String::from("pwd"));
assert_eq!(history.len(), 3);
history.push(String::from("\n"));
assert_eq!(history.len(), 3);
let mut history_vec: Vec<String> = Vec::with_capacity(2048);
for i in 0..2048 {
history_vec.push(format!("echo {}", i));
}
history.load(history_vec);
assert_eq!(history.len(), 2048);
assert_eq!(history.at(0).unwrap(), String::from("echo 2047"));
assert_eq!(history.at(2047).unwrap(), String::from("echo 0"));
history.push(String::from("echo 2048"));
assert_eq!(history.len(), 2048);
assert_eq!(history.at(0).unwrap(), String::from("echo 2048"));
assert_eq!(history.at(2047).unwrap(), String::from("echo 1"));
history.clear();
assert_eq!(history.len(), 0);
history.push(String::from("ls -l"));
history.push(String::from("cd /tmp/"));
let dump: Vec<String> = history.dump();
assert_eq!(dump.len(), 2);
assert_eq!(*dump.get(0).unwrap(), String::from("ls -l"));
assert_eq!(*dump.get(1).unwrap(), String::from("cd /tmp/"));
}
}