Input history: reset the nav cursor on every submit
`push_history` skipped its `history_cursor` / `history_draft` reset on the consecutive-duplicate early-return path. Recalling a command with Up and re-submitting it unchanged left the cursor stranded at that entry, so the next Up stepped backwards from there instead of restarting at the newest entry. Move the reset ahead of the early-return guards. Adds a Tier-1 regression test driving the recall/resubmit keystroke sequence.
This commit is contained in:
+33
-2
@@ -849,6 +849,13 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn push_history(&mut self, line: &str) {
|
fn push_history(&mut self, line: &str) {
|
||||||
|
// Submitting a command always ends history navigation —
|
||||||
|
// the next Up restarts from the newest entry. Reset here,
|
||||||
|
// before the early-return guards below, so a recalled
|
||||||
|
// command re-submitted unchanged (a consecutive duplicate)
|
||||||
|
// doesn't strand the cursor at its old position.
|
||||||
|
self.history_cursor = None;
|
||||||
|
self.history_draft = None;
|
||||||
// Skip empties and consecutive duplicates — the same
|
// Skip empties and consecutive duplicates — the same
|
||||||
// trick most shells use to keep navigation pleasant.
|
// trick most shells use to keep navigation pleasant.
|
||||||
if line.is_empty() {
|
if line.is_empty() {
|
||||||
@@ -861,8 +868,6 @@ impl App {
|
|||||||
while self.history.len() > HISTORY_CAPACITY {
|
while self.history.len() > HISTORY_CAPACITY {
|
||||||
self.history.remove(0);
|
self.history.remove(0);
|
||||||
}
|
}
|
||||||
self.history_cursor = None;
|
|
||||||
self.history_draft = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn submit(&mut self) -> Vec<Action> {
|
fn submit(&mut self) -> Vec<Action> {
|
||||||
@@ -2923,6 +2928,32 @@ mod tests {
|
|||||||
assert_eq!(app.input, "drop table A");
|
assert_eq!(app.input, "drop table A");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resubmitting_a_recalled_command_does_not_strand_the_cursor() {
|
||||||
|
// Regression: a recalled command re-submitted unchanged
|
||||||
|
// is a consecutive duplicate, so `push_history` skips the
|
||||||
|
// append — but it must still reset the navigation cursor.
|
||||||
|
// Otherwise the next Up steps backwards from the stranded
|
||||||
|
// position instead of restarting at the newest entry.
|
||||||
|
let mut app = App::new();
|
||||||
|
type_str(&mut app, "show data Thing");
|
||||||
|
submit(&mut app);
|
||||||
|
type_str(&mut app, "insert into Thing values (1)");
|
||||||
|
submit(&mut app);
|
||||||
|
|
||||||
|
// Recall the insert and resubmit it unchanged, repeatedly.
|
||||||
|
// Every fresh Up must restart at the newest entry.
|
||||||
|
for round in 0..3 {
|
||||||
|
app.update(key(KeyCode::Up));
|
||||||
|
assert_eq!(
|
||||||
|
app.input, "insert into Thing values (1)",
|
||||||
|
"Up #{} should recall the newest entry",
|
||||||
|
round + 1,
|
||||||
|
);
|
||||||
|
submit(&mut app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn down_arrow_returns_through_history_to_the_draft() {
|
fn down_arrow_returns_through_history_to_the_draft() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user