From d6bc9d549f6b4f0cc896c1186a99c798d068681f Mon Sep 17 00:00:00 2001 From: Loongphy Date: Mon, 18 May 2026 17:23:05 +0800 Subject: [PATCH] fix live tui cursor fallback --- src/cli/live_tui.zig | 2 +- tests/cli_picker_test.zig | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/cli/live_tui.zig b/src/cli/live_tui.zig index 5409704b..87c10964 100644 --- a/src/cli/live_tui.zig +++ b/src/cli/live_tui.zig @@ -290,7 +290,7 @@ pub fn resolveSelectedIndex( ) !?usize { if (rows.selectable_row_indices.len == 0) return null; const selected_idx = if (selected_account_key.*) |key| - picker.selectableIndexForAccountKey(rows, reg, key) orelse picker.activeSelectableIndex(rows) orelse 0 + picker.selectableIndexForAccountKey(rows, reg, key) orelse 0 else picker.activeSelectableIndex(rows) orelse 0; try picker.replaceSelectedAccountKeyForSelectable(allocator, selected_account_key, rows, reg, selected_idx); diff --git a/tests/cli_picker_test.zig b/tests/cli_picker_test.zig index f6745051..b909e7ad 100644 --- a/tests/cli_picker_test.zig +++ b/tests/cli_picker_test.zig @@ -919,6 +919,59 @@ test "Scenario: Given live switch navigation shortcuts when an account is unavai try std.testing.expectEqualStrings("user-1::acc-1", selected_account_key.?); } +test "Scenario: Given a stale live cursor key when resolving then switch does not snap back to active" { + const gpa = std.testing.allocator; + var reg = makeTestRegistry(); + defer reg.deinit(gpa); + + try appendTestAccount(gpa, ®, "user-1::acc-1", "active@example.com", "", .team); + try appendTestAccount(gpa, ®, "user-1::acc-2", "second@example.com", "", .team); + try appendTestAccount(gpa, ®, "user-1::acc-3", "third@example.com", "", .team); + reg.active_account_key = try gpa.dupe(u8, "user-1::acc-2"); + + var rows = try live_tui.buildSelectableRows(gpa, .{ + .reg = ®, + .usage_overrides = null, + }); + defer rows.deinit(gpa); + + var selected_account_key: ?[]u8 = try gpa.dupe(u8, "user-1::missing"); + defer if (selected_account_key) |key| gpa.free(key); + + const resolved_idx = try live_tui.resolveSelectedIndex(gpa, &selected_account_key, &rows, ®); + try std.testing.expectEqual(@as(?usize, 0), resolved_idx); + try std.testing.expectEqualStrings("user-1::acc-1", selected_account_key.?); + + try std.testing.expect(try live_tui.moveSelectedIndexForKey(gpa, &selected_account_key, &rows, ®, TuiInputKey.move_down)); + try std.testing.expectEqualStrings("user-1::acc-2", selected_account_key.?); +} + +test "Scenario: Given active first account when navigating live switch then adjacent accounts are not skipped" { + const gpa = std.testing.allocator; + var reg = makeTestRegistry(); + defer reg.deinit(gpa); + + try appendTestAccount(gpa, ®, "user-1::acc-1", "active@example.com", "", .team); + try appendTestAccount(gpa, ®, "user-1::acc-2", "second@example.com", "", .team); + try appendTestAccount(gpa, ®, "user-1::acc-3", "third@example.com", "", .team); + reg.active_account_key = try gpa.dupe(u8, "user-1::acc-1"); + + var rows = try live_tui.buildSelectableRows(gpa, .{ + .reg = ®, + .usage_overrides = null, + }); + defer rows.deinit(gpa); + + var selected_account_key: ?[]u8 = try gpa.dupe(u8, "user-1::acc-3"); + defer if (selected_account_key) |key| gpa.free(key); + + try std.testing.expect(try live_tui.moveSelectedIndexForKey(gpa, &selected_account_key, &rows, ®, TuiInputKey.keyboard_up)); + try std.testing.expectEqualStrings("user-1::acc-2", selected_account_key.?); + + try std.testing.expect(try live_tui.moveSelectedIndexForKey(gpa, &selected_account_key, &rows, ®, TuiInputKey.keyboard_up)); + try std.testing.expectEqualStrings("user-1::acc-1", selected_account_key.?); +} + test "Scenario: Given live auto switch state when starting then the initial display triggers auto-switch once" { var enabled = live_tui.LiveAutoSwitchState.init(true); try std.testing.expect(enabled.takePending());