Skip to content

refactor(input,ui): track input mode per tab instead of globally#62

Merged
roramirez merged 1 commit into
mainfrom
refactor/per-tab-input-mode
Jul 12, 2026
Merged

refactor(input,ui): track input mode per tab instead of globally#62
roramirez merged 1 commit into
mainfrom
refactor/per-tab-input-mode

Conversation

@roramirez

Copy link
Copy Markdown
Owner

Summary

Moves the InputMode field from the global AppState onto per-tab TabState, so each tab keeps its own Insert/Normal/Visual/Search mode. Switching tabs now restores that tab's own mode instead of sharing one mode across the whole window — matching how zoomed and passthrough are already handled (per-tab, session-only, never persisted).

Changes

  • mode field moved from AppState to TabState; initialized to Insert at all three TabState construction sites (new_tab, session restore, add_empty_tab).
  • Access routed through panic-free mode() -> &InputMode and set_mode(m) accessors that delegate to the active tab, with a static DEFAULT_MODE = Insert fallback for the empty-tabs case.
  • do_set_mode refactored to compute the resolved mode into a local before taking &mut self, avoiding a double borrow.
  • Added on_active_tab_changed() to clear/recompute the global search_matches (which describe only the active tab's grid) on next_tab/prev_tab/do_go_to_tab.
  • ~70 read/write call sites migrated across app_event, app_state, mouse_ops, input_ops, render_ops, and views.

Invariant

Mode stays session-only and is never serialized — src/session/mod.rs has zero mode references.

How to test

  1. cargo run and open a second tab (Ctrl+T).
  2. In tab 1, enter NORMAL mode (Ctrl+[ / your normal-mode binding) — the mode badge shows NORMAL.
  3. Switch to tab 2 (Ctrl+PageDown / Ctrl+Tab) — the badge shows INSERT (tab 2 keeps its own mode).
  4. Switch back to tab 1 — it is still in NORMAL. The mode did not leak across tabs.
  5. In tab 1, enter VISUAL mode and start a selection, switch away and back — the tab returns to its own VISUAL state; tab 2 is unaffected.
  6. Open scrollback search (/) in one tab and switch tabs — no stale match highlight appears on the other tab (search_matches are cleared/recomputed on switch).

Automated coverage: cargo test — new per-tab isolation tests assert that a new tab starts in Insert, mode is tracked per tab across switches, Visual does not leak between tabs, and search_matches are cleared on tab switch.

Checks

  • Full suite green: 1203 + 256 passing.
  • cargo fmt --check clean; cargo clippy --locked -- -D warnings clean.

Move the InputMode field from AppState onto TabState so each tab keeps
its own Insert/Normal/Visual/Search mode; switching tabs restores that
tab's mode. Access is routed through panic-free mode()/set_mode()
accessors, and the global search_matches are cleared/recomputed on tab
switch. Mode stays session-only and is never persisted.
@roramirez roramirez merged commit e618fee into main Jul 12, 2026
2 checks passed
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.

1 participant