mirror of
https://github.com/bobwen-dev/hunter
synced 2025-04-12 00:55:41 +02:00
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)]
|
#[fail(display = "INofify failed: {}", error)]
|
||||||
INotifyError{#[cause] error: notify::Error},
|
INotifyError{#[cause] error: notify::Error},
|
||||||
#[fail(display = "Tags not loaded yet")]
|
#[fail(display = "Tags not loaded yet")]
|
||||||
TagsNotLoadedYetError
|
TagsNotLoadedYetError,
|
||||||
|
#[fail(display = "Input cancelled!")]
|
||||||
|
MiniBufferCancelledInput,
|
||||||
|
#[fail(display = "Empty input!")]
|
||||||
|
MiniBufferEmptyInput
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HError {
|
impl HError {
|
||||||
@ -78,6 +82,12 @@ impl HError {
|
|||||||
pub fn tags_not_loaded<T>() -> HResult<T> {
|
pub fn tags_not_loaded<T>() -> HResult<T> {
|
||||||
Err(HError::TagsNotLoadedYetError)
|
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 {
|
pub trait ErrorLog where Self: Sized {
|
||||||
|
@ -546,7 +546,7 @@ impl FileBrowser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn turbo_cd(&mut self) -> HResult<()> {
|
pub fn turbo_cd(&mut self) -> HResult<()> {
|
||||||
let dir = self.minibuffer("cd: ");
|
let dir = self.minibuffer("cd");
|
||||||
|
|
||||||
match dir {
|
match dir {
|
||||||
Ok(dir) => {
|
Ok(dir) => {
|
||||||
@ -589,7 +589,7 @@ impl FileBrowser {
|
|||||||
let file_names
|
let file_names
|
||||||
= selected_files.iter().map(|f| f.name.clone()).collect::<Vec<String>>();
|
= 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();
|
self.show_status(&format!("Running: \"{}\"", &cmd)).log();
|
||||||
|
|
||||||
|
@ -1,18 +1,139 @@
|
|||||||
use termion::event::Key;
|
use termion::event::Key;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::coordinates::{Coordinates};
|
use crate::coordinates::{Coordinates};
|
||||||
use crate::widget::{Widget, WidgetCore};
|
use crate::widget::{Widget, WidgetCore};
|
||||||
use crate::fail::{HResult, HError, ErrorLog};
|
use crate::fail::{HResult, HError, ErrorLog};
|
||||||
use crate::term::ScreenExt;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct MiniBuffer {
|
pub struct MiniBuffer {
|
||||||
core: WidgetCore,
|
core: WidgetCore,
|
||||||
query: String,
|
query: String,
|
||||||
input: String,
|
input: String,
|
||||||
position: usize,
|
position: usize,
|
||||||
history: Vec<String>,
|
history: History,
|
||||||
history_pos: Option<usize>,
|
|
||||||
completions: Vec<String>,
|
completions: Vec<String>,
|
||||||
last_completion: Option<String>
|
last_completion: Option<String>
|
||||||
}
|
}
|
||||||
@ -29,8 +150,7 @@ impl MiniBuffer {
|
|||||||
query: String::new(),
|
query: String::new(),
|
||||||
input: String::new(),
|
input: String::new(),
|
||||||
position: 0,
|
position: 0,
|
||||||
history: vec![],
|
history: History::new(),
|
||||||
history_pos: None,
|
|
||||||
completions: vec![],
|
completions: vec![],
|
||||||
last_completion: None
|
last_completion: None
|
||||||
}
|
}
|
||||||
@ -40,13 +160,18 @@ impl MiniBuffer {
|
|||||||
self.query = query.to_string();
|
self.query = query.to_string();
|
||||||
self.input.clear();
|
self.input.clear();
|
||||||
self.position = 0;
|
self.position = 0;
|
||||||
self.history_pos = None;
|
self.history.reset();
|
||||||
self.completions.clear();
|
self.completions.clear();
|
||||||
self.last_completion = None;
|
self.last_completion = None;
|
||||||
|
|
||||||
self.get_core()?.screen.lock()?.cursor_hide().log();
|
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())
|
Ok(self.input.clone())
|
||||||
}
|
}
|
||||||
@ -112,45 +237,17 @@ impl MiniBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn history_up(&mut self) -> HResult<()> {
|
pub fn history_up(&mut self) -> HResult<()> {
|
||||||
if self.history_pos == Some(0) { self.history_pos = None; }
|
if let Ok(historic) = self.history.get_prev(&self.query) {
|
||||||
if self.history.len() == 0 { return Err(HError::NoHistoryError); }
|
self.position = historic.len();
|
||||||
|
|
||||||
if let Some(history_pos) = self.history_pos {
|
|
||||||
let historic = self.history[history_pos - 1].clone();
|
|
||||||
|
|
||||||
self.input = historic;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn history_down(&mut self) -> HResult<()> {
|
pub fn history_down(&mut self) -> HResult<()> {
|
||||||
let hist_len = self.history.len();
|
if let Ok(historic) = self.history.get_next(&self.query) {
|
||||||
|
self.position = historic.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();
|
|
||||||
|
|
||||||
self.input = historic;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -219,8 +316,18 @@ impl MiniBuffer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input_finnished(&mut self) -> HResult<()> {
|
pub fn input_finnished(&self) -> HResult<()> {
|
||||||
return Err(HError::PopupFinnished)
|
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> {
|
fn get_drawlist(&self) -> HResult<String> {
|
||||||
let (xpos, ypos) = self.get_coordinates()?.u16position();
|
let (xpos, ypos) = self.get_coordinates()?.u16position();
|
||||||
Ok(format!("{}{}{}: {}",
|
Ok(format!("{}{}{}{}: {}",
|
||||||
crate::term::goto_xy(xpos, ypos),
|
crate::term::goto_xy(xpos, ypos),
|
||||||
termion::clear::CurrentLine,
|
termion::clear::CurrentLine,
|
||||||
|
crate::term::header_color(),
|
||||||
self.query,
|
self.query,
|
||||||
self.input))
|
self.input))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key(&mut self, key: Key) -> HResult<()> {
|
fn on_key(&mut self, key: Key) -> HResult<()> {
|
||||||
match key {
|
match key {
|
||||||
Key::Esc | Key::Ctrl('c') => { self.input_finnished()?; },
|
Key::Esc | Key::Ctrl('c') => {
|
||||||
|
self.input_cancelled()?;
|
||||||
|
},
|
||||||
Key::Char('\n') => {
|
Key::Char('\n') => {
|
||||||
if self.input != "" {
|
if self.input != "" {
|
||||||
self.history.push(self.input.clone());
|
self.history.add(&self.query, &self.input);
|
||||||
}
|
}
|
||||||
self.input_finnished()?;
|
self.input_finnished()?;
|
||||||
}
|
}
|
||||||
|
@ -203,10 +203,10 @@ pub trait Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn popup(&mut self) -> HResult<()> {
|
fn popup(&mut self) -> HResult<()> {
|
||||||
self.run_widget().log();
|
let result = self.run_widget();
|
||||||
self.clear().log();
|
self.clear().log();
|
||||||
self.get_core()?.get_sender().send(Events::ExclusiveEvent(None))?;
|
self.get_core()?.get_sender().send(Events::ExclusiveEvent(None))?;
|
||||||
Ok(())
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_widget(&mut self) -> HResult<()> {
|
fn run_widget(&mut self) -> HResult<()> {
|
||||||
@ -220,9 +220,7 @@ pub trait Widget {
|
|||||||
for event in rx_event.iter() {
|
for event in rx_event.iter() {
|
||||||
match event {
|
match event {
|
||||||
Events::InputEvent(input) => {
|
Events::InputEvent(input) => {
|
||||||
if let Err(HError::PopupFinnished) = self.on_event(input) {
|
self.on_event(input)?;
|
||||||
return Err(HError::PopupFinnished)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Events::WidgetReady => {
|
Events::WidgetReady => {
|
||||||
self.refresh().log();
|
self.refresh().log();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user