Skip to content

Vim motion support#4

Open
KyawTheMonkey wants to merge 5 commits into
phranck:mainfrom
KyawTheMonkey:vim-motion-support
Open

Vim motion support#4
KyawTheMonkey wants to merge 5 commits into
phranck:mainfrom
KyawTheMonkey:vim-motion-support

Conversation

@KyawTheMonkey

Copy link
Copy Markdown

Summary

Adds opt-in vim-style keyboard navigation to all interactive views in TUIkit, alongside a complementary horizontal navigation modifier.

What changed

New public API — two composable modifiers:

// Vertical (up/down within a list, menu, or VStack)
.verticalNavigationStyle(.vim)
.verticalNavigationStyle(.vim, .arrowKey)   // both active

// Horizontal (Tab-cycling between sections/panels)
.horizontalNavigationStyle(.vim)
.horizontalNavigationStyle(.tab, .vim)      // both active

Both modifiers accept a variadic Set of styles, so each scheme is fully opt-in and can be combined freely. Neither changes the default behaviour. Existing apps get [.arrowKey] vertical and [.tab] horizontal with zero migration required.

Checklist

  • Swift 6.0 compatible (no features requiring a newer compiler)
  • Builds on macOS and Linux (swift build succeeds on both)
  • All tests pass (swift test)
  • No new SwiftLint warnings (swiftlint)
  • Public APIs match SwiftUI signatures (parameter names, order, types)
  • Modifiers propagate through the View hierarchy

Test Plan

35 new tests across 4 new suites in 2 existing test files

Tests/TUIkitTests/ItemListHandlerTests.swift:

ItemListHandlerVimMotionTests (15 tests) — unit tests for every vim binding directly on ItemListHandler:

  • j moves down and wraps at the end
  • k moves up and wraps at the start
  • g jumps to index 0; respects selectableIndices (jumps to first selectable)
  • G jumps to last index; respects selectableIndices
  • Ctrl+d moves max(1, viewportHeight/2) forward, clamps at last item, moves at least 1 step even when viewport height is 1
  • Ctrl+u moves half page backward, clamps at first item
  • Ctrl+f moves a full page forward
  • Ctrl+b moves a full page backward
  • ItemListHandlerNavigationStyleGatingTests (5 tests) — verifies the opt-in/opt-out gating:
    • Default [.arrowKey]: j/k return false and don't move the cursor
    • [.vim] only: .down/.home/.pageDown return false; vim keys work
    • [.arrowKey, .vim]: both sets work simultaneously
    • [] empty set: all navigation keys return false

Tests/TUIkitTests/FocusManagerTests.swift:

FocusManagerVerticalVimTests (5 tests) — covers j/k in FocusManager.dispatchKeyEvent:

  • Default style: j/k not consumed by the fallback
  • [.vim]: j calls focusNextInSection, k calls focusPreviousInSection
  • [.vim] only: .down arrow not consumed by the fallback
  • [.arrowKey, .vim]: both key sets drive section navigation
  • beginRenderPass() resets verticalNavigationStyles back to [.arrowKey]

FocusManagerHorizontalVimTests (8 tests) — covers h/l and Tab gating:

  • Default [.tab]: h/l not consumed, Tab cycles focus
  • [.vim] only: l → focusNext, h → focusPrevious; Tab returns false
  • [.tab] only: l/h not consumed
  • [.tab, .vim]: Tab, l, and h all cycle focus correctly
  • beginRenderPass() resets horizontalNavigationStyles back to [.tab]

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