1use crate::error::ModCliError;
8use std::fs::{self, File, OpenOptions};
9use std::io::{BufRead, BufReader, Write};
10use std::path::{Path, PathBuf};
11
12pub fn default_history_path() -> PathBuf {
14 if let Ok(home) = std::env::var("HOME") {
16 let base = Path::new(&home).join(".config").join("modcli");
17 return base.join("history");
18 }
19 if let Ok(home) = std::env::var("USERPROFILE") {
21 let base = Path::new(&home)
22 .join("AppData")
23 .join("Roaming")
24 .join("modcli");
25 return base.join("history");
26 }
27 PathBuf::from(".modcli_history")
29}
30
31pub fn load(path: Option<&Path>) -> Vec<String> {
33 let p: PathBuf = path
34 .map(|p| p.to_path_buf())
35 .unwrap_or_else(default_history_path);
36 let file = match File::open(&p) {
37 Ok(f) => f,
38 Err(_) => return Vec::new(),
39 };
40 let reader = BufReader::new(file);
41 reader.lines().map_while(Result::ok).collect()
42}
43
44pub fn save(path: Option<&Path>, entries: &[String]) -> Result<(), ModCliError> {
46 let p: PathBuf = path
47 .map(|p| p.to_path_buf())
48 .unwrap_or_else(default_history_path);
49 if let Some(dir) = p.parent() {
50 fs::create_dir_all(dir)?;
51 }
52 let mut f = File::create(&p)?;
53 for e in entries {
54 writeln!(f, "{e}")?;
55 }
56 Ok(())
57}
58
59pub fn add(path: Option<&Path>, line: &str) -> Result<(), ModCliError> {
61 let p: PathBuf = path
62 .map(|p| p.to_path_buf())
63 .unwrap_or_else(default_history_path);
64 if let Some(dir) = p.parent() {
65 fs::create_dir_all(dir)?;
66 }
67 let mut f = OpenOptions::new().create(true).append(true).open(&p)?;
68 writeln!(f, "{line}")?;
69 Ok(())
70}
71
72pub fn search(entries: &[String], query: &str, limit: usize) -> Vec<String> {
74 if query.is_empty() {
75 return entries
76 .iter()
77 .rev()
78 .take(limit)
79 .cloned()
80 .collect::<Vec<_>>()
81 .into_iter()
82 .rev()
83 .collect();
84 }
85 let q = query.to_ascii_lowercase();
86 let mut out: Vec<String> = Vec::new();
87 for e in entries.iter().rev() {
88 if e.to_ascii_lowercase().contains(&q) {
89 out.push(e.clone());
90 if out.len() >= limit {
91 break;
92 }
93 }
94 }
95 out.reverse();
96 out
97}