reedline icon indicating copy to clipboard operation
reedline copied to clipboard

Feature: Helix mode

Open schlich opened this issue 3 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

whoa. helix mode sounds cool. thanks. this will be interesting to play around with.

fdncred avatar Oct 10 '25 22:10 fdncred

the ci needs to be green to proceed. i think these are just formatting cargo fmt --all

fdncred avatar Oct 11 '25 12:10 fdncred

The manual test sequence is helpful for those who don't use helix. However, on my mac, it doesn't work precisely as you've laid out in those bullets. I'm not sure if they're just wrong or if it's a bug.

fdncred avatar Oct 11 '25 14:10 fdncred

I'll check it out! I've def been testing on windows layout so it's likely something I missed. That documentation there also might have gotten out of sequence in editing too. Good reminder to make sure the keyboard layout is consistent either way

schlich avatar Oct 11 '25 23:10 schlich

@fdncred if you want to kick off CI again, i was able to fix a few bugs and think it's working pretty smoothly, ran cargo test and cargo fmt --all locally, hopefully it will pass this time, not sure how the spell checker works though

schlich avatar Oct 12 '25 23:10 schlich

This is getting pretty close to complete w/comprehensive tests for the commands listed, but i'm gonna mark this as draft temporarily since i want to try to reconcile upstream Helix's architecture a little more closely with reedline's interface... hopefully it will reduce the footprint of this PR.

schlich avatar Oct 23 '25 06:10 schlich

Are you planning on moving forward with this at all? I'd be willing to help, although my rust knowledge is very limited.

freepicheep avatar Dec 01 '25 20:12 freepicheep

Hi, I am although I haven't had too much free time for open source lately. If youd like to pick it up I think right now it would just be helpful to try the demo and double check feature parity. I'm a total rust noob too so any refactoring that's more rust-idiomatic or reduces the size of the PR would definitely be welcome. Let me know if there's anything else I can help with, I'm gonna try to use some of the holiday season to catch up on things

schlich avatar Dec 01 '25 23:12 schlich