summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoah Too <krivahtoo@gmail.com>2022-10-17 19:39:53 +0300
committerGitHub <noreply@github.com>2022-10-17 12:39:53 -0400
commitbe452d4c9abf7891111138000fe7683f169d69a5 (patch)
tree75d9967795d601f7dc7eacd5e3dede155bd36d1f
parent02c7e941566a2d828e77dd33a6dda74c8a0c42ef (diff)
add `filter` command (#205)
* add `filter` command * cargo fmt
-rw-r--r--src/commands/escape.rs9
-rw-r--r--src/commands/filter.rs16
-rw-r--r--src/commands/mod.rs1
-rw-r--r--src/commands/reload.rs6
-rw-r--r--src/config/general/display_raw.rs1
-rw-r--r--src/config/option/display_option.rs63
-rw-r--r--src/fs/dirlist.rs2
-rw-r--r--src/history.rs7
-rw-r--r--src/key_command/command.rs4
-rw-r--r--src/key_command/constants.rs1
-rw-r--r--src/key_command/impl_appcommand.rs2
-rw-r--r--src/key_command/impl_appexecute.rs2
-rw-r--r--src/key_command/impl_comment.rs2
-rw-r--r--src/key_command/impl_from_str.rs4
-rw-r--r--src/key_command/impl_interactive.rs3
15 files changed, 103 insertions, 20 deletions
diff --git a/src/commands/escape.rs b/src/commands/escape.rs
index 1a507df..26b3da4 100644
--- a/src/commands/escape.rs
+++ b/src/commands/escape.rs
@@ -1,9 +1,16 @@
use crate::context::AppContext;
use crate::error::JoshutoResult;
+use super::reload;
+
pub fn escape(context: &mut AppContext) -> JoshutoResult {
if let Some(curr_dir_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() {
- curr_dir_list.visual_mode_cancel();
+ if curr_dir_list.get_visual_mode_anchor_index().is_some() {
+ curr_dir_list.visual_mode_cancel();
+ } else {
+ // reload to clear current filter
+ reload::reload_dirlist(context)?;
+ }
};
Ok(())
}
diff --git a/src/commands/filter.rs b/src/commands/filter.rs
new file mode 100644
index 0000000..b87c901
--- /dev/null
+++ b/src/commands/filter.rs
@@ -0,0 +1,16 @@
+use crate::context::AppContext;
+use crate::error::JoshutoResult;
+
+use super::reload;
+
+pub fn filter(context: &mut AppContext, arg: &str) -> JoshutoResult {
+ let curr_tab = context.tab_context_mut().curr_tab_mut();
+ curr_tab.option_mut().set_filter_string(arg);
+
+ if let Some(list) = curr_tab.curr_list_mut() {
+ list.depreciate();
+ }
+
+ reload::soft_reload_curr_tab(context)?;
+ Ok(())
+}
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 0bf83ae..c4f7531 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -5,6 +5,7 @@ pub mod cursor_move;
pub mod delete_files;
pub mod escape;
pub mod file_ops;
+pub mod filter;
pub mod flat;
pub mod line_nums;
pub mod new_directory;
diff --git a/src/commands/reload.rs b/src/commands/reload.rs
index f7197c1..fe5b6b3 100644
--- a/src/commands/reload.rs
+++ b/src/commands/reload.rs
@@ -92,6 +92,12 @@ pub fn reload(context: &mut AppContext, id: &Uuid) -> std::io::Result<()> {
}
pub fn reload_dirlist(context: &mut AppContext) -> JoshutoResult {
+ // clear filter on reload
+ context
+ .tab_context_mut()
+ .curr_tab_mut()
+ .option_mut()
+ .set_filter_string("");
reload(context, &context.tab_context_ref().curr_tab_id())?;
Ok(())
}
diff --git a/src/config/general/display_raw.rs b/src/config/general/display_raw.rs
index dc0dc9f..c594e5c 100644
--- a/src/config/general/display_raw.rs
+++ b/src/config/general/display_raw.rs
@@ -125,6 +125,7 @@ impl From<DisplayOptionRaw> for DisplayOption {
no_preview_layout,
default_tab_display_option: TabDisplayOption {
_sort_options: raw.sort_options.into(),
+ filter_string: "".to_owned(),
},
}
}
diff --git a/src/config/option/display_option.rs b/src/config/option/display_option.rs
index 1578e06..a076db8 100644
--- a/src/config/option/display_option.rs
+++ b/src/config/option/display_option.rs
@@ -36,6 +36,7 @@ pub struct DisplayOption {
#[derive(Clone, Debug)]
pub struct TabDisplayOption {
pub _sort_options: SortOption,
+ pub filter_string: String,
}
#[derive(Clone, Copy, Debug)]
@@ -53,6 +54,14 @@ impl TabDisplayOption {
pub fn sort_options_mut(&mut self) -> &mut SortOption {
&mut self._sort_options
}
+
+ pub fn set_filter_string(&mut self, pattern: &str) {
+ self.filter_string = pattern.to_owned();
+ }
+
+ pub fn filter_string_ref(&self) -> &str {
+ &self.filter_string
+ }
}
impl DisplayOption {
@@ -100,12 +109,10 @@ impl DisplayOption {
self._line_nums = style;
}
- pub fn filter_func(&self) -> fn(&Result<fs::DirEntry, std::io::Error>) -> bool {
- if self.show_hidden() {
- no_filter
- } else {
- filter_hidden
- }
+ pub fn filter_func(
+ &self,
+ ) -> fn(&Result<fs::DirEntry, std::io::Error>, &DisplayOption, &TabDisplayOption) -> bool {
+ filter
}
}
@@ -140,22 +147,48 @@ impl std::default::Default for DisplayOption {
no_preview_layout,
default_tab_display_option: TabDisplayOption {
_sort_options: SortOption::default(),
+ filter_string: "".to_owned(),
},
}
}
}
-const fn no_filter(_: &Result<fs::DirEntry, std::io::Error>) -> bool {
- true
+fn has_str(entry: &fs::DirEntry, pat: &str) -> bool {
+ match entry.file_name().into_string().ok() {
+ Some(s) => s
+ .to_ascii_lowercase()
+ .contains(pat.to_ascii_lowercase().as_str()),
+ None => false,
+ }
}
-fn filter_hidden(result: &Result<fs::DirEntry, std::io::Error>) -> bool {
- match result {
- Err(_) => true,
- Ok(entry) => {
- let file_name = entry.file_name();
- let lossy_string = file_name.as_os_str().to_string_lossy();
- !lossy_string.starts_with('.')
+fn filter(
+ result: &Result<fs::DirEntry, std::io::Error>,
+ opt: &DisplayOption,
+ tab_opts: &TabDisplayOption,
+) -> bool {
+ if opt.show_hidden() && tab_opts.filter_string_ref().is_empty() {
+ true
+ } else {
+ match result {
+ Err(_) => true,
+ Ok(entry) => {
+ if tab_opts.filter_string_ref().is_empty() {
+ let file_name = entry.file_name();
+ let lossy_string = file_name.as_os_str().to_string_lossy();
+ !lossy_string.starts_with('.')
+ } else if opt.show_hidden() {
+ has_str(entry, tab_opts.filter_string_ref())
+ } else {
+ let file_name = entry.file_name();
+ let lossy_string = file_name.as_os_str().to_string_lossy();
+ if !lossy_string.starts_with('.') {
+ has_str(entry, tab_opts.filter_string_ref())
+ } else {
+ false
+ }
+ }
+ }
}
}
}
diff --git a/src/fs/dirlist.rs b/src/fs/dirlist.rs
index 1d035fa..dfd8831 100644
--- a/src/fs/dirlist.rs
+++ b/src/fs/dirlist.rs
@@ -46,7 +46,7 @@ impl JoshutoDirList {
tab_options: &TabDisplayOption,
) -> io::Result<Self> {
let filter_func = options.filter_func();
- let mut contents = read_directory(path.as_path(), filter_func, options)?;
+ let mut contents = read_directory(path.as_path(), filter_func, options, tab_options)?;
contents.sort_by(|f1, f2| tab_options.sort_options_ref().compare(f1, f2));
let index = if contents.is_empty() { None } else { Some(0) };
diff --git a/src/history.rs b/src/history.rs
index 162c3bd..076f59c 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -155,7 +155,7 @@ pub fn create_dirlist_with_history(
tab_options: &TabDisplayOption,
) -> io::Result<JoshutoDirList> {
let filter_func = options.filter_func();
- let mut contents = read_directory(path, filter_func, options)?;
+ let mut contents = read_directory(path, filter_func, options, tab_options)?;
// re-use directory size information on reload
for entry in contents.iter_mut() {
@@ -246,12 +246,13 @@ pub fn read_directory<F>(
path: &Path,
filter_func: F,
options: &DisplayOption,
+ tab_options: &TabDisplayOption,
) -> io::Result<Vec<JoshutoDirEntry>>
where
- F: Fn(&Result<fs::DirEntry, io::Error>) -> bool,
+ F: Fn(&Result<fs::DirEntry, io::Error>, &DisplayOption, &TabDisplayOption) -> bool,
{
let results: Vec<JoshutoDirEntry> = fs::read_dir(path)?
- .filter(filter_func)
+ .filter(|res| filter_func(res, options, tab_options))
.filter_map(|res| JoshutoDirEntry::from(&res.ok()?, options).ok())
.collect();
diff --git a/src/key_command/command.rs b/src/key_command/command.rs
index d345c48..bc8fe6d 100644
--- a/src/key_command/command.rs
+++ b/src/key_command/command.rs
@@ -124,6 +124,10 @@ pub enum Command {
Sort(SortType),
SortReverse,
+ Filter {
+ pattern: String,
+ },
+
NewTab,
CloseTab,
TabSwitch {
diff --git a/src/key_command/constants.rs b/src/key_command/constants.rs
index c7cfaaa..c3bddc9 100644
--- a/src/key_command/constants.rs
+++ b/src/key_command/constants.rs
@@ -80,6 +80,7 @@ cmd_constants![
(CMD_NUMBERED_COMMAND, "numbered_command"),
(CMD_FLAT, "flat"),
(CMD_ESCAPE, "escape"),
+ (CMD_FILTER, "filter"),
];
pub fn complete_command(partial_command: &str) -> Vec<Pair> {
diff --git a/src/key_command/impl_appcommand.rs b/src/key_command/impl_appcommand.rs
index 7156f43..bc509af 100644
--- a/src/key_command/impl_appcommand.rs
+++ b/src/key_command/impl_appcommand.rs
@@ -74,6 +74,8 @@ impl AppCommand for Command {
Self::Sort(_) => CMD_SORT,
Self::SortReverse => CMD_SORT_REVERSE,
+ Self::Filter { .. } => CMD_FILTER,
+
Self::SubProcess { spawn: false, .. } => CMD_SUBPROCESS_FOREGROUND,
Self::SubProcess { spawn: true, .. } => CMD_SUBPROCESS_BACKGROUND,
Self::SwitchLineNums(_) => CMD_SWITCH_LINE_NUMBERS,
diff --git a/src/key_command/impl_appexecute.rs b/src/key_command/impl_appexecute.rs
index 0dc9a9d..f72aca3 100644
--- a/src/key_command/impl_appexecute.rs
+++ b/src/key_command/impl_appexecute.rs
@@ -122,6 +122,8 @@ impl AppExecute for Command {
numbered_command::numbered_command(context, backend, keymap_t, *initial)
}
+ Self::Filter { pattern } => filter::filter(context, pattern.as_str()),
+
Self::ToggleHiddenFiles => show_hidden::toggle_hidden(context),
Self::TabSwitch { offset } => {
diff --git a/src/key_command/impl_comment.rs b/src/key_command/impl_comment.rs
index 616dfed..b74da7a 100644
--- a/src/key_command/impl_comment.rs
+++ b/src/key_command/impl_comment.rs
@@ -106,6 +106,8 @@ impl CommandComment for Command {
},
Self::SortReverse => "Reverse sort order",
+ Self::Filter { .. } => "Filter directory list",
+
Self::TabSwitch { .. } => "Swith to the next tab",
Self::TabSwitchIndex { .. } => "Swith to a given tab",
Self::Help => "Open this help page",
diff --git a/src/key_command/impl_from_str.rs b/src/key_command/impl_from_str.rs
index c84bc1b..5802573 100644
--- a/src/key_command/impl_from_str.rs
+++ b/src/key_command/impl_from_str.rs
@@ -378,6 +378,10 @@ impl std::str::FromStr for Command {
format!("{}: no starting character given", command),
)),
}
+ } else if command == CMD_FILTER {
+ Ok(Self::Filter {
+ pattern: arg.to_string(),
+ })
} else {
Err(JoshutoError::new(
JoshutoErrorKind::UnrecognizedCommand,
diff --git a/src/key_command/impl_interactive.rs b/src/key_command/impl_interactive.rs
index f92137d..8171ecb 100644
--- a/src/key_command/impl_interactive.rs
+++ b/src/key_command/impl_interactive.rs
@@ -10,6 +10,9 @@ impl InteractiveExecute for Command {
Self::SearchIncremental { pattern } => {
search_string::search_string(context, pattern.as_str(), true)
}
+ Self::Filter { pattern } => {
+ filter::filter(context, pattern).ok();
+ }
_ => (),
}
}