summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.yaml1
-rwxr-xr-xhellobin20552 -> 0 bytes
-rw-r--r--hello.c3
-rw-r--r--src/actioner.rs5
-rw-r--r--src/args.rs1
-rw-r--r--src/config.rs6
-rw-r--r--src/display.rs17
-rw-r--r--src/event_char.rs2
-rw-r--r--src/help.rs1
-rw-r--r--src/lib.rs1
-rw-r--r--src/mode.rs3
-rw-r--r--src/status.rs42
-rw-r--r--src/visited.rs73
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
diff --git a/hello b/hello
deleted file mode 100755
index e9a0375..0000000
--- a/hello
+++ /dev/null
Binary files differ
diff --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
";
diff --git a/src/lib.rs b/src/lib.rs
index 57f84f9..4aa3e4a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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
+ }
+ }
+}