use std::io::{BufRead, BufReader};
use kimun_core::nfs::VaultPath;
use kimun_core::system::{self, SystemError, SystemPath};
pub const LAST_PATH_HISTORY_SIZE: usize = 50;
const HISTORY_FILE_EXT: &str = "txt";
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HistoryFile {
path: SystemPath,
}
impl HistoryFile {
pub fn in_dir(dir: &SystemPath, workspace_name: &str) -> Self {
Self {
path: dir.join(format!("{workspace_name}.{HISTORY_FILE_EXT}")),
}
}
pub fn path(&self) -> &SystemPath {
&self.path
}
pub fn exists(&self) -> bool {
self.path.exists()
}
pub fn load(&self) -> Vec<VaultPath> {
let file = match std::fs::File::open(&self.path) {
Ok(f) => f,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Vec::new(),
Err(e) => {
tracing::warn!("failed to open history file {}: {}", self.path, e);
return Vec::new();
}
};
BufReader::new(file)
.lines()
.map_while(Result::ok)
.filter_map(|line| {
let candidate = VaultPath::new(line.trim());
(!candidate.to_string().is_empty()).then_some(candidate)
})
.collect()
}
pub fn push(&self, path: &VaultPath) -> Result<(), SystemError> {
let mut existing = self.load();
if existing.first().is_some_and(|f| f.is_like(path)) {
return Ok(());
}
existing.retain(|p| !p.is_like(path));
existing.insert(0, path.clone());
existing.truncate(LAST_PATH_HISTORY_SIZE);
self.write(&existing)
}
pub fn write(&self, paths: &[VaultPath]) -> Result<(), SystemError> {
let mut body = String::new();
for path in paths {
body.push_str(&path.to_string());
body.push('\n');
}
system::replace_atomically(self.path.as_path(), body.as_bytes())
}
pub fn move_to(&self, dest: &HistoryFile) -> Result<(), SystemError> {
if !self.exists() {
return Ok(());
}
if dest.exists() {
return Err(SystemError::AlreadyExists {
path: dest.path.to_string(),
});
}
system::move_file(self.path.as_path(), dest.path.as_path())
}
pub fn remove(&self) -> Result<(), SystemError> {
system::remove_file(self.path.as_path())
}
}
impl std::fmt::Display for HistoryFile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.path)
}
}