diff options
author | Noah Too <krivahtoo@gmail.com> | 2022-10-17 19:39:53 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-17 12:39:53 -0400 |
commit | be452d4c9abf7891111138000fe7683f169d69a5 (patch) | |
tree | 75d9967795d601f7dc7eacd5e3dede155bd36d1f | |
parent | 02c7e941566a2d828e77dd33a6dda74c8a0c42ef (diff) |
add `filter` command (#205)
* add `filter` command
* cargo fmt
-rw-r--r-- | src/commands/escape.rs | 9 | ||||
-rw-r--r-- | src/commands/filter.rs | 16 | ||||
-rw-r--r-- | src/commands/mod.rs | 1 | ||||
-rw-r--r-- | src/commands/reload.rs | 6 | ||||
-rw-r--r-- | src/config/general/display_raw.rs | 1 | ||||
-rw-r--r-- | src/config/option/display_option.rs | 63 | ||||
-rw-r--r-- | src/fs/dirlist.rs | 2 | ||||
-rw-r--r-- | src/history.rs | 7 | ||||
-rw-r--r-- | src/key_command/command.rs | 4 | ||||
-rw-r--r-- | src/key_command/constants.rs | 1 | ||||
-rw-r--r-- | src/key_command/impl_appcommand.rs | 2 | ||||
-rw-r--r-- | src/key_command/impl_appexecute.rs | 2 | ||||
-rw-r--r-- | src/key_command/impl_comment.rs | 2 | ||||
-rw-r--r-- | src/key_command/impl_from_str.rs | 4 | ||||
-rw-r--r-- | src/key_command/impl_interactive.rs | 3 |
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(); + } _ => (), } } |