diff options
Diffstat (limited to 'src/commands')
-rw-r--r-- | src/commands/case_sensitivity.rs | 26 | ||||
-rw-r--r-- | src/commands/filter.rs | 14 | ||||
-rw-r--r-- | src/commands/mod.rs | 1 | ||||
-rw-r--r-- | src/commands/search.rs | 86 | ||||
-rw-r--r-- | src/commands/search_fzf.rs | 26 | ||||
-rw-r--r-- | src/commands/search_glob.rs | 56 | ||||
-rw-r--r-- | src/commands/search_string.rs | 70 | ||||
-rw-r--r-- | src/commands/select.rs | 13 | ||||
-rw-r--r-- | src/commands/subdir_fzf.rs | 22 |
9 files changed, 189 insertions, 125 deletions
diff --git a/src/commands/case_sensitivity.rs b/src/commands/case_sensitivity.rs new file mode 100644 index 0000000..c604b74 --- /dev/null +++ b/src/commands/case_sensitivity.rs @@ -0,0 +1,26 @@ +use crate::config::option::CaseSensitivity; +use crate::context::AppContext; +use crate::error::JoshutoResult; + +#[derive(Clone, Copy, Debug)] +pub enum SetType { + String, + Glob, + Fzf, +} + +pub fn set_case_sensitivity( + context: &mut AppContext, + case_sensitivity: CaseSensitivity, + set_type: SetType, +) -> JoshutoResult { + let options = context.config_mut().search_options_mut(); + + match set_type { + SetType::String => options.string_case_sensitivity = case_sensitivity, + SetType::Glob => options.glob_case_sensitivity = case_sensitivity, + SetType::Fzf => options.fzf_case_sensitivity = case_sensitivity, + } + + Ok(()) +} diff --git a/src/commands/filter.rs b/src/commands/filter.rs index 2ea818d..fbf1d30 100644 --- a/src/commands/filter.rs +++ b/src/commands/filter.rs @@ -1,15 +1,23 @@ -use crate::context::AppContext; +use crate::context::{AppContext, MatchContext}; use crate::error::JoshutoResult; use super::reload; -pub fn filter(context: &mut AppContext, arg: &str) -> JoshutoResult { +pub fn filter(context: &mut AppContext, pattern: &str) -> JoshutoResult { + let case_sensitivity = context + .config_ref() + .search_options_ref() + .string_case_sensitivity; + + let filter_context = MatchContext::new_string(pattern, case_sensitivity); + let curr_tab = context.tab_context_mut().curr_tab_mut(); let path = curr_tab.cwd().to_path_buf(); + curr_tab .option_mut() .dirlist_options_mut(&path) - .set_filter_string(arg); + .set_filter_context(filter_context); if let Some(list) = curr_tab.curr_list_mut() { list.depreciate(); diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 0f821bd..4753380 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,5 +1,6 @@ pub mod bookmark; pub mod bulk_rename; +pub mod case_sensitivity; pub mod change_directory; pub mod command_line; pub mod cursor_move; diff --git a/src/commands/search.rs b/src/commands/search.rs index 71beae1..41c2a8d 100644 --- a/src/commands/search.rs +++ b/src/commands/search.rs @@ -1,41 +1,87 @@ -use crate::context::AppContext; +use crate::context::{AppContext, MatchContext}; use crate::error::JoshutoResult; -use crate::util::search::SearchPattern; +use crate::tab::JoshutoTab; use super::cursor_move; -use super::search_glob; -use super::search_string; pub fn search_next(context: &mut AppContext) -> JoshutoResult { if let Some(search_context) = context.get_search_context() { - let index = match search_context { - SearchPattern::Glob(s) => { - search_glob::search_glob_fwd(context.tab_context_ref().curr_tab_ref(), s) - } - SearchPattern::String(s) => { - search_string::search_string_fwd(context.tab_context_ref().curr_tab_ref(), s) - } + if search_context.is_none() { + return Ok(()); + } + + let curr_tab = &context.tab_context_ref().curr_tab_ref(); + let index = curr_tab.curr_list_ref().and_then(|c| c.get_index()); + + let offset = match index { + Some(index) => index + 1, + None => return Ok(()), }; - if let Some(index) = index { + + if let Some(index) = search_next_impl(curr_tab, search_context, offset) { cursor_move::cursor_move(context, index); } } + Ok(()) } +pub(super) fn search_next_impl( + curr_tab: &JoshutoTab, + match_context: &MatchContext, + offset: usize, +) -> Option<usize> { + let curr_list = curr_tab.curr_list_ref()?; + let contents_len = curr_list.contents.len(); + + for i in 0..contents_len { + let file_name = curr_list.contents[(offset + i) % contents_len].file_name(); + + if match_context.is_match(file_name) { + return Some((offset + i) % contents_len); + } + } + + None +} + pub fn search_prev(context: &mut AppContext) -> JoshutoResult { if let Some(search_context) = context.get_search_context() { - let index = match search_context { - SearchPattern::Glob(s) => { - search_glob::search_glob_rev(context.tab_context_ref().curr_tab_ref(), s) - } - SearchPattern::String(s) => { - search_string::search_string_rev(context.tab_context_ref().curr_tab_ref(), s) - } + if search_context.is_none() { + return Ok(()); + } + + let curr_tab = &context.tab_context_ref().curr_tab_ref(); + let index = curr_tab.curr_list_ref().and_then(|c| c.get_index()); + + let offset = match index { + Some(index) => index, + None => return Ok(()), }; - if let Some(index) = index { + + if let Some(index) = search_prev_impl(curr_tab, search_context, offset) { cursor_move::cursor_move(context, index); } } + Ok(()) } + +fn search_prev_impl( + curr_tab: &JoshutoTab, + match_context: &MatchContext, + offset: usize, +) -> Option<usize> { + let curr_list = curr_tab.curr_list_ref()?; + let contents_len = curr_list.contents.len(); + + for i in (0..contents_len).rev() { + let file_name = curr_list.contents[(offset + i) % contents_len].file_name(); + + if match_context.is_match(file_name) { + return Some((offset + i) % contents_len); + } + } + + None +} diff --git a/src/commands/search_fzf.rs b/src/commands/search_fzf.rs index f845c60..9d86b7b 100644 --- a/src/commands/search_fzf.rs +++ b/src/commands/search_fzf.rs @@ -3,6 +3,7 @@ use std::io::Write; use std::process::{Command, Stdio}; use crate::commands::cursor_move; +use crate::config::option::CaseSensitivity; use crate::context::AppContext; use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult}; use crate::ui::AppBackend; @@ -31,11 +32,26 @@ pub fn search_fzf(context: &mut AppContext, backend: &mut AppBackend) -> Joshuto backend.terminal_drop(); - let mut fzf = match Command::new("fzf") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - { + let mut cmd = Command::new("fzf"); + cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); + + let case_sensitivity = context + .config_ref() + .search_options_ref() + .fzf_case_sensitivity; + + match case_sensitivity { + CaseSensitivity::Insensitive => { + cmd.arg("-i"); + } + CaseSensitivity::Sensitive => { + cmd.arg("+i"); + } + // fzf uses smart-case match by default + CaseSensitivity::Smart => {} + } + + let mut fzf = match cmd.spawn() { Ok(child) => child, Err(e) => { backend.terminal_restore()?; diff --git a/src/commands/search_glob.rs b/src/commands/search_glob.rs index 30962c1..c833b8e 100644 --- a/src/commands/search_glob.rs +++ b/src/commands/search_glob.rs @@ -1,49 +1,29 @@ -use globset::{GlobBuilder, GlobMatcher}; - -use crate::context::AppContext; +use crate::context::{AppContext, MatchContext}; use crate::error::JoshutoResult; -use crate::tab::JoshutoTab; -use crate::util::search::SearchPattern; use super::cursor_move; +use super::search; -pub fn search_glob_fwd(curr_tab: &JoshutoTab, glob: &GlobMatcher) -> Option<usize> { - let curr_list = curr_tab.curr_list_ref()?; +pub fn search_glob(context: &mut AppContext, pattern: &str) -> JoshutoResult { + let case_sensitivity = context + .config_ref() + .search_options_ref() + .glob_case_sensitivity; - let offset = curr_list.get_index()? + 1; - let contents_len = curr_list.len(); - for i in 0..contents_len { - let file_name = curr_list.contents[(offset + i) % contents_len].file_name(); - if glob.is_match(file_name) { - return Some((offset + i) % contents_len); - } - } - None -} -pub fn search_glob_rev(curr_tab: &JoshutoTab, glob: &GlobMatcher) -> Option<usize> { - let curr_list = curr_tab.curr_list_ref()?; + let search_context = MatchContext::new_glob(pattern, case_sensitivity)?; - let offset = curr_list.get_index()?; - let contents_len = curr_list.len(); - for i in (0..contents_len).rev() { - let file_name = curr_list.contents[(offset + i) % contents_len].file_name(); - if glob.is_match(file_name) { - return Some((offset + i) % contents_len); - } - } - None -} + let curr_tab = &context.tab_context_ref().curr_tab_ref(); + let index = curr_tab.curr_list_ref().and_then(|c| c.get_index()); -pub fn search_glob(context: &mut AppContext, pattern: &str) -> JoshutoResult { - let glob = GlobBuilder::new(pattern) - .case_insensitive(true) - .build()? - .compile_matcher(); + let offset = match index { + Some(index) => index + 1, + None => return Ok(()), + }; - let index = search_glob_fwd(context.tab_context_ref().curr_tab_ref(), &glob); - if let Some(index) = index { - cursor_move::cursor_move(context, index); + if let Some(new_index) = search::search_next_impl(curr_tab, &search_context, offset) { + cursor_move::cursor_move(context, new_index); } - context.set_search_context(SearchPattern::Glob(glob)); + + context.set_search_context(search_context); Ok(()) } diff --git a/src/commands/search_string.rs b/src/commands/search_string.rs index 53d54ea..084fc89 100644 --- a/src/commands/search_string.rs +++ b/src/commands/search_string.rs @@ -1,65 +1,29 @@ -use crate::context::AppContext; -use crate::tab::JoshutoTab; -use crate::util::search::SearchPattern; +use crate::context::{AppContext, MatchContext}; use super::cursor_move; +use super::search; -pub fn search_string_fwd(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize> { - let curr_list = curr_tab.curr_list_ref()?; +pub fn search_string(context: &mut AppContext, pattern: &str, incremental: bool) { + let case_sensitivity = context + .config_ref() + .search_options_ref() + .string_case_sensitivity; - let offset = curr_list.get_index()? + 1; - let contents_len = curr_list.contents.len(); - for i in 0..contents_len { - let file_name_lower = curr_list.contents[(offset + i) % contents_len] - .file_name() - .to_lowercase(); - if file_name_lower.contains(pattern) { - return Some((offset + i) % contents_len); - } - } - None -} + let search_context = MatchContext::new_string(pattern, case_sensitivity); -pub fn search_string_start(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize> { - let curr_list = curr_tab.curr_list_ref()?; + let curr_tab = context.tab_context_ref().curr_tab_ref(); - let contents_len = curr_list.contents.len(); - for i in 0..contents_len { - let file_name_lower = curr_list.contents[i].file_name().to_lowercase(); - if file_name_lower.contains(pattern) { - return Some(i); + if incremental { + if let Some(new_index) = search::search_next_impl(curr_tab, &search_context, 0) { + cursor_move::cursor_move(context, new_index); } - } - None -} + } else if let Some(index) = curr_tab.curr_list_ref().and_then(|c| c.get_index()) { + let offset = index + 1; -pub fn search_string_rev(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize> { - let curr_list = curr_tab.curr_list_ref()?; - - let offset = curr_list.get_index()?; - let contents_len = curr_list.contents.len(); - for i in (0..contents_len).rev() { - let file_name_lower = curr_list.contents[(offset + i) % contents_len] - .file_name() - .to_lowercase(); - if file_name_lower.contains(pattern) { - return Some((offset + i) % contents_len); + if let Some(new_index) = search::search_next_impl(curr_tab, &search_context, offset) { + cursor_move::cursor_move(context, new_index); } } - None -} - -pub fn search_string(context: &mut AppContext, pattern: &str, incremental: bool) { - let pattern = pattern.to_lowercase(); - let curr_tab = context.tab_context_ref().curr_tab_ref(); - let index = if incremental { - search_string_start(curr_tab, pattern.as_str()) - } else { - search_string_fwd(curr_tab, pattern.as_str()) - }; - if let Some(index) = index { - cursor_move::cursor_move(context, index); - } - context.set_search_context(SearchPattern::String(pattern)); + context.set_search_context(search_context); } diff --git a/src/commands/select.rs b/src/commands/select.rs index 3bfa227..0ab3023 100644 --- a/src/commands/select.rs +++ b/src/commands/select.rs @@ -1,7 +1,5 @@ -use globset::Glob; - use crate::config::option::SelectOption; -use crate::context::AppContext; +use crate::context::{AppContext, MatchContext}; use crate::error::JoshutoResult; use super::cursor_move; @@ -54,13 +52,18 @@ fn select_with_pattern( pattern: &str, options: &SelectOption, ) -> JoshutoResult { - let glob = Glob::new(pattern)?.compile_matcher(); + let case_sensitivity = context + .config_ref() + .search_options_ref() + .glob_case_sensitivity; + + let select_context = MatchContext::new_glob(pattern, case_sensitivity)?; if let Some(curr_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() { let mut found = 0; curr_list .iter_mut() - .filter(|e| glob.is_match(e.file_name())) + .filter(|e| select_context.is_match(e.file_name())) .for_each(|e| { found += 1; if options.reverse { diff --git a/src/commands/subdir_fzf.rs b/src/commands/subdir_fzf.rs index fee12e9..6bae11a 100644 --- a/src/commands/subdir_fzf.rs +++ b/src/commands/subdir_fzf.rs @@ -1,6 +1,7 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use crate::config::option::CaseSensitivity; use crate::context::AppContext; use crate::error::JoshutoResult; use crate::ui::AppBackend; @@ -10,7 +11,26 @@ use super::change_directory::change_directory; pub fn subdir_fzf(context: &mut AppContext, backend: &mut AppBackend) -> JoshutoResult { backend.terminal_drop(); - let fzf = Command::new("fzf").stdout(Stdio::piped()).spawn()?; + let mut cmd = Command::new("fzf"); + cmd.stdout(Stdio::piped()); + + let case_sensitivity = context + .config_ref() + .search_options_ref() + .fzf_case_sensitivity; + + match case_sensitivity { + CaseSensitivity::Insensitive => { + cmd.arg("-i"); + } + CaseSensitivity::Sensitive => { + cmd.arg("+i"); + } + // fzf uses smart-case match by default + CaseSensitivity::Smart => {} + } + + let fzf = cmd.spawn()?; let fzf_output = fzf.wait_with_output(); |