mirror of https://github.com/bobwen-dev/hunter
save minibuffer history
This commit is contained in:
parent
9cc1ce1a44
commit
d3a385ea75
12
src/fail.rs
12
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<T>() -> HResult<T> {
|
||||
Err(HError::TagsNotLoadedYetError)
|
||||
}
|
||||
pub fn minibuffer_cancel<T>() -> HResult<T> {
|
||||
Err(HError::MiniBufferCancelledInput)
|
||||
}
|
||||
pub fn minibuffer_empty<T>() -> HResult<T> {
|
||||
Err(HError::MiniBufferEmptyInput)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ErrorLog where Self: Sized {
|
||||
|
|
|
@ -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::<Vec<String>>();
|
||||
|
||||
let cmd = self.minibuffer("exec:")?;
|
||||
let cmd = self.minibuffer("exec")?;
|
||||
|
||||
self.show_status(&format!("Running: \"{}\"", &cmd)).log();
|
||||
|
||||
|
|
|
@ -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<String, Vec<String>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct History {
|
||||
history: HMap,
|
||||
position: Option<usize>,
|
||||
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::<Vec<&str>>();
|
||||
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::<String>()
|
||||
}).collect::<String>();
|
||||
|
||||
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<String> {
|
||||
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<String> {
|
||||
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<String>,
|
||||
history_pos: Option<usize>,
|
||||
history: History,
|
||||
completions: Vec<String>,
|
||||
last_completion: Option<String>
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
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(history_pos - 1);
|
||||
} else {
|
||||
let historic = self.history[self.history.len() - 1].clone();
|
||||
|
||||
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<String> {
|
||||
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()?;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue