reedline icon indicating copy to clipboard operation
reedline copied to clipboard

Feature: Helix mode

Open schlich opened this issue 2 months ago • 8 comments

Add Helix keybinding mode

Summary

This PR adds a new Helix-style modal editing mode to Reedline, providing an alternative to the existing Vi and Emacs modes. Helix mode implements selection-extends-on-motion (Helix's signature feature) along with character/word/line motions, find/till motions, select mode toggle, and editing commands.

This is a purely additive change with zero impact on existing functionality. The implementation follows the same architectural patterns as Vi and Emacs modes, integrating cleanly into the existing EditMode trait system.

Features

Normal Mode (default starting mode)

Mode switching:

  • v - Toggle select mode
  • i/a/I/A - Enter insert at cursor/after/line start/line end

Character motions (extend selection):

  • h/l - Move left/right with selection

Word motions (extend selection):

  • w - Next word start
  • b - Previous word start
  • e - Word end
  • W - Next WORD start (whitespace-delimited)
  • B - Previous WORD start
  • E - WORD end

Line motions (extend selection):

  • 0 - Line start
  • $ - Line end

Find/till motions (extend selection):

  • f{char} - Find next occurrence of character
  • t{char} - Till next occurrence (stop before)
  • F{char} - Find previous occurrence
  • T{char} - Till previous occurrence (stop after)

Selection commands:

  • x - Select entire line
  • ; - Collapse selection to cursor
  • Alt+; - Swap cursor and anchor (flip selection)

Edit commands:

  • d - Delete selection
  • c - Change selection (delete and enter insert)
  • y - Yank/copy selection
  • p - Paste after cursor
  • P - Paste before cursor

Other:

  • Enter - Accept/submit line
  • Ctrl+C/Ctrl+D - Exit/abort

Select Mode

  • v or Esc - Exit select mode (clear selection)
  • All motion keys work the same as Normal mode
  • i/a/I/A - Exit select and enter insert mode
  • d/c/y/p - Edit commands work the same

Insert Mode

  • All printable characters - Insert text
  • Esc - Return to normal mode (cursor moves left, vi-style)
  • Backspace - Delete previous character
  • Enter - Accept/submit line
  • Ctrl+C/Ctrl+D - Exit/abort

Motivation

  • Provide Helix-style modal editing for users who prefer that workflow
  • Demonstrate Helix's "selection-first" paradigm is viable in a line editor context
  • Expand Reedline's modal editing options without disrupting existing modes
  • Provide a foundation for future Helix features (multi-cursor, text objects, etc.)

Impact on Codebase

Architectural Integration

The implementation follows Reedline's established patterns:

  1. EditMode trait - Helix implements the same EditMode trait as Vi and Emacs, ensuring consistent integration with the line editor engine
  2. Module structure - Mirrors src/edit_mode/vi/ organization with separate keybindings and mode logic
  3. Keybindings system - Uses existing Keybindings infrastructure for customization
  4. Prompt system - Extends PromptViMode enum with Select variant for proper mode display

Code Organization

src/edit_mode/
├── helix/              # New module (self-contained)
│   ├── mod.rs         # Main implementation (~786 lines)
│   └── helix_keybindings.rs  # Default bindings (~190 lines)
├── vi/                # Unchanged
├── emacs/             # Unchanged
└── mod.rs             # Updated to export helix module

src/prompt/
├── base.rs            # Added PromptViMode::Select variant
└── default.rs         # Added default select mode prompt indicator

src/lib.rs             # Updated to export helix types
examples/helix_mode.rs # New example (~127 lines)
HELIX_MODE.md          # Comprehensive documentation (~181 lines)

No changes to:

  • Core editor (src/core_editor/)
  • Engine (src/engine.rs)
  • Painting/rendering (src/painting/)
  • History, completion, validation, or menu systems
  • Existing Vi or Emacs modes

API Surface

New public exports (non-breaking additions):

  • reedline::Helix - The edit mode struct
  • reedline::default_helix_normal_keybindings() - Default normal mode bindings
  • reedline::default_helix_insert_keybindings() - Default insert mode bindings
  • reedline::PromptViMode::Select - New variant for select mode display

Usage pattern matches existing modes:

// Same pattern as Vi/Emacs
let helix_mode = Box::new(Helix::default());
let editor = Reedline::create().with_edit_mode(helix_mode);

Compatibility Notes

For Application Developers

If you're currently using Reedline:

  • No action required - your code continues to work exactly as before
  • To adopt Helix mode - simply swap your EditMode:
    // Before
    let editor = Reedline::create().with_edit_mode(Box::new(Vi::default()));
    
    // After  
    let editor = Reedline::create().with_edit_mode(Box::new(Helix::default()));
    
  • If you implement custom Prompt - you may need to add a match arm for PromptViMode::Select

AI Assistance Disclosure

This PR was developed with assistance from OpenCode using Claude Sonnet 4.5. The AI helped with:

  • Initial implementation structure and architecture
  • Iterative refactoring to improve code quality
  • Test coverage and edge case identification
  • Documentation and PR summary writing

All code has been reviewed and validated by the human contributor.

schlich avatar Oct 10 '25 22:10 schlich