Conversation
Implements foundation for vi-style modal editing in Pair Writing mode: - Configuration: Add viMode to VaultConfig, flow through to VaultInfo - Keyboard detection: useHasKeyboard hook to gate vi mode on physical keyboard - State machine: useViMode hook with normal/insert/command mode transitions - Cursor overlay: useViCursor hook + ViCursor component with mirror element technique - Mode indicator: ViModeIndicator component showing current mode This is the infrastructure layer. Movement commands, editing, and ex commands come in subsequent chunks. Refs #394 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Export ViCursor from pair-writing/index.ts for public API - Remove duplicate ViMode type from ViModeIndicator, import from useViMode - Add Ctrl+C handling in command mode to abort (standard vi behavior) - Add test for Ctrl+C command mode abort Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Chunk 6 - Basic Movement Commands: - Add h/j/k/l for character and line movement - Add 0/$ for line start/end movement - Export helper functions: getLineInfo, getLineCount, getLinePositions, moveCursor - Handle boundary clamping and column preservation Chunk 7 - Insert Mode Entry Commands: - i: insert at cursor (existing, confirmed working) - a: append after cursor - A: append at end of line - o: open line below - O: open line above - Wire up onContentChange callback for o/O operations Completes Milestone B - navigation and insert mode now functional. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Chunk 8 - Undo Stack: - Add internal undo stack with 100 entry limit - pushUndoState captures content and cursor before edits - 'u' command restores previous state - Insert mode batches into single undo entry Chunk 9 - Delete Commands: - 'x' deletes character at cursor - 'dd' deletes current line (pending operator pattern) - Both push to undo stack before delete Chunk 10 - Yank/Put Commands: - 'yy' yanks current line to internal clipboard - 'p' pastes after current line - 'P' pastes before current line - Clipboard persists within session (REQ-20, REQ-21) Chunk 11 - Numeric Prefixes: - Digits 1-9 start count accumulation - '0' is line-start when no count, digit when accumulating - Count applies to: h, l, j, k, x, dd, yy - Large counts clamp to boundaries Completes Milestone C - full Normal mode editing now functional. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The return value was set inside an async state setter callback, making it unreliable. Since the return value was never used, removed it entirely rather than leave a trap for future code. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…egration Chunk 12 - Command Mode UI: - Add ViCommandLine component for ex command display - Show ":" prefix with command text and cursor indicator - Style to match vim command line appearance Chunk 13 - Ex Commands: - :w saves file (calls onSave) - :wq/:x saves and exits (calls onSave then onExit) - :q triggers quit with unsaved check (calls onQuitWithUnsaved) - :q! force quits (calls onExit directly) Chunk 14 - Integration: - Wire useViMode, useViCursor, useHasKeyboard into PairWritingEditor - Add ViCursor overlay, ViModeIndicator, ViCommandLine components - Gate on vault viMode config AND keyboard detection - Connect callbacks to existing save/exit handlers Chunk 15 - Polish: - Escape in Normal mode clears pending operator and count - ViCommandLine respects isProcessingQuickAction state - Focus stays on textarea during command mode Completes Milestone D - vi mode feature complete. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove onSubmit, onCancel, onChange props from ViCommandLine (these were never used; all input handled by useViMode) - Remove dead code passing empty functions from PairWritingEditor - Remove "Props API Tests" section testing non-existent props - Wrap fireEvent calls in act() to eliminate React warnings - Use separate act() calls for sequential keypresses in ex commands Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Add "Enable Vi Mode" checkbox in new "Editing" section of ConfigEditorDialog, allowing users to toggle vi mode without manually editing config files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The viMode field was missing from the initialConfig passed to ConfigEditorDialog in both App.tsx and VaultSelect.tsx, causing the value to not be saved when toggling the checkbox. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The viMode field was missing from local state updates after saving: - VaultSelect.tsx: setVaults() wasn't updating viMode - reducer.ts: UPDATE_VAULT_CONFIG wasn't applying viMode This caused the checkbox to appear stuck after toggling because the local state wasn't updated, so reopening the dialog showed the old value. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed cursor background from --color-text (same as text color) to --color-accent-quartary (Sunset Gold) so it's visible against both the dark background and text. Also softened the blink animation to fade between 0.85-0.3 opacity instead of completely disappearing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The cursor position was being calculated by subtracting textarea's viewport position from the span's viewport position, but the mirror element is positioned at -9999px off-screen. This resulted in very negative coordinates. Fixed by measuring the span position relative to the mirror element instead, which gives correct offsets that work as the cursor position. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added scrollCursorIntoView() that calculates cursor line position and adjusts textarea.scrollTop when the cursor moves outside the visible area. Called after j/k movement commands to keep cursor visible. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The up-scroll was triggering too late (5-6 lines off-screen). Added a 3-line margin so scrolling starts before the cursor reaches the top edge, matching the responsive feel of down-scrolling. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous line-based calculation assumed one logical line = one visual line, which broke with text wrapping. Now uses the same mirror element technique as cursor positioning to get the actual pixel position accounting for wrapped text. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Focus the textarea on mount so users can start typing immediately without clicking the text area first. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Captures lessons learned from the vi mode feature: - Visual components need visual testing (cursor was invisible) - Config changes must be traced end-to-end - Text wrapping breaks line-based calculations - Polish emerges from actual use Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
h,j,k,l,0,$i,a,A,o,Ox,dd,yy,p,P,u(undo)5j,3dd, etc.:w,:wq,:q,:q!Test plan
viMode: truein vault config, verify:ienters Insert mode (cursor changes to line)Escapereturns to Normal modehjkl,0$)x,dd,yy,p):wsaves,:wqsaves and exits,:q!exits without savingCloses #394
🤖 Generated with Claude Code