use std::cell::Cell;
use std::collections::VecDeque;
use std::fs;
use std::io::{self, prelude::*};
use std::path::PathBuf;
pub struct History {
buffer: VecDeque<Vec<String>>,
iter_i: Cell<isize>,
path: Option<PathBuf>,
}
impl History {
pub fn with_capacity(capacity: usize, path: Option<PathBuf>) -> Self {
Self {
buffer: VecDeque::with_capacity(capacity + 1),
iter_i: Cell::new(-1),
path,
}
}
fn at_capacity(&self) -> bool {
self.buffer.len() == self.buffer.capacity()
}
pub fn push(&mut self, lines: Vec<String>) {
if self.at_capacity() {
self.buffer.pop_back();
}
self.reset_iter();
self.buffer.push_front(lines);
}
pub fn read_from_file(&mut self) -> io::Result<()> {
let contents = fs::read_to_string(self.path.as_ref().ok_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, "Path to persisted file not found")
})?)?;
let mut lines = Vec::new();
for line in contents.lines() {
if line.starts_with("---") {
self.push(lines);
lines = Vec::new();
} else {
lines.push(line.to_owned());
}
}
Ok(())
}
pub fn write_to_file(&self) -> io::Result<()> {
let mut f = fs::File::create(self.path.as_ref().ok_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, "Path to persisted file not found")
})?)?;
for lines in self.buffer.iter().rev() {
for line in lines {
f.write_all(line.as_bytes())?;
f.write_all(b"\n")?;
}
f.write_all(b"---\n")?;
}
Ok(())
}
fn _len(&self) -> isize {
self.buffer.len() as isize
}
pub fn len(&self) -> usize {
self.buffer.len()
}
fn _at(&self, index: isize) -> Option<&Vec<String>> {
if index >= 0 {
Some(&self.buffer[index as usize])
} else {
None
}
}
pub fn cur(&self) -> Option<&Vec<String>> {
if self.len() > 0 {
self._at(self.iter_i.get())
} else {
None
}
}
pub fn prev(&self) -> Option<&Vec<String>> {
let iter_i = self.iter_i.get() + 1;
if iter_i < self._len() {
self.iter_i.set(iter_i);
self._at(iter_i)
} else {
None
}
}
pub fn next(&self) -> Option<&Vec<String>> {
let iter_i = self.iter_i.get() - 1;
if iter_i >= -1 {
self.iter_i.set(iter_i);
self._at(iter_i)
} else {
None
}
}
pub fn reset_iter(&self) {
self.iter_i.set(-1);
}
#[allow(dead_code)]
pub fn clear(&mut self) {
self.buffer.clear();
self.reset_iter();
}
}
impl std::ops::Index<usize> for History {
type Output = Vec<String>;
fn index(&self, index: usize) -> &Self::Output {
&self.buffer[index]
}
}
impl Drop for History {
fn drop(&mut self) {
let _ = self.write_to_file();
}
}