rush_sync_server/commands/history/
manager.rs1use 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 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 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") }
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 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 self.entries.retain(|e| e != &entry);
79
80 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 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()); }
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}