Skip to content

feat: input history recall via Up/Down arrows and /history command#265

Open
mmacedoeu wants to merge 14 commits into
1jehuang:masterfrom
mmacedoeu:feat/input-history
Open

feat: input history recall via Up/Down arrows and /history command#265
mmacedoeu wants to merge 14 commits into
1jehuang:masterfrom
mmacedoeu:feat/input-history

Conversation

@mmacedoeu
Copy link
Copy Markdown

Summary

Adds input history recall to the TUI, addressing #264. Users can now press Up arrow in an empty input box to recall previously submitted inputs, and Down arrow to navigate forward.

What's new

Keybindings

Key Behavior
Up (empty input) Recall previous submitted input
Down (while browsing) Navigate to next input, clear at end

Any manual edit (typing, backspace) cancels history browsing and returns to normal editing.

Slash commands

Command Behavior
/history or /history input List all stored inputs with indices
/history input N Load entry N into the input box

Behavior

  • Ring buffer of 100 entries (newest at end)
  • Consecutive duplicate inputs are not stored
  • Empty/whitespace-only inputs are not stored
  • Works in both local and remote TUI modes

Files changed (9 files, +326 lines)

File Change
src/tui/app.rs Add input_history, input_history_index fields
src/tui/app/tui_lifecycle.rs Initialize fields in both constructors
src/tui/app/state_ui_runtime.rs push_input_history, input_history_up/down, reset_input_history_browse methods
src/tui/app/input.rs Record history on submit; reset on edit; take_prepared_input records too
src/tui/app/remote/key_handling.rs Wire Up/Down for remote mode; reset on backspace
src/tui/app/state_ui_input_helpers.rs Register /history in autocomplete
src/tui/app/commands.rs /history input [N] command handler
src/tui/ui_overlays.rs Help overlay updated with new keybindings and /history
src/tui/app/tests/remote_startup_input_02/part_01.rs 13 unit tests

Tests

All 13 new tests pass:

  • test_submit_input_records_input_history
  • test_submit_input_deduplicates_consecutive_entries
  • test_submit_input_does_not_record_empty
  • test_input_history_up_recalls_last_input (including boundary at index 0)
  • test_input_history_down_navigates_forward (including clear at end)
  • test_input_history_down_does_nothing_when_not_browsing
  • test_text_input_resets_history_browse
  • test_backspace_resets_history_browse
  • test_history_command_lists_entries
  • test_history_command_empty
  • test_history_input_n_loads_entry
  • test_history_input_n_rejects_invalid_index
  • test_input_history_up_empty_history

Closes #264

mmacedoeu added 7 commits May 24, 2026 15:33
- Add input_history ring buffer (max 100) and input_history_index to App
- Up arrow in empty input recalls previous submitted inputs
- Down arrow navigates forward through history, clearing at the end
- Any manual edit (typing, backspace) cancels history browsing
- Consecutive duplicate inputs are not stored
- /history lists all stored inputs with indices
- /history input N loads entry N into the input box
- Works in both local and remote TUI modes
- Help overlay updated with new keybindings and /history command
- 13 unit tests covering all history operations

Closes 1jehuang#264
…overage

- Up arrow now works when already browsing history (not just from empty input)
- Same fix applied to both local and remote key handlers
- reset_input_history_browse added to insert_input_text, undo_input_change, and remember_input_undo_state for comprehensive coverage
- Removed redundant reset calls from individual key handlers
- Added tests for multi-press Up navigation, Down when not browsing
- 15 total tests passing
… indicator

- /history clear: wipe all entries
- /history search <term>: case-insensitive search with match count
- /history delete N: remove specific entry
- Non-consecutive dedup: re-inserting existing text moves it to the end
- Persistent history: saved to ~/.jcode/input-history.json, loaded on startup
- Status bar indicator: shows '📋 history N/M' while browsing
- input_history_browse_status() added to TuiState trait
- 20 unit tests passing (7 new)
…/history input N

Round 1: save_input_history now deletes file when history is empty so
/clear doesn't leave stale data on disk.

Round 2: Update help overlay, autocomplete description, and add /history
to command_accepts_args. Remove duplicate inherent input_history_browse_status
method in favor of trait impl.

Round 3: Better error messages for /history delete and /history input
when history is empty. Add catch-all for unknown /history subcommands.
Remove double clone.

Round 4: Add missing sync_model_picker_preview_from_input() call on
/history input N.

Round 5: Save undo state before /history input N replaces input.
- Added HistorySearchState struct to App with query, match_index, saved_input, saved_cursor
- Added search methods: start, char, backspace, next, accept, cancel, find_match
- Added handle_history_search_key free function for key dispatch during search
- Wired Ctrl+R in both local and remote key handlers to start search
- Search mode intercepts all keys before normal input handling
- Case-insensitive substring matching, backwards from most recent entry
- Ctrl+R cycles to next older match, Enter accepts, Esc cancels
- Added input_history_search_status to TuiState trait with impls
- UI renders (reverse-i-search) prompt in notification bar and input hint
- 13 unit tests covering start, search, cycle, accept, cancel, edge cases
- Add reset_tab_completion + sync_model_picker_preview guards on accept/cancel
- Fix undo snapshot to capture pre-search input instead of post-find_match state
- Use reset_input_history_browse() in start_input_history_search
- Fix Alt+char captured as search input (check both CTRL and ALT modifiers)
- Update help overlay: Ctrl+R now means 'Search input history'
- Update tool recovery message: refer to /fix instead of Ctrl+R
- Replace unwrap() with if-let in cancel_input_history_search
- Add 2 undo snapshot regression tests
mmacedoeu added 7 commits May 24, 2026 21:56
Add InputHistoryConfig to jcode-config-types with max_entries field.
Supports [input_history] config section and JCODE_INPUT_HISTORY_MAX
env var override. Defaults to 100 entries (hardcoded fallback).
- Add #[serde(default = "default_max_entries")] so max_entries defaults
  to 100 when [input_history] section present but field omitted
- Add deserialize_clamped_usize to clamp TOML/env values to 1..=10000
- Clamp JCODE_INPUT_HISTORY_MAX env var to 1..=10_000
- Add missing JCODE_ACP_{,TOOL_}PROFILE to CONFIG_ENV_KEYS
- Add 5 new config tests for serde default, clamping edge cases
- Command suggestions intercepted Down during history browsing when the
  history entry started with '/' (e.g. /commit). Skip suggestion key
  handling when input_history_index is active.
- Down-past-end of history cleared input instead of restoring the
  original pre-browse text. Added input_history_pre_browse to save and
  restore the input that was present when Up first entered browse mode.
- Ctrl+R search mode ignored Down arrow entirely. Now Down accepts the
  current search match and exits search, allowing continued Down
  navigation through history.
- Ctrl+R search mode ignored Up arrow for cycling older matches.
The '(reverse-i-search) Type to search...' hint was rendered as the
first line inside the input area, pushing the matched history content
below the visible region. The search query and match info are already
displayed in the notification bar above, making this hint redundant.
- Notification bar: simplified to '🔍 match 3/10' instead of the
  dense '(reverse-i-search)'foo': 3/10' format.
- Input area: shows the search query on its own line with a cursor
  block, above the matched history entry rendered with the normal
  prompt. Clear visual separation between what you search and what
  was found.
- HistorySearchState now stores a matches list and selected index
  instead of a single match_index.
- Up/Down arrows navigate the match list, Ctrl+R cycles down.
- Input area renders all matching entries (up to 8) with selection
  highlight (▸ for selected, dimmed for others).
- Empty query shows all history entries for browsing.
- Notification bar shows '🔍 match N/M' counter.
- TuiState trait exposes input_history_search_matches() for rendering.
The search results were rendered inside the input area at the bottom of
the screen, getting cut off. Now they render as a bordered floating
popup above the input area with:
- Search query line with cursor block
- Separator line
- Up to 8 results with selection highlight (▸ for selected, dimmed rest)
- Scroll window tracks the selected item
- Rounded border with 'History Search' title
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Input history recall — repeat/scroll previous submitted inputs

1 participant