diff options
-rw-r--r-- | config.yaml | 1 | ||||
-rwxr-xr-x | hello | bin | 20552 -> 0 bytes | |||
-rw-r--r-- | hello.c | 3 | ||||
-rw-r--r-- | src/actioner.rs | 5 | ||||
-rw-r--r-- | src/args.rs | 1 | ||||
-rw-r--r-- | src/config.rs | 6 | ||||
-rw-r--r-- | src/display.rs | 17 | ||||
-rw-r--r-- | src/event_char.rs | 2 | ||||
-rw-r--r-- | src/help.rs | 1 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/mode.rs | 3 | ||||
-rw-r--r-- | src/status.rs | 42 | ||||
-rw-r--r-- | src/visited.rs | 73 |
13 files changed, 146 insertions, 9 deletions
diff --git a/config.yaml b/config.yaml index a39d053..cf593dc 100644 --- a/config.yaml +++ b/config.yaml @@ -41,3 +41,4 @@ keybindings: sort_by: O symlink: S preview: P + history: H Binary files differdiff --git a/hello.c b/hello.c deleted file mode 100644 index 2d2f529..0000000 --- a/hello.c +++ /dev/null @@ -1,3 +0,0 @@ -#include <stdio.h> - -int main() { printf("Hello, World\n"); } diff --git a/src/actioner.rs b/src/actioner.rs index 8b1451d..ce2f107 100644 --- a/src/actioner.rs +++ b/src/actioner.rs @@ -44,6 +44,7 @@ impl Actioner { (keybindings.sort_by, EventChar::Sort), (keybindings.symlink, EventChar::Symlink), (keybindings.preview, EventChar::Preview), + (keybindings.history, EventChar::History), ]); Self { binds } } @@ -85,6 +86,7 @@ impl Actioner { match status.mode { Mode::Normal | Mode::Preview => status.event_up_one_row(), Mode::Jump => status.event_jumplist_prev(), + Mode::History => status.event_history_prev(), Mode::Goto | Mode::Exec | Mode::Search => { status.completion.prev(); } @@ -97,6 +99,7 @@ impl Actioner { match status.mode { Mode::Normal | Mode::Preview => status.event_down_one_row(), Mode::Jump => status.event_jumplist_next(), + Mode::History => status.event_history_next(), Mode::Goto | Mode::Exec | Mode::Search => { status.completion.next(); } @@ -208,6 +211,7 @@ impl Actioner { Mode::Goto => status.exec_goto(), Mode::RegexMatch => status.exec_regex(), Mode::Jump => status.exec_jump(), + Mode::History => status.exec_history(), Mode::Normal | Mode::NeedConfirmation | Mode::Help | Mode::Sort | Mode::Preview => (), } @@ -251,6 +255,7 @@ impl Actioner { }, Mode::Help | Mode::Preview => status.event_normal(), Mode::Jump => (), + Mode::History => (), Mode::NeedConfirmation => { if c == 'y' { status.exec_last_edition() diff --git a/src/args.rs b/src/args.rs index 467b958..3d9784f 100644 --- a/src/args.rs +++ b/src/args.rs @@ -42,6 +42,7 @@ use clap::Parser; /// w: REGEXMATCH{n} /// j: JUMP{n} /// O: SORT{n} +/// H: HISTORY{n} /// Enter: Execute mode then NORMAL{n} /// Esc: NORMAL{n} pub struct Args { diff --git a/src/config.rs b/src/config.rs index e0fa5bb..a21b368 100644 --- a/src/config.rs +++ b/src/config.rs @@ -203,6 +203,8 @@ pub struct Keybindings { pub symlink: char, /// Preview with bat pub preview: char, + /// Display a stack of visited directories + pub history: char, } impl Keybindings { @@ -284,6 +286,9 @@ impl Keybindings { if let Some(preview) = yaml["preview"].as_str().map(|s| s.to_string()) { self.preview = preview.chars().next().unwrap_or('P'); } + if let Some(history) = yaml["history"].as_str().map(|s| s.to_string()) { + self.history = history.chars().next().unwrap_or('H'); + } } /// Returns a new `Keybindings` instance with hardcoded values. @@ -314,6 +319,7 @@ impl Keybindings { sort_by: 'O', symlink: 'S', preview: 'P', + history: 'H', } } } diff --git a/src/display.rs b/src/display.rs index 0ced49e..31b3f69 100644 --- a/src/display.rs +++ b/src/display.rs @@ -55,6 +55,7 @@ impl Display { self.cursor(status); self.help(status); self.jump_list(status); + self.history(status); self.completion(status); self.preview(status); } @@ -167,6 +168,22 @@ impl Display { } } } + /// Display the history of visited directories. + fn history(&mut self, status: &Status) { + if let Mode::History = status.mode { + let _ = self.term.clear(); + let _ = self.term.print(0, 0, "Go to..."); + for (row, path) in status.history.visited.iter().rev().enumerate() { + let mut attr = Attr::default(); + if row == status.history.len() - status.history.index - 1 { + attr.effect |= Effect::REVERSE; + } + let _ = self + .term + .print_with_attr(row + 1, 4, path.to_str().unwrap(), attr); + } + } + } /// Display the possible completion items. The currently selected one is /// reversed. diff --git a/src/event_char.rs b/src/event_char.rs index 9b3e4fc..74ac4a7 100644 --- a/src/event_char.rs +++ b/src/event_char.rs @@ -22,6 +22,7 @@ pub enum EventChar { FlagAll, ReverseFlags, Jump, + History, NvimFilepicker, Sort, Symlink, @@ -52,6 +53,7 @@ impl EventChar { EventChar::FlagAll => status.event_flag_all(), EventChar::ReverseFlags => status.event_reverse_flags(), EventChar::Jump => status.event_jump(), + EventChar::History => status.event_history(), EventChar::NvimFilepicker => status.event_nvim_filepicker(), EventChar::Sort => status.event_sort(), EventChar::Symlink => status.event_symlink(), diff --git a/src/help.rs b/src/help.rs index 1424201..0d964d7 100644 --- a/src/help.rs +++ b/src/help.rs @@ -42,6 +42,7 @@ P: preview this file w: REGEXMATCH j: JUMP O: SORT + H: HISTORY Enter: Execute mode then NORMAL Esc: NORMAL "; @@ -12,3 +12,4 @@ pub mod last_edition; pub mod mode; pub mod preview; pub mod status; +pub mod visited; diff --git a/src/mode.rs b/src/mode.rs index be13bcf..a2384fd 100644 --- a/src/mode.rs +++ b/src/mode.rs @@ -33,6 +33,8 @@ pub enum Mode { Sort, /// Preview a content with bat Preview, + /// Display a stack of visited directories, + History, } impl fmt::Debug for Mode { @@ -49,6 +51,7 @@ impl fmt::Debug for Mode { Mode::Goto => write!(f, "Goto : "), Mode::RegexMatch => write!(f, "Regex : "), Mode::Jump => write!(f, "Jump : "), + Mode::History => write!(f, "History :"), Mode::NeedConfirmation => write!(f, "Y/N :"), Mode::Sort => write!(f, "(N)ame (D)ate (S)ize (E)xt (R)ev :"), Mode::Preview => write!(f, "Preview : "), diff --git a/src/status.rs b/src/status.rs index 19ee9b8..7eb7170 100644 --- a/src/status.rs +++ b/src/status.rs @@ -17,6 +17,7 @@ use crate::input::Input; use crate::last_edition::LastEdition; use crate::mode::Mode; use crate::preview::Preview; +use crate::visited::History; /// Holds every thing about the current status of the application. /// Is responsible to execute commands depending on received events, mutating @@ -53,6 +54,8 @@ pub struct Status { /// Lines of the previewed files. /// Empty if not in preview mode. pub preview: Preview, + /// Visited directories + pub history: History, } impl Status { @@ -62,7 +65,7 @@ impl Status { eprintln!("File does not exists {:?}", args.path); std::process::exit(2) }); - let path_content = PathContent::new(path, args.all); + let path_content = PathContent::new(path.clone(), args.all); let show_hidden = args.all; let terminal = config.terminal; let opener = config.opener; @@ -76,6 +79,8 @@ impl Status { let last_edition = LastEdition::Nothing; let must_quit = false; let preview = Preview::Empty; + let mut history = History::default(); + history.push(&path); Self { mode, line_index, @@ -92,6 +97,7 @@ impl Status { last_edition, must_quit, preview, + history, } } @@ -203,10 +209,20 @@ impl Status { } } + pub fn event_history_next(&mut self) { + self.history.next() + } + + pub fn event_history_prev(&mut self) { + self.history.prev() + } + pub fn event_move_to_parent(&mut self) { match self.path_content.path.parent() { Some(parent) => { - self.path_content = PathContent::new(path::PathBuf::from(parent), self.show_hidden); + let path = path::PathBuf::from(parent); + self.history.push(&path); + self.path_content = PathContent::new(path, self.show_hidden); self.window.reset(self.path_content.files.len()); self.line_index = 0; self.input.cursor_start() @@ -224,10 +240,9 @@ impl Status { return; } if let FileKind::Directory = self.path_content.files[self.path_content.selected].file_kind { - self.path_content = PathContent::new( - self.path_content.selected_file().unwrap().path.clone(), - self.show_hidden, - ); + let childpath = self.path_content.selected_file().unwrap().path.clone(); + self.history.push(&childpath); + self.path_content = PathContent::new(childpath, self.show_hidden); self.window.reset(self.path_content.files.len()); self.line_index = 0; self.input.cursor_start() @@ -429,6 +444,10 @@ impl Status { } } + pub fn event_history(&mut self) { + self.mode = Mode::History + } + pub fn event_right_click(&mut self, row: u16) { if self.path_content.files.is_empty() || row as usize > self.path_content.files.len() { return; @@ -623,6 +642,7 @@ impl Status { let expanded_cow_path = shellexpand::tilde(&target_string); let expanded_target: &str = expanded_cow_path.borrow(); if let Ok(path) = std::fs::canonicalize(expanded_target) { + self.history.push(&path); self.path_content = PathContent::new(path, self.show_hidden); self.window.reset(self.path_content.files.len()); } @@ -636,6 +656,7 @@ impl Status { Some(parent) => parent.to_path_buf(), None => jump_target.clone(), }; + self.history.push(&target_dir); self.path_content = PathContent::new(target_dir, self.show_hidden); self.line_index = self .path_content @@ -648,6 +669,15 @@ impl Status { self.window.scroll_to(self.line_index); } + pub fn exec_history(&mut self) { + self.input.reset(); + if let Some(path) = self.history.selected() { + self.path_content = PathContent::new(path, self.show_hidden); + } + self.history.drop_queue(); + self.event_normal(); + } + pub fn exec_regex(&mut self) { let re = Regex::new(&self.input.string).unwrap(); if !self.input.string.is_empty() { diff --git a/src/visited.rs b/src/visited.rs new file mode 100644 index 0000000..c9b27bf --- /dev/null +++ b/src/visited.rs @@ -0,0 +1,73 @@ +use std::path::PathBuf; + +#[derive(Clone, Debug)] +pub struct History { + pub visited: Vec<PathBuf>, + pub index: usize, +} + +impl Default for History { + fn default() -> Self { + Self { + visited: vec![], + index: 0, + } + } +} + +impl History { + pub fn push(&mut self, path: &PathBuf) { + if !self.visited.contains(path) { + self.visited.push(path.to_owned()); + self.index = self.len() - 1 + } + } + + pub fn pop(&mut self) -> Option<PathBuf> { + self.visited.pop() + } + + pub fn is_empty(&self) -> bool { + self.visited.is_empty() + } + + pub fn len(&self) -> usize { + self.visited.len() + } + + pub fn next(&mut self) { + if self.is_empty() { + self.index = 0 + } else if self.index > 0 { + self.index -= 1; + } else { + self.index = self.len() - 1 + } + } + + pub fn prev(&mut self) { + if self.is_empty() { + self.index = 0; + } else { + self.index = (self.index + 1) % self.len() + } + } + + pub fn selected(&self) -> Option<PathBuf> { + if self.index < self.len() { + Some(self.visited[self.index].clone()) + } else { + None + } + } + + pub fn drop_queue(&mut self) { + let final_length = self.len() - self.index; + self.visited.truncate(final_length); + if self.is_empty() { + self.index = 0 + } else { + self.index = self.len() - 1 + } + } +} |