aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@atuin.sh>2026-01-22 15:56:10 -0800
committerGitHub <noreply@github.com>2026-01-22 15:56:10 -0800
commit1fb16c0ab6821f66014948a59a34807c55cf38db (patch)
treec28f55bc3d83aec25ecb0da893bda8eea6daffa2
parentfeat: add custom column support (#3089) (diff)
downloadatuin-1fb16c0ab6821f66014948a59a34807c55cf38db.zip
feat: left arrow/backspace on empty to start edit (#3090)
resolves #1906 <!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing one, we'd really appreciate if you open an issue, post on the forum, or drop in on Discord --> ## Checks - [ ] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle - [ ] I have checked that there are no existing pull requests for the same thing
-rw-r--r--crates/atuin/src/command/client/search/interactive.rs53
1 files changed, 38 insertions, 15 deletions
diff --git a/crates/atuin/src/command/client/search/interactive.rs b/crates/atuin/src/command/client/search/interactive.rs
index 3a69b973..2b0522fc 100644
--- a/crates/atuin/src/command/client/search/interactive.rs
+++ b/crates/atuin/src/command/client/search/interactive.rs
@@ -306,6 +306,9 @@ impl State {
{
Some(InputAction::Accept(self.results_state.selected()))
}
+ KeyCode::Left | KeyCode::Backspace if self.search.input.as_str().is_empty() => {
+ Some(InputAction::Accept(self.results_state.selected()))
+ }
KeyCode::Char('o') if ctrl => {
self.tab_index = (self.tab_index + 1) % TAB_TITLES.len();
Some(InputAction::Continue)
@@ -1747,42 +1750,62 @@ mod tests {
"Tab should always accept"
);
- // Test left arrow with accept_past_line_start disabled (should continue)
+ // Test left arrow with empty search should accept (new default behavior)
let left_event = KeyEvent::new(KeyCode::Left, KeyModifiers::NONE);
let result = state.handle_key_input(&settings, &left_event);
assert!(
- matches!(result, super::InputAction::Continue),
- "Left arrow should continue when disabled"
+ matches!(result, super::InputAction::Accept(_)),
+ "Left arrow should accept when search is empty"
);
- // Test left arrow with accept_past_line_start enabled (should accept at start of line)
- settings.keys.accept_past_line_start = true;
- let result = state.handle_key_input(&settings, &left_event);
+ // Test backspace with empty search should accept (new default behavior)
+ let backspace_event = KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE);
+ let result = state.handle_key_input(&settings, &backspace_event);
assert!(
matches!(result, super::InputAction::Accept(_)),
- "Left arrow should accept at start of line when enabled"
+ "Backspace should accept when search is empty"
+ );
+
+ // Test left/backspace with non-empty search at cursor start should NOT accept
+ state.search.input.insert('t');
+ state.search.input.insert('e');
+ state.search.input.insert('s');
+ state.search.input.insert('t');
+ state.search.input.start(); // Move cursor to start of non-empty search
+
+ let left_event = KeyEvent::new(KeyCode::Left, KeyModifiers::NONE);
+ let result = state.handle_key_input(&settings, &left_event);
+ assert!(
+ matches!(result, super::InputAction::Continue),
+ "Left arrow should continue when search is not empty (even at cursor start)"
);
- settings.keys.accept_past_line_start = false;
let backspace_event = KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE);
let result = state.handle_key_input(&settings, &backspace_event);
assert!(
matches!(result, super::InputAction::Continue),
- "Backspace should continue when disabled"
+ "Backspace should continue when search is not empty (even at cursor start)"
+ );
+
+ // Test that accept_past_line_start flag still works with non-empty search at start
+ settings.keys.accept_past_line_start = true;
+ let result = state.handle_key_input(&settings, &left_event);
+ assert!(
+ matches!(result, super::InputAction::Accept(_)),
+ "Left arrow should accept at cursor start when flag enabled (even with non-empty search)"
);
+ settings.keys.accept_past_line_start = false;
+ // Test that accept_with_backspace flag still works with non-empty search at start
settings.keys.accept_with_backspace = true;
let result = state.handle_key_input(&settings, &backspace_event);
assert!(
matches!(result, super::InputAction::Accept(_)),
- "Backspace should accept at start of line when enabled"
+ "Backspace should accept at cursor start when flag enabled (even with non-empty search)"
);
+ settings.keys.accept_with_backspace = false;
- state.search.input.insert('t');
- state.search.input.insert('e');
- state.search.input.insert('s');
- state.search.input.insert('t');
- state.search.input.end();
+ state.search.input.end(); // Move cursor back to end for remaining tests
let right_event = KeyEvent::new(KeyCode::Right, KeyModifiers::NONE);
let result = state.handle_key_input(&settings, &right_event);