1use crate::dirs::WindshDirs;
2use chrono::prelude::*;
3use serde::{Deserialize, Serialize};
4use std::fs;
5use std::path::PathBuf;
6
7#[derive(Debug, Deserialize, Serialize)]
8pub struct HistoryItem {
9 datetime: Option<String>,
10 cmd: Option<String>,
11}
12
13#[derive(Debug, Clone)]
14pub struct History {
15 datetime: DateTime<Utc>,
16 cmd: String,
17}
18
19impl History {
20 pub fn new() -> Self {
21 Self {
22 datetime: Utc::now(),
23 cmd: String::new(),
24 }
25 }
26
27 pub fn from(cmd: &str) -> Self {
28 Self {
29 datetime: Utc::now(),
30 cmd: String::from(cmd),
31 }
32 }
33
34 pub fn save(&self, history_file: Option<&str>) {
35 let mut history_file_path = PathBuf::new();
36
37 #[cfg(unix)]
38 if history_file == None {
39 history_file_path.push(
40 format!(
41 "{}/history.yml",
42 WindshDirs::load()
43 .config_dir()
44 .to_str()
45 .expect("Cannot convert config_dir path to str")
46 )
47 .as_str(),
48 );
49 } else {
50 history_file_path
51 .push(history_file.expect("Cannot get the history file"));
52 }
53
54 #[cfg(windows)]
55 if history_file == None {
56 history_file_path.push(
57 format!(
58 "{}/history.yml",
59 WindshDirs::load()
60 .config_dir()
61 .to_str()
62 .expect("Cannot convert config_dir path to str")
63 )
64 .as_str(),
65 );
66 } else {
67 history_file_path
68 .push(history_file.expect("Cannot get the history file"));
69 }
70
71 if !history_file_path.exists() {
72 fs::File::create(history_file_path.to_str().unwrap()).unwrap();
73 let default_content: Vec<HistoryItem> = vec![HistoryItem {
74 datetime: Some(String::from("DEFAULT")),
75 cmd: Some(String::from("DEFAULT")),
76 }];
77 fs::write(
78 &history_file_path,
79 serde_yaml::to_string(&default_content).unwrap(),
80 )
81 .unwrap();
82 }
83
84 let content_raw =
85 fs::read_to_string(&history_file_path.to_str().unwrap()).unwrap();
86
87 let content_yaml: Vec<HistoryItem> =
88 serde_yaml::from_str(content_raw.as_str()).unwrap();
89
90 let mut history_vec: Vec<HistoryItem> = Vec::new();
91
92 for item in content_yaml {
93 history_vec.push(HistoryItem {
94 datetime: item.datetime,
95 cmd: item.cmd,
96 })
97 }
98
99 history_vec.push(HistoryItem {
100 datetime: Some(self.datetime.to_string()),
101 cmd: Some(self.cmd.to_string()),
102 });
103
104 let all_history = serde_yaml::to_string(&history_vec).unwrap();
105
106 fs::write(history_file_path, all_history).unwrap();
107 }
108
109 pub fn set_datetime(&mut self, datetime: DateTime<Utc>) {
119 self.datetime = datetime;
120 }
121
122 pub fn set_cmd(&mut self, cmd: &str) {
132 self.cmd = String::from(cmd);
133 }
134
135 pub fn get_datetime(&self) -> DateTime<Utc> {
136 self.datetime.clone()
137 }
138
139 pub fn get_cmd(&self) -> String {
140 self.cmd.clone()
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use std::thread;
148 use std::time;
149
150 #[test]
151 fn test_history_new() {
152 let my_history = History::new();
153
154 assert_eq!(my_history.cmd, "");
155
156 thread::sleep(time::Duration::from_millis(5000));
157 assert_ne!(my_history.datetime, Utc::now());
158 }
159
160 #[test]
161 fn test_history_from() {
162 let my_history = History::from("ls -lsa");
163
164 assert_eq!(my_history.cmd, "ls -lsa");
165 assert_ne!(my_history.cmd, "ls -lsa ");
166
167 thread::sleep(time::Duration::from_millis(5000));
168 assert_ne!(my_history.datetime, Utc::now());
169 }
170
171 #[test]
172 fn test_set_datetime() {
173 let mut my_history = History::from("print Hello, World!");
174 let datetime = Utc::now();
175
176 my_history.set_datetime(datetime);
177
178 assert_eq!(my_history.datetime, datetime);
179 }
180
181 #[test]
182 fn test_set_cmd() {
183 let mut my_history = History::from("print Hello, World!");
184
185 my_history.set_cmd("print This is awesome");
186 assert_eq!(my_history.cmd, "print This is awesome");
187
188 my_history.set_cmd("ls -lsa \n");
189 assert_eq!(my_history.cmd, "ls -lsa \n");
190 }
191
192 #[test]
193 fn test_get_datetime() {
194 let mut my_history = History::from("ls -lsa");
195
196 let datetime = Utc::now();
197 my_history.datetime = datetime;
198
199 assert_eq!(my_history.datetime, datetime);
200
201 thread::sleep(time::Duration::from_millis(5000));
202 assert_ne!(my_history.datetime, Utc::now());
203 }
204
205 #[test]
206 fn test_get_cmd() {
207 let mut my_history = History::from("ls -lsa");
208
209 assert_eq!(my_history.cmd, "ls -lsa");
210
211 my_history.cmd = String::from("");
212
213 assert_eq!(my_history.cmd, "");
214 assert_ne!(my_history.cmd, "\n");
215 }
216}