Factor out the repl-eval and repl-stop event dispatching code into
replEval() and replStop() helper functions that are shared between
Vim and Helix keybindings.
This refactoring:
- Reduces code duplication between Vim :w/:q and Helix :w/:q commands
- Makes the keybinding handlers more maintainable
- Properly implements Helix commands using the commands.of() API
- Ensures consistent behavior across both keybinding modes
The Helix keybindings now properly integrate with the REPL using the
same event dispatch mechanism as Vim, dispatching custom repl-evaluate
and repl-stop events with fallbacks to keyboard events.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add support for Helix editor keybindings in the REPL, providing users
with a modern, selection-first modal editing experience as an alternative
to Vim, Emacs, and VSCode keybindings.
Helix Keybindings Integration:
- Add codemirror-helix@^0.5.0 dependency to @strudel/codemirror
- Import and register helix keybindings in keybindings.mjs
- Add 'Helix' option to keybindings selector in Settings UI
- Create comprehensive user documentation at technical-manual/helix.mdx
- Update developer documentation with keybinding integration pattern
The Helix mode provides selection-first editing (select → action) which
differs from Vim's action-motion paradigm, offering an alternative
workflow for modal editing enthusiasts.
Documentation:
- Update CLAUDE.md with Helix support and keybinding addition process
- Create helix.mdx with user-facing documentation and command reference
- Update CHANGELOG.md with December 2025 entry
Testing:
Run `pnpm i` to install new dependencies, then `pnpm dev` to test.
Verify Helix mode works in Settings → Keybindings → Helix.
- Merged scalePreColonHandler and scaleAfterColonHandler into single scaleHandler
- Merged modePreColonHandler and modeAfterColonHandler into single modeHandler
- Cached all regex patterns as constants above their respective handler functions
- Eliminated regex compilation overhead on every keystroke/navigation event
- Improved code maintainability by reducing duplication between similar handlers
- Preserved exact same functionality while improving performance
Each handler now follows a consistent pattern of checking after-colon context
first (more specific) then pre-colon context, with all regex patterns
pre-compiled for better performance during intensive autocomplete sessions.
- Added modePreColonHandler for autocomplete of mode values (below, above, duck, root)
- Added modeAfterColonHandler for pitch name completion after colon in mode:anchor syntax
- Follows same pattern as sound/bank/scale handlers for complex expressions
- Supports expressions like '<above [below root]>' with proper fragment matching
- Uses regex pattern (?:[\s\[\{\()<])([\w:]*)$ to handle delimited expressions
- Refactored handlers to use consistent early return pattern for better readability
- Added blocking behavior for unquoted contexts (sound(, scale(, bank()) to guide users toward correct syntax instead of showing irrelevant fallback completions
- Fixed soundHandler to show all sounds when fragment is empty (e.g., sound(""))
- Simplified bankHandler by removing complex quote handling logic in favor of consistent blocking pattern
- Made scale handler regex patterns consistent (removed leading dots)
- All handlers now follow same structure: block unquoted contexts, provide completions for quoted contexts