Allow changing search_mode during interactive search (#586)

* Make search_mode a part of SearchState

* Allow changing search mode using ctrl+s

* Tweak state reset for switched_search_mode

* Improve search_mode display in interactive mode

* Incorporate review suggestion

* Tweak language

* Fix Clippy and format
This commit is contained in:
Krut Patel 2023-03-22 21:46:59 +05:30 committed by GitHub
parent bc06d5f36f
commit 378be6b790
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 14 deletions

View File

@ -34,6 +34,32 @@ pub enum SearchMode {
Skim,
}
impl SearchMode {
pub fn as_str(&self) -> &'static str {
match self {
SearchMode::Prefix => "PREFIX",
SearchMode::FullText => "FULLTXT",
SearchMode::Fuzzy => "FUZZY",
SearchMode::Skim => "SKIM",
}
}
pub fn next(&self, settings: &Settings) -> Self {
match self {
SearchMode::Prefix => SearchMode::FullText,
SearchMode::FullText => {
// if the user is using skim, we go to skim, otherwise fuzzy.
if settings.search_mode == SearchMode::Skim {
SearchMode::Skim
} else {
SearchMode::Fuzzy
}
}
SearchMode::Fuzzy => SearchMode::Prefix,
SearchMode::Skim => SearchMode::Prefix,
}
}
}
#[derive(Clone, Debug, Deserialize, Copy, PartialEq, Eq, ValueEnum)]
pub enum FilterMode {
#[serde(rename = "global")]

View File

@ -54,15 +54,16 @@ struct State {
pub struct SearchState {
pub input: Cursor,
pub filter_mode: FilterMode,
pub search_mode: SearchMode,
/// Store if the user has _just_ changed the search mode.
/// If so, we change the UI to show the search mode instead
/// of the filter mode until user starts typing again.
switched_search_mode: bool,
pub context: Context,
}
impl State {
async fn query_results(
&mut self,
search_mode: SearchMode,
db: &mut impl Database,
) -> Result<Vec<Arc<HistoryWrapper>>> {
async fn query_results(&mut self, db: &mut impl Database) -> Result<Vec<Arc<HistoryWrapper>>> {
let i = self.search.input.as_str();
let results = if i.is_empty() {
db.list(
@ -76,7 +77,7 @@ impl State {
.map(|history| HistoryWrapper { history, count: 1 })
.map(Arc::new)
.collect::<Vec<_>>()
} else if search_mode == SearchMode::Skim {
} else if self.search.search_mode == SearchMode::Skim {
if self.all_history.is_empty() {
self.all_history = db
.all_with_count()
@ -91,7 +92,7 @@ impl State {
super::skim_impl::fuzzy_search(&self.search, &self.all_history).await
} else {
db.search(
search_mode,
self.search.search_mode,
self.search.filter_mode,
&self.search.context,
i,
@ -154,6 +155,8 @@ impl State {
let ctrl = input.modifiers.contains(KeyModifiers::CONTROL);
let alt = input.modifiers.contains(KeyModifiers::ALT);
// reset the state, will be set to true later if user really did change it
self.search.switched_search_mode = false;
match input.code {
KeyCode::Char('c' | 'd' | 'g') if ctrl => return Some(RETURN_ORIGINAL),
KeyCode::Esc => {
@ -226,6 +229,10 @@ impl State {
let i = (i + 1) % FILTER_MODES.len();
self.search.filter_mode = FILTER_MODES[i];
}
KeyCode::Char('s') if ctrl => {
self.search.switched_search_mode = true;
self.search.search_mode = self.search.search_mode.next(settings);
}
KeyCode::Down if self.results_state.selected() == 0 => return Some(RETURN_ORIGINAL),
KeyCode::Down => {
let i = self.results_state.selected().saturating_sub(1);
@ -395,11 +402,17 @@ impl State {
}
fn build_input(&mut self, compact: bool, chunk_width: usize) -> Paragraph {
let input = format!(
"[{:^14}] {}",
self.search.filter_mode.as_str(),
self.search.input.as_str(),
);
/// Max width of the UI box showing current mode
const MAX_WIDTH: usize = 14;
let (pref, mode) = if self.search.switched_search_mode {
(" SRCH:", self.search.search_mode.as_str())
} else {
("", self.search.filter_mode.as_str())
};
let mode_width = MAX_WIDTH - pref.len();
// sanity check to ensure we don't exceed the layout limits
debug_assert!(mode_width >= mode.len(), "mode name '{mode}' is too long!");
let input = format!("[{pref}{mode:^mode_width$}] {}", self.search.input.as_str(),);
let input = if compact {
Paragraph::new(input)
} else {
@ -543,11 +556,13 @@ pub async fn history(
} else {
settings.filter_mode
},
search_mode: settings.search_mode,
switched_search_mode: false,
},
all_history: Vec::new(),
};
let mut results = app.query_results(settings.search_mode, db).await?;
let mut results = app.query_results(db).await?;
let index = 'render: loop {
let compact = match settings.style {
@ -561,6 +576,7 @@ pub async fn history(
let initial_input = app.search.input.as_str().to_owned();
let initial_filter_mode = app.search.filter_mode;
let initial_search_mode = app.search.search_mode;
let event_ready = tokio::task::spawn_blocking(|| event::poll(Duration::from_millis(250)));
@ -584,8 +600,9 @@ pub async fn history(
if initial_input != app.search.input.as_str()
|| initial_filter_mode != app.search.filter_mode
|| initial_search_mode != app.search.search_mode
{
results = app.query_results(settings.search_mode, db).await?;
results = app.query_results(db).await?;
}
};
if index < results.len() {