Add setting for keeping typed query when exiting (#451)

* Add option for keeping typed query on escape

fixes #422

* chore: Address duplicate if statement blocks
This commit is contained in:
Sam Lanning 2022-11-06 07:34:14 +00:00 committed by GitHub
parent d87abbd3dc
commit 4768b16b74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 8 deletions

View file

@ -33,3 +33,7 @@
## which style to use ## which style to use
## possible values: auto, full, compact ## possible values: auto, full, compact
#style = "auto" #style = "auto"
## what to do when the escape key is pressed when searching
## possible values: return-original, return-query
# exit_mode = "return-original"

View file

@ -54,6 +54,15 @@ impl FilterMode {
} }
} }
#[derive(Clone, Debug, Deserialize, Copy)]
pub enum ExitMode {
#[serde(rename = "return-original")]
ReturnOriginal,
#[serde(rename = "return-query")]
ReturnQuery,
}
// FIXME: Can use upstream Dialect enum if https://github.com/stevedonovan/chrono-english/pull/16 is merged // FIXME: Can use upstream Dialect enum if https://github.com/stevedonovan/chrono-english/pull/16 is merged
// FIXME: Above PR was merged, but dependency was changed to interim (fork of chrono-english) in the ... interim // FIXME: Above PR was merged, but dependency was changed to interim (fork of chrono-english) in the ... interim
#[derive(Clone, Debug, Deserialize, Copy)] #[derive(Clone, Debug, Deserialize, Copy)]
@ -99,6 +108,7 @@ pub struct Settings {
pub session_path: String, pub session_path: String,
pub search_mode: SearchMode, pub search_mode: SearchMode,
pub filter_mode: FilterMode, pub filter_mode: FilterMode,
pub exit_mode: ExitMode,
// This is automatically loaded when settings is created. Do not set in // This is automatically loaded when settings is created. Do not set in
// config! Keep secrets and settings apart. // config! Keep secrets and settings apart.
pub session_token: String, pub session_token: String,
@ -278,6 +288,7 @@ impl Settings {
.set_default("sync_address", "https://api.atuin.sh")? .set_default("sync_address", "https://api.atuin.sh")?
.set_default("search_mode", "fuzzy")? .set_default("search_mode", "fuzzy")?
.set_default("filter_mode", "global")? .set_default("filter_mode", "global")?
.set_default("exit_mode", "return-original")?
.set_default("session_token", "")? .set_default("session_token", "")?
.set_default("style", "auto")? .set_default("style", "auto")?
.add_source( .add_source(

View file

@ -143,6 +143,21 @@ Filter modes can still be toggled via ctrl-r
search_mode = "fulltext" search_mode = "fulltext"
``` ```
### `exit_mode`
What to do when the escape key is pressed when searching
| Value | Behaviour |
|------------------------- | --------------- |
| return-original (default) | Set the command-line to the value it had before starting search |
| return-query | Set the command-line to the search query you have entered so far |
Pressing ctrl+c or ctrl+d will always return the original command-line value.
```
exit_mode = "return-query"
```
#### `fuzzy` search syntax #### `fuzzy` search syntax
The "fuzzy" search syntax is based on the The "fuzzy" search syntax is based on the

View file

@ -21,7 +21,7 @@ use atuin_client::{
database::Context, database::Context,
database::Database, database::Database,
history::History, history::History,
settings::{FilterMode, SearchMode, Settings}, settings::{ExitMode, FilterMode, SearchMode, Settings},
}; };
use super::{ use super::{
@ -31,6 +31,9 @@ use super::{
}; };
use crate::VERSION; use crate::VERSION;
const RETURN_ORIGINAL: usize = usize::MAX;
const RETURN_QUERY: usize = usize::MAX - 1;
struct State { struct State {
history_count: i64, history_count: i64,
input: Cursor, input: Cursor,
@ -59,9 +62,20 @@ impl State {
Ok(results) Ok(results)
} }
fn handle_input(&mut self, input: &TermEvent, len: usize) -> Option<usize> { fn handle_input(
&mut self,
settings: &Settings,
input: &TermEvent,
len: usize,
) -> Option<usize> {
match input { match input {
TermEvent::Key(Key::Esc | Key::Ctrl('c' | 'd' | 'g')) => return Some(usize::MAX), TermEvent::Key(Key::Ctrl('c' | 'd' | 'g')) => return Some(RETURN_ORIGINAL),
TermEvent::Key(Key::Esc) => {
return Some(match settings.exit_mode {
ExitMode::ReturnOriginal => RETURN_ORIGINAL,
ExitMode::ReturnQuery => RETURN_QUERY,
})
}
TermEvent::Key(Key::Char('\n')) => { TermEvent::Key(Key::Char('\n')) => {
return Some(self.results_state.selected()); return Some(self.results_state.selected());
} }
@ -323,14 +337,14 @@ pub async fn history(
// Handle input // Handle input
if let Event::Input(input) = events.next()? { if let Event::Input(input) = events.next()? {
if let Some(i) = app.handle_input(&input, results.len()) { if let Some(i) = app.handle_input(settings, &input, results.len()) {
break 'render i; break 'render i;
} }
} }
// After we receive input process the whole event channel before query/render. // After we receive input process the whole event channel before query/render.
while let Ok(Event::Input(input)) = events.try_next() { while let Ok(Event::Input(input)) = events.try_next() {
if let Some(i) = app.handle_input(&input, results.len()) { if let Some(i) = app.handle_input(settings, &input, results.len()) {
break 'render i; break 'render i;
} }
} }
@ -356,11 +370,12 @@ pub async fn history(
if index < results.len() { if index < results.len() {
// index is in bounds so we return that entry // index is in bounds so we return that entry
Ok(results.swap_remove(index).command) Ok(results.swap_remove(index).command)
} else if index == usize::MAX { } else if index == RETURN_ORIGINAL {
// index is max which implies an early exit
Ok(String::new()) Ok(String::new())
} else { } else {
// out of bounds usually implies no selected entry so we return the input // Either:
// * index == RETURN_QUERY, in which case we should return the input
// * out of bounds -> usually implies no selected entry so we return the input
Ok(app.input.into_inner()) Ok(app.input.into_inner())
} }
} }