use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize)]
pub struct CommandHistory {
frequency: HashMap<String, u32>,
#[serde(skip)]
history_file: PathBuf,
}
impl Clone for CommandHistory {
fn clone(&self) -> Self {
CommandHistory {
frequency: self.frequency.clone(),
history_file: Self::get_history_path(),
}
}
}
impl CommandHistory {
pub fn new() -> Self {
let history_file = Self::get_history_path();
let mut history = CommandHistory {
frequency: HashMap::new(),
history_file: history_file.clone(),
};
if history_file.exists() {
if let Ok(contents) = fs::read_to_string(&history_file) {
if let Ok(loaded) = serde_json::from_str::<CommandHistory>(&contents) {
history.frequency = loaded.frequency;
}
}
}
history
}
fn get_history_path() -> PathBuf {
let mut path = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
path.push(".term39");
let _ = fs::create_dir_all(&path);
path.push("command_history.json");
path
}
pub fn record_command(&mut self, command: &str) {
let cmd_name = command.split_whitespace().next().unwrap_or(command);
if !cmd_name.is_empty() {
*self.frequency.entry(cmd_name.to_string()).or_insert(0) += 1;
let _ = self.save();
}
}
pub fn get_frequency(&self, command: &str) -> u32 {
*self.frequency.get(command).unwrap_or(&0)
}
pub fn get_frequent_commands(&self) -> Vec<(String, u32)> {
let mut commands: Vec<_> = self
.frequency
.iter()
.map(|(k, v)| (k.clone(), *v))
.collect();
commands.sort_by(|a, b| b.1.cmp(&a.1)); commands
}
fn save(&self) -> Result<(), Box<dyn std::error::Error>> {
let json = serde_json::to_string_pretty(self)?;
fs::write(&self.history_file, json)?;
Ok(())
}
#[allow(dead_code)]
pub fn clear(&mut self) {
self.frequency.clear();
let _ = self.save();
}
}
impl Default for CommandHistory {
fn default() -> Self {
Self::new()
}
}