Skip to main content

rush_sync_server/commands/history/
manager.rs

1use std::path::PathBuf;
2
3#[derive(Debug)]
4pub struct HistoryManager {
5    entries: Vec<String>,
6    position: Option<usize>,
7    max_size: usize,
8    file_path: PathBuf,
9}
10
11impl HistoryManager {
12    pub fn new(max_size: usize) -> Self {
13        let file_path = Self::get_history_path();
14
15        let mut manager = Self {
16            entries: Vec::with_capacity(max_size),
17            position: None,
18            max_size,
19            file_path,
20        };
21
22        // Load history from disk immediately
23        manager.load_from_file();
24        manager
25    }
26
27    fn get_history_path() -> PathBuf {
28        if let Ok(exe_path) = std::env::current_exe() {
29            if let Some(base_dir) = exe_path.parent() {
30                let history_path = base_dir.join(".rss").join("rush.history");
31
32                // Create directory if it doesn't exist
33                if let Some(parent) = history_path.parent() {
34                    let _ = std::fs::create_dir_all(parent);
35                }
36
37                return history_path;
38            }
39        }
40        PathBuf::from("rush.history") // Fallback
41    }
42
43    fn load_from_file(&mut self) {
44        if !self.file_path.exists() {
45            return;
46        }
47
48        if let Ok(content) = std::fs::read_to_string(&self.file_path) {
49            for line in content.lines() {
50                let trimmed = line.trim();
51                if !trimmed.is_empty() && !self.entries.contains(&trimmed.to_string()) {
52                    self.entries.push(trimmed.to_string());
53                }
54            }
55
56            // Trim to max_size
57            if self.entries.len() > self.max_size {
58                self.entries.drain(0..self.entries.len() - self.max_size);
59            }
60
61            log::info!("Loaded {} history entries", self.entries.len());
62        }
63    }
64
65    fn save_to_file(&self) {
66        let content = self.entries.join("\n");
67        if let Err(e) = std::fs::write(&self.file_path, content) {
68            log::error!("Failed to save history: {}", e);
69        }
70    }
71
72    pub fn add_entry(&mut self, entry: String) {
73        if entry.trim().is_empty() {
74            return;
75        }
76
77        // Remove duplicates
78        self.entries.retain(|e| e != &entry);
79
80        // Append new entry
81        if self.entries.len() >= self.max_size {
82            self.entries.remove(0);
83        }
84
85        self.entries.push(entry);
86        self.position = None;
87
88        // Persist immediately
89        self.save_to_file();
90    }
91
92    pub fn navigate_previous(&mut self) -> Option<String> {
93        if let Some(pos) = self.position {
94            if pos > 0 {
95                self.position = Some(pos - 1);
96                return self.entries.get(pos - 1).cloned();
97            }
98        } else if !self.entries.is_empty() {
99            self.position = Some(self.entries.len() - 1);
100            return self.entries.last().cloned();
101        }
102        None
103    }
104
105    pub fn navigate_next(&mut self) -> Option<String> {
106        if let Some(pos) = self.position {
107            if pos < self.entries.len() - 1 {
108                self.position = Some(pos + 1);
109                return self.entries.get(pos + 1).cloned();
110            } else {
111                self.position = None;
112                return Some(String::new()); // Empty = clear input
113            }
114        }
115        None
116    }
117
118    pub fn clear(&mut self) {
119        self.entries.clear();
120        self.position = None;
121
122        let _ = std::fs::remove_file(&self.file_path);
123        log::info!("History cleared");
124    }
125
126    pub fn reset_position(&mut self) {
127        self.position = None;
128    }
129
130    pub fn get_all_entries(&self) -> Vec<String> {
131        self.entries.clone()
132    }
133
134    pub fn import_entries(&mut self, entries: Vec<String>) {
135        for entry in entries {
136            if !entry.trim().is_empty() && !self.entries.contains(&entry) {
137                self.entries.push(entry);
138            }
139        }
140
141        if self.entries.len() > self.max_size {
142            self.entries.drain(0..self.entries.len() - self.max_size);
143        }
144
145        self.save_to_file();
146    }
147
148    pub fn entry_count(&self) -> usize {
149        self.entries.len()
150    }
151}