summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsushi-shi <47691267+sushi-shi@users.noreply.github.com>2022-02-23 20:39:46 +0300
committerGitHub <noreply@github.com>2022-02-23 12:39:46 -0500
commitfe3308c75da696b37c970c12ef9cefe942fa8377 (patch)
treeb4baefda219918cd9603b7dc3e1d2ab222eb28c1 /src
parent1a78bb897a191ce5e816bf690be52ec03222369f (diff)
Add incremental search (#140)
Diffstat (limited to 'src')
-rw-r--r--src/commands/search_string.rs26
-rw-r--r--src/error/mod.rs2
-rw-r--r--src/key_command/command.rs1
-rw-r--r--src/key_command/constants.rs1
-rw-r--r--src/key_command/impl_appcommand.rs1
-rw-r--r--src/key_command/impl_appexecute.rs12
-rw-r--r--src/key_command/impl_comment.rs1
-rw-r--r--src/key_command/impl_from_str.rs2
-rw-r--r--src/key_command/impl_interactive.rs15
-rw-r--r--src/key_command/mod.rs1
-rw-r--r--src/key_command/traits.rs8
-rw-r--r--src/ui/views/tui_textfield.rs8
12 files changed, 68 insertions, 10 deletions
diff --git a/src/commands/search_string.rs b/src/commands/search_string.rs
index 62d9a7f..70b0795 100644
--- a/src/commands/search_string.rs
+++ b/src/commands/search_string.rs
@@ -1,5 +1,4 @@
use crate::context::AppContext;
-use crate::error::JoshutoResult;
use crate::tab::JoshutoTab;
use crate::util::search::SearchPattern;
@@ -20,6 +19,20 @@ pub fn search_string_fwd(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize>
}
None
}
+
+pub fn search_string_start(curr_tab: &JoshutoTab, pattern: &str) -> 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_lower = curr_list.contents[i].file_name().to_lowercase();
+ if file_name_lower.contains(pattern) {
+ return Some(i);
+ }
+ }
+ None
+}
+
pub fn search_string_rev(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize> {
let curr_list = curr_tab.curr_list_ref()?;
@@ -36,12 +49,17 @@ pub fn search_string_rev(curr_tab: &JoshutoTab, pattern: &str) -> Option<usize>
None
}
-pub fn search_string(context: &mut AppContext, pattern: &str) -> JoshutoResult<()> {
+pub fn search_string(context: &mut AppContext, pattern: &str, incremental: bool) {
let pattern = pattern.to_lowercase();
- let index = search_string_fwd(context.tab_context_ref().curr_tab_ref(), pattern.as_str());
+ 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 {
let _ = cursor_move::cursor_move(context, index);
}
context.set_search_context(SearchPattern::String(pattern));
- Ok(())
}
diff --git a/src/error/mod.rs b/src/error/mod.rs
index f305df3..8c4ca24 100644
--- a/src/error/mod.rs
+++ b/src/error/mod.rs
@@ -4,4 +4,4 @@ mod error_type;
pub use self::error_kind::JoshutoErrorKind;
pub use self::error_type::JoshutoError;
-pub type JoshutoResult<T> = Result<T, JoshutoError>;
+pub type JoshutoResult<T = ()> = Result<T, JoshutoError>;
diff --git a/src/key_command/command.rs b/src/key_command/command.rs
index e20a642..6560ed1 100644
--- a/src/key_command/command.rs
+++ b/src/key_command/command.rs
@@ -52,6 +52,7 @@ pub enum Command {
SearchGlob(String),
SearchString(String),
+ SearchIncremental(String),
SearchFzf,
SearchNext,
SearchPrev,
diff --git a/src/key_command/constants.rs b/src/key_command/constants.rs
index 101bf15..29d1591 100644
--- a/src/key_command/constants.rs
+++ b/src/key_command/constants.rs
@@ -53,6 +53,7 @@ cmd_constants![
(CMD_RENAME_FILE_APPEND, "rename_append"),
(CMD_RENAME_FILE_PREPEND, "rename_prepend"),
(CMD_SEARCH_STRING, "search"),
+ (CMD_SEARCH_INCREMENTAL, "search_inc"),
(CMD_SEARCH_GLOB, "search_glob"),
(CMD_SEARCH_FZF, "search_fzf"),
(CMD_SEARCH_NEXT, "search_next"),
diff --git a/src/key_command/impl_appcommand.rs b/src/key_command/impl_appcommand.rs
index c1bc0df..aa15c51 100644
--- a/src/key_command/impl_appcommand.rs
+++ b/src/key_command/impl_appcommand.rs
@@ -52,6 +52,7 @@ impl AppCommand for Command {
Self::RenameFilePrepend => CMD_RENAME_FILE_PREPEND,
Self::SearchString(_) => CMD_SEARCH_STRING,
+ Self::SearchIncremental(_) => CMD_SEARCH_INCREMENTAL,
Self::SearchGlob(_) => CMD_SEARCH_GLOB,
Self::SearchFzf => CMD_SEARCH_FZF,
Self::SearchNext => CMD_SEARCH_NEXT,
diff --git a/src/key_command/impl_appexecute.rs b/src/key_command/impl_appexecute.rs
index 540d20e..0e6b075 100644
--- a/src/key_command/impl_appexecute.rs
+++ b/src/key_command/impl_appexecute.rs
@@ -12,7 +12,7 @@ impl AppExecute for Command {
context: &mut AppContext,
backend: &mut TuiBackend,
keymap_t: &AppKeyMapping,
- ) -> JoshutoResult<()> {
+ ) -> JoshutoResult {
match &*self {
Self::BulkRename => bulk_rename::bulk_rename(context, backend),
@@ -70,7 +70,15 @@ impl AppExecute for Command {
Self::RenameFilePrepend => rename_file::rename_file_prepend(context, backend, keymap_t),
Self::TouchFile(arg) => touch_file::touch_file(context, arg.as_str()),
Self::SearchGlob(pattern) => search_glob::search_glob(context, pattern.as_str()),
- Self::SearchString(pattern) => search_string::search_string(context, pattern.as_str()),
+ Self::SearchString(pattern) => Ok(search_string::search_string(
+ context,
+ pattern.as_str(),
+ false,
+ )),
+ // We call `interactive_execute` on each key press, so even before Enter is pressed the
+ // cursor will be one the selected word. And as `interactive_execute` for
+ // `SearchIncremental` always starts from index 0, this operation will be a no-op
+ Self::SearchIncremental(_) => Ok(()),
Self::SearchFzf => search_fzf::search_fzf(context, backend),
Self::SearchNext => search::search_next(context),
Self::SearchPrev => search::search_prev(context),
diff --git a/src/key_command/impl_comment.rs b/src/key_command/impl_comment.rs
index 11265d9..9db7cec 100644
--- a/src/key_command/impl_comment.rs
+++ b/src/key_command/impl_comment.rs
@@ -68,6 +68,7 @@ impl CommandComment for Command {
Self::RenameFilePrepend => "Rename a file",
Self::SearchString(_) => "Search",
+ Self::SearchIncremental(_) => "Search as you type",
Self::SearchGlob(_) => "Search with globbing",
Self::SearchFzf => "Search via fzf",
Self::SearchNext => "Next search entry",
diff --git a/src/key_command/impl_from_str.rs b/src/key_command/impl_from_str.rs
index aff7996..589e420 100644
--- a/src/key_command/impl_from_str.rs
+++ b/src/key_command/impl_from_str.rs
@@ -220,6 +220,8 @@ impl std::str::FromStr for Command {
)),
arg => Ok(Self::SearchString(arg.to_string())),
}
+ } else if command == CMD_SEARCH_INCREMENTAL {
+ Ok(Self::SearchIncremental(arg.to_string()))
} else if command == CMD_SEARCH_GLOB {
match arg {
"" => Err(JoshutoError::new(
diff --git a/src/key_command/impl_interactive.rs b/src/key_command/impl_interactive.rs
new file mode 100644
index 0000000..98ad337
--- /dev/null
+++ b/src/key_command/impl_interactive.rs
@@ -0,0 +1,15 @@
+use crate::commands::*;
+use crate::context::AppContext;
+
+use super::{Command, InteractiveExecute};
+
+impl InteractiveExecute for Command {
+ fn interactive_execute(&self, context: &mut AppContext) {
+ match self {
+ Self::SearchIncremental(pattern) => {
+ search_string::search_string(context, pattern.as_str(), true)
+ }
+ _ => (),
+ }
+ }
+}
diff --git a/src/key_command/mod.rs b/src/key_command/mod.rs
index 6d7bcfe..f337c0d 100644
--- a/src/key_command/mod.rs
+++ b/src/key_command/mod.rs
@@ -8,6 +8,7 @@ mod impl_appexecute;
mod impl_comment;
mod impl_display;
mod impl_from_str;
+mod impl_interactive;
mod impl_numbered;
pub use self::command::*;
diff --git a/src/key_command/traits.rs b/src/key_command/traits.rs
index f988d73..08f6c0d 100644
--- a/src/key_command/traits.rs
+++ b/src/key_command/traits.rs
@@ -9,7 +9,7 @@ pub trait AppExecute {
context: &mut AppContext,
backend: &mut TuiBackend,
keymap_t: &AppKeyMapping,
- ) -> JoshutoResult<()>;
+ ) -> JoshutoResult;
}
pub trait NumberedExecute {
@@ -19,7 +19,11 @@ pub trait NumberedExecute {
context: &mut AppContext,
backend: &mut TuiBackend,
keymap_t: &AppKeyMapping,
- ) -> JoshutoResult<()>;
+ ) -> JoshutoResult;
+}
+
+pub trait InteractiveExecute {
+ fn interactive_execute(&self, context: &mut AppContext);
}
pub trait AppCommand: AppExecute + std::fmt::Display + std::fmt::Debug {
diff --git a/src/ui/views/tui_textfield.rs b/src/ui/views/tui_textfield.rs
index 153a903..7c481e7 100644
--- a/src/ui/views/tui_textfield.rs
+++ b/src/ui/views/tui_textfield.rs
@@ -1,3 +1,5 @@
+use std::str::FromStr;
+
use rustyline::completion::{Candidate, Completer, FilenameCompleter, Pair};
use rustyline::line_buffer;
@@ -8,7 +10,7 @@ use unicode_width::UnicodeWidthStr;
use crate::context::AppContext;
use crate::event::AppEvent;
-use crate::key_command::complete_command;
+use crate::key_command::{complete_command, Command, InteractiveExecute};
use crate::ui::views::TuiView;
use crate::ui::widgets::{TuiMenu, TuiMultilineText};
use crate::ui::TuiBackend;
@@ -270,6 +272,10 @@ impl<'a> TuiTextField<'a> {
if line_buffer.insert(c, 1).is_some() {
completion_tracker.take();
}
+
+ if let Ok(command) = Command::from_str(line_buffer.as_str()) {
+ command.interactive_execute(context)
+ }
}
_ => {}
}