1use super::main::{Zle, ZleString};
15
16#[derive(Debug, Clone)]
18pub struct HistEntry {
19 pub line: String,
21 pub num: i64,
23 pub time: Option<i64>,
25}
26
27#[derive(Debug, Default)]
29pub struct History {
30 pub entries: Vec<HistEntry>,
32 pub cursor: usize,
34 pub max_size: usize,
36 pub saved_line: Option<ZleString>,
38 pub saved_cs: usize,
40 pub search_pattern: String,
42 pub search_backward: bool,
44}
45
46impl History {
47 pub fn new(max_size: usize) -> Self {
48 History {
49 entries: Vec::new(),
50 cursor: 0,
51 max_size,
52 saved_line: None,
53 saved_cs: 0,
54 search_pattern: String::new(),
55 search_backward: true,
56 }
57 }
58
59 pub fn add(&mut self, line: String) {
61 if line.is_empty() {
63 return;
64 }
65 if let Some(last) = self.entries.last() {
66 if last.line == line {
67 return;
68 }
69 }
70
71 self.entries.push(HistEntry {
72 line,
73 num: self.entries.len() as i64 + 1,
74 time: Some(
75 std::time::SystemTime::now()
76 .duration_since(std::time::UNIX_EPOCH)
77 .map(|d| d.as_secs() as i64)
78 .unwrap_or(0),
79 ),
80 });
81
82 while self.entries.len() > self.max_size {
84 self.entries.remove(0);
85 }
86
87 self.cursor = self.entries.len();
89 }
90
91 pub fn get(&self, index: usize) -> Option<&HistEntry> {
93 self.entries.get(index)
94 }
95
96 pub fn up(&mut self) -> Option<&HistEntry> {
98 if self.cursor > 0 {
99 self.cursor -= 1;
100 self.entries.get(self.cursor)
101 } else {
102 None
103 }
104 }
105
106 pub fn down(&mut self) -> Option<&HistEntry> {
108 if self.cursor < self.entries.len() {
109 self.cursor += 1;
110 self.entries.get(self.cursor)
111 } else {
112 None
113 }
114 }
115
116 pub fn search_backward(&mut self, pattern: &str) -> Option<&HistEntry> {
118 let start = if self.cursor > 0 {
119 self.cursor - 1
120 } else {
121 return None;
122 };
123
124 for i in (0..=start).rev() {
125 if self.entries[i].line.contains(pattern) {
126 self.cursor = i;
127 return self.entries.get(i);
128 }
129 }
130
131 None
132 }
133
134 pub fn search_forward(&mut self, pattern: &str) -> Option<&HistEntry> {
136 for i in (self.cursor + 1)..self.entries.len() {
137 if self.entries[i].line.contains(pattern) {
138 self.cursor = i;
139 return self.entries.get(i);
140 }
141 }
142
143 None
144 }
145
146 pub fn reset(&mut self) {
148 self.cursor = self.entries.len();
149 self.saved_line = None;
150 }
151}
152
153impl Zle {
154 pub fn init_history(&mut self, max_size: usize) {
156 let _ = max_size;
159 }
160
161 pub fn history_up(&mut self, hist: &mut History) {
163 if hist.saved_line.is_none() {
164 hist.saved_line = Some(self.zleline.clone());
166 hist.saved_cs = self.zlecs;
167 }
168
169 if let Some(entry) = hist.up() {
170 self.zleline = entry.line.chars().collect();
171 self.zlell = self.zleline.len();
172 self.zlecs = self.zlell;
173 self.resetneeded = true;
174 }
175 }
176
177 pub fn history_down(&mut self, hist: &mut History) {
179 if let Some(entry) = hist.down() {
180 self.zleline = entry.line.chars().collect();
181 self.zlell = self.zleline.len();
182 self.zlecs = self.zlell;
183 self.resetneeded = true;
184 } else if let Some(saved) = hist.saved_line.take() {
185 self.zleline = saved;
187 self.zlell = self.zleline.len();
188 self.zlecs = hist.saved_cs;
189 self.resetneeded = true;
190 }
191 }
192
193 pub fn history_isearch_backward(&mut self, hist: &mut History) {
195 hist.search_backward = true;
196 }
198
199 pub fn history_isearch_forward(&mut self, hist: &mut History) {
201 hist.search_backward = false;
202 }
204
205 pub fn history_search_prefix(&mut self, hist: &mut History) {
207 let prefix: String = self.zleline[..self.zlecs].iter().collect();
208
209 if let Some(entry) = hist.search_backward(&prefix) {
210 self.zleline = entry.line.chars().collect();
211 self.zlell = self.zleline.len();
212 self.resetneeded = true;
213 }
214 }
215
216 pub fn beginning_of_history(&mut self, hist: &mut History) {
219 if hist.saved_line.is_none() {
220 hist.saved_line = Some(self.zleline.clone());
221 hist.saved_cs = self.zlecs;
222 }
223
224 if !hist.entries.is_empty() {
225 hist.cursor = 0;
226 if let Some(entry) = hist.entries.first() {
227 self.zleline = entry.line.chars().collect();
228 self.zlell = self.zleline.len();
229 self.zlecs = 0;
230 self.resetneeded = true;
231 }
232 }
233 }
234
235 pub fn end_of_history(&mut self, hist: &mut History) {
238 hist.cursor = hist.entries.len();
239
240 if let Some(saved) = hist.saved_line.take() {
241 self.zleline = saved;
242 self.zlell = self.zleline.len();
243 self.zlecs = hist.saved_cs;
244 self.resetneeded = true;
245 }
246 }
247
248 pub fn up_line_or_history(&mut self, hist: &mut History) {
251 self.history_up(hist);
253 }
254
255 pub fn down_line_or_history(&mut self, hist: &mut History) {
258 self.history_down(hist);
259 }
260
261 pub fn history_search_backward(&mut self, hist: &mut History) {
264 let prefix: String = self.zleline[..self.zlecs.min(self.zleline.len())]
265 .iter()
266 .collect();
267
268 if hist.saved_line.is_none() {
269 hist.saved_line = Some(self.zleline.clone());
270 hist.saved_cs = self.zlecs;
271 }
272
273 hist.search_pattern = prefix.clone();
274 hist.search_backward = true;
275
276 let start = hist.cursor.saturating_sub(1);
277 for i in (0..=start).rev() {
278 if hist.entries[i].line.starts_with(&prefix) {
279 hist.cursor = i;
280 self.zleline = hist.entries[i].line.chars().collect();
281 self.zlell = self.zleline.len();
282 self.zlecs = prefix.len();
283 self.resetneeded = true;
284 return;
285 }
286 }
287 }
288
289 pub fn history_search_forward(&mut self, hist: &mut History) {
292 let prefix = &hist.search_pattern;
293 hist.search_backward = false;
294
295 for i in (hist.cursor + 1)..hist.entries.len() {
296 if hist.entries[i].line.starts_with(prefix) {
297 hist.cursor = i;
298 self.zleline = hist.entries[i].line.chars().collect();
299 self.zlell = self.zleline.len();
300 self.zlecs = prefix.len();
301 self.resetneeded = true;
302 return;
303 }
304 }
305
306 if let Some(ref saved) = hist.saved_line {
308 let saved_str: String = saved.iter().collect();
309 if saved_str.starts_with(prefix) {
310 hist.cursor = hist.entries.len();
311 self.zleline = saved.clone();
312 self.zlell = self.zleline.len();
313 self.zlecs = hist.saved_cs;
314 self.resetneeded = true;
315 }
316 }
317 }
318
319 pub fn insert_last_word(&mut self, hist: &History) {
322 if let Some(entry) = hist.entries.last() {
323 if let Some(last_word) = entry.line.split_whitespace().last() {
325 for c in last_word.chars() {
327 self.zleline.insert(self.zlecs, c);
328 self.zlecs += 1;
329 }
330 self.zlell = self.zleline.len();
331 self.resetneeded = true;
332 }
333 }
334 }
335
336 pub fn push_line(&mut self) {
339 let line: String = self.zleline.iter().collect();
341 if !line.is_empty() {
342 self.zleline.clear();
345 self.zlell = 0;
346 self.zlecs = 0;
347 self.resetneeded = true;
348 }
349 }
350
351 pub fn accept_line_and_down_history(&mut self, hist: &mut History) -> Option<String> {
354 let line: String = self.zleline.iter().collect();
355
356 if hist.cursor < hist.entries.len() {
358 hist.cursor += 1;
359 if let Some(entry) = hist.entries.get(hist.cursor) {
360 self.zleline = entry.line.chars().collect();
361 self.zlell = self.zleline.len();
362 self.zlecs = self.zlell;
363 }
364 }
365
366 Some(line)
367 }
368
369 pub fn vi_fetch_history(&mut self, hist: &mut History, num: usize) {
372 if num > 0 && num <= hist.entries.len() {
373 if hist.saved_line.is_none() {
374 hist.saved_line = Some(self.zleline.clone());
375 hist.saved_cs = self.zlecs;
376 }
377
378 hist.cursor = num - 1;
379 if let Some(entry) = hist.entries.get(hist.cursor) {
380 self.zleline = entry.line.chars().collect();
381 self.zlell = self.zleline.len();
382 self.zlecs = 0;
383 self.resetneeded = true;
384 }
385 }
386 }
387
388 pub fn vi_history_search_backward(&mut self, hist: &mut History, pattern: &str) {
391 hist.search_pattern = pattern.to_string();
392 hist.search_backward = true;
393
394 if let Some(entry) = hist.search_backward(pattern) {
395 self.zleline = entry.line.chars().collect();
396 self.zlell = self.zleline.len();
397 self.zlecs = 0;
398 self.resetneeded = true;
399 }
400 }
401
402 pub fn vi_history_search_forward(&mut self, hist: &mut History, pattern: &str) {
405 hist.search_pattern = pattern.to_string();
406 hist.search_backward = false;
407
408 if let Some(entry) = hist.search_forward(pattern) {
409 self.zleline = entry.line.chars().collect();
410 self.zlell = self.zleline.len();
411 self.zlecs = 0;
412 self.resetneeded = true;
413 }
414 }
415
416 pub fn vi_repeat_search(&mut self, hist: &mut History) {
419 let pattern = hist.search_pattern.clone();
420 if hist.search_backward {
421 self.vi_history_search_backward(hist, &pattern);
422 } else {
423 self.vi_history_search_forward(hist, &pattern);
424 }
425 }
426
427 pub fn vi_rev_repeat_search(&mut self, hist: &mut History) {
430 let pattern = hist.search_pattern.clone();
431 if hist.search_backward {
432 self.vi_history_search_forward(hist, &pattern);
433 } else {
434 self.vi_history_search_backward(hist, &pattern);
435 }
436 }
437
438 pub fn set_local_history(&mut self, _local: bool) {
441 }
444
445 pub fn remember_edits(&mut self, hist: &mut History) {
448 if hist.cursor < hist.entries.len() {
449 let line: String = self.zleline.iter().collect();
451 hist.entries[hist.cursor].line = line;
452 }
453 }
454
455 pub fn forget_edits(&mut self, _hist: &mut History) {
458 }
461}