From d3a385ea754e47ca462c84a9aef2e40306e2997c Mon Sep 17 00:00:00 2001 From: rabite Date: Mon, 11 Mar 2019 21:21:47 +0100 Subject: save minibuffer history --- src/fail.rs | 12 +++- src/file_browser.rs | 4 +- src/minibuffer.rs | 196 ++++++++++++++++++++++++++++++++++++++++------------ src/widget.rs | 8 +-- 4 files changed, 169 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/fail.rs b/src/fail.rs index 16a6028..1b1544f 100644 --- a/src/fail.rs +++ b/src/fail.rs @@ -55,7 +55,11 @@ pub enum HError { #[fail(display = "INofify failed: {}", error)] INotifyError{#[cause] error: notify::Error}, #[fail(display = "Tags not loaded yet")] - TagsNotLoadedYetError + TagsNotLoadedYetError, + #[fail(display = "Input cancelled!")] + MiniBufferCancelledInput, + #[fail(display = "Empty input!")] + MiniBufferEmptyInput } impl HError { @@ -78,6 +82,12 @@ impl HError { pub fn tags_not_loaded() -> HResult { Err(HError::TagsNotLoadedYetError) } + pub fn minibuffer_cancel() -> HResult { + Err(HError::MiniBufferCancelledInput) + } + pub fn minibuffer_empty() -> HResult { + Err(HError::MiniBufferEmptyInput) + } } pub trait ErrorLog where Self: Sized { diff --git a/src/file_browser.rs b/src/file_browser.rs index 241af1f..34ddd32 100644 --- a/src/file_browser.rs +++ b/src/file_browser.rs @@ -546,7 +546,7 @@ impl FileBrowser { } pub fn turbo_cd(&mut self) -> HResult<()> { - let dir = self.minibuffer("cd: "); + let dir = self.minibuffer("cd"); match dir { Ok(dir) => { @@ -589,7 +589,7 @@ impl FileBrowser { let file_names = selected_files.iter().map(|f| f.name.clone()).collect::>(); - let cmd = self.minibuffer("exec:")?; + let cmd = self.minibuffer("exec")?; self.show_status(&format!("Running: \"{}\"", &cmd)).log(); diff --git a/src/minibuffer.rs b/src/minibuffer.rs index 02f235e..bf915aa 100644 --- a/src/minibuffer.rs +++ b/src/minibuffer.rs @@ -1,18 +1,139 @@ use termion::event::Key; +use std::collections::HashMap; + use crate::coordinates::{Coordinates}; use crate::widget::{Widget, WidgetCore}; use crate::fail::{HResult, HError, ErrorLog}; use crate::term::ScreenExt; +type HMap = HashMap>; + +#[derive(Debug)] +struct History { + history: HMap, + position: Option, + loaded: bool +} + +impl History { + fn new() -> History { + History { + history: HashMap::new(), + position: None, + loaded: false + } + } + + fn load(&mut self) -> HResult<()> { + if self.loaded { return Ok(()) } + + let hpath = crate::paths::history_path()?; + let hf_content = std::fs::read_to_string(hpath)?; + + let history = hf_content.lines().fold(HashMap::new(), |mut hm: HMap, line| { + let parts = line.splitn(2, ":").collect::>(); + if parts.len() == 2 { + let (htype, hline) = (parts[0].to_string(), parts[1].to_string()); + + match hm.get_mut(&htype) { + Some(hvec) => hvec.push(hline), + None => { + let hvec = vec![hline]; + hm.insert(htype, hvec); + } + }; + } + hm + }); + + self.history = history; + self.loaded = true; + + Ok(()) + } + + fn save(&self) -> HResult<()> { + let hpath = crate::paths::history_path()?; + + let history = self.history.iter().map(|(htype, hlines)| { + hlines.iter().map(|hline| format!("{}: {}\n", htype, hline)) + .collect::() + }).collect::(); + + std::fs::write(hpath, history)?; + Ok(()) + } + + fn reset(&mut self) { + self.position = None; + } + + fn add(&mut self, htype: &str, input: &str) { + self.load().log(); + let history = match self.history.get_mut(htype) { + Some(history) => history, + None => { + let hvec = Vec::new(); + self.history.insert(htype.to_string(), hvec); + self.history.get_mut(htype).unwrap() + } + }; + history.push(input.to_string()); + self.save().log(); + } + + fn get_prev(&mut self, htype: &str) -> HResult { + self.load()?; + let history = self.history.get(htype)?; + let mut position = self.position; + let hist_len = history.len(); + + if position == Some(0) { position = None; } + if hist_len == 0 { return Err(HError::NoHistoryError); } + + if let Some(position) = position { + let historic = history[position - 1].clone(); + self.position = Some(position - 1); + Ok(historic) + } else { + let historic = history[hist_len - 1].clone(); + self.position = Some(hist_len - 1); + Ok(historic) + } + + } + + fn get_next(&mut self, htype: &str) -> HResult { + self.load()?; + let history = self.history.get(htype)?; + let mut position = self.position; + let hist_len = history.len(); + + if hist_len == 0 { return Err(HError::NoHistoryError); } + if position == Some(hist_len) || + position == None + { position = Some(0); } + + if let Some(position) = position { + let historic = history[position].clone(); + self.position = Some(position + 1); + Ok(historic) + } else { + let historic = history[0].clone(); + self.position = Some(1); + Ok(historic) + } + } +} + #[derive(Debug)] pub struct MiniBuffer { core: WidgetCore, query: String, input: String, position: usize, - history: Vec, - history_pos: Option, + history: History, completions: Vec, last_completion: Option } @@ -29,8 +150,7 @@ impl MiniBuffer { query: String::new(), input: String::new(), position: 0, - history: vec![], - history_pos: None, + history: History::new(), completions: vec![], last_completion: None } @@ -40,13 +160,18 @@ impl MiniBuffer { self.query = query.to_string(); self.input.clear(); self.position = 0; - self.history_pos = None; + self.history.reset(); self.completions.clear(); self.last_completion = None; self.get_core()?.screen.lock()?.cursor_hide().log(); - self.popup()?; + match self.popup() { + Err(HError::MiniBufferCancelledInput) => self.input_cancelled()?, + _ => {} + }; + + if self.input == "" { self.input_empty()?; } Ok(self.input.clone()) } @@ -112,45 +237,17 @@ impl MiniBuffer { } pub fn history_up(&mut self) -> HResult<()> { - if self.history_pos == Some(0) { self.history_pos = None; } - if self.history.len() == 0 { return Err(HError::NoHistoryError); } - - if let Some(history_pos) = self.history_pos { - let historic = self.history[history_pos - 1].clone(); - - self.input = historic; - self.position = self.input.len(); - self.history_pos = Some(history_pos - 1); - } else { - let historic = self.history[self.history.len() - 1].clone(); - + if let Ok(historic) = self.history.get_prev(&self.query) { + self.position = historic.len(); self.input = historic; - self.position = self.input.len(); - self.history_pos = Some(self.history.len() - 1); } Ok(()) } pub fn history_down(&mut self) -> HResult<()> { - let hist_len = self.history.len(); - - if hist_len == 0 { return Err(HError::NoHistoryError); } - if self.history_pos == Some(hist_len) || - self.history_pos == None - { self.history_pos = Some(0); } - - if let Some(history_pos) = self.history_pos { - let historic = self.history[history_pos].clone(); - + if let Ok(historic) = self.history.get_next(&self.query) { + self.position = historic.len(); self.input = historic; - self.position = self.input.len(); - self.history_pos = Some(history_pos + 1); - } else { - let historic = self.history[0].clone(); - - self.input = historic; - self.position = self.input.len(); - self.history_pos = Some(1); } Ok(()) } @@ -219,8 +316,18 @@ impl MiniBuffer { Ok(()) } - pub fn input_finnished(&mut self) -> HResult<()> { - return Err(HError::PopupFinnished) + pub fn input_finnished(&self) -> HResult<()> { + return HError::popup_finnished() + } + + pub fn input_cancelled(&self) -> HResult<()> { + self.show_status("Input cancelled").log(); + return HError::minibuffer_cancel() + } + + pub fn input_empty(&self) -> HResult<()> { + self.show_status("Empty!").log(); + return HError::minibuffer_empty() } } @@ -297,19 +404,22 @@ impl Widget for MiniBuffer { fn get_drawlist(&self) -> HResult { let (xpos, ypos) = self.get_coordinates()?.u16position(); - Ok(format!("{}{}{}: {}", + Ok(format!("{}{}{}{}: {}", crate::term::goto_xy(xpos, ypos), termion::clear::CurrentLine, + crate::term::header_color(), self.query, self.input)) } fn on_key(&mut self, key: Key) -> HResult<()> { match key { - Key::Esc | Key::Ctrl('c') => { self.input_finnished()?; }, + Key::Esc | Key::Ctrl('c') => { + self.input_cancelled()?; + }, Key::Char('\n') => { if self.input != "" { - self.history.push(self.input.clone()); + self.history.add(&self.query, &self.input); } self.input_finnished()?; } diff --git a/src/widget.rs b/src/widget.rs index e453679..7000cfb 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -203,10 +203,10 @@ pub trait Widget { } fn popup(&mut self) -> HResult<()> { - self.run_widget().log(); + let result = self.run_widget(); self.clear().log(); self.get_core()?.get_sender().send(Events::ExclusiveEvent(None))?; - Ok(()) + result } fn run_widget(&mut self) -> HResult<()> { @@ -220,9 +220,7 @@ pub trait Widget { for event in rx_event.iter() { match event { Events::InputEvent(input) => { - if let Err(HError::PopupFinnished) = self.on_event(input) { - return Err(HError::PopupFinnished) - } + self.on_event(input)?; } Events::WidgetReady => { self.refresh().log(); -- cgit v1.2.3