A typescript embedable helix-editor clone.
  • TypeScript 97%
  • JavaScript 2.5%
  • HTML 0.4%
Find a file
Théophile Gervreau-Mercier 8192fe5add Fix x (line selection) to extend to multiple lines
Fixed selectLine to work with inclusive range model:

Issues fixed:
1. Detection of "already selecting full line" was broken with new rangeEnd()
2. Now correctly detects when we're selecting full lines
3. Extends to next line on subsequent x presses

Logic:
- First x: select current line from column 0 to last column
  Example: "hello" → range(0, 4), cursor at 4
- Second x: detect full line selection, extend to next line
  Example: "hello" + "world" → range(0, 10), cursor at 10
- Handles empty lines (length 0) correctly

Detection criteria:
- Start at column 0
- Head at last column of line (or column 0 for empty lines)
- This indicates a full line is selected

Now x can be pressed repeatedly to select multiple lines.
2026-02-08 17:00:40 +01:00
src Fix x (line selection) to extend to multiple lines 2026-02-08 17:00:40 +01:00
tests WIP: Change to inclusive range model (Helix-style) 2026-02-08 16:58:30 +01:00
.eslintrc.cjs Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
.gitignore Fix word motion semantics to match Helix behavior 2026-02-08 16:58:30 +01:00
.prettierrc Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
FEATURE_PARITY.md Fix word motion semantics to match Helix behavior 2026-02-08 16:58:30 +01:00
index.html Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
LICENSE Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
package.json Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
pnpm-lock.yaml Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
README.md Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
shell.nix Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
test-actual-positions.js WIP: Change to inclusive range model (Helix-style) 2026-02-08 16:58:30 +01:00
test-word-motion.js Fix word motion semantics to match Helix behavior 2026-02-08 16:58:30 +01:00
TEST_FAILURES_SUMMARY.md Fix x (line selection) to extend to multiple lines 2026-02-08 17:00:40 +01:00
TEST_RESULTS.md Fix word motion semantics to match Helix behavior 2026-02-08 16:58:30 +01:00
tsconfig.json Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
vite.config.ts Fix selection ranges for w/e/W/E word movements 2026-02-08 16:58:30 +01:00
WORD_MOTION_FIX_FINAL.md Fix word motion semantics to match Helix behavior 2026-02-08 16:58:30 +01:00
WORD_MOTION_FIXES.md Fix word motion semantics to match Helix behavior 2026-02-08 16:58:30 +01:00

Spiral Editor

A Helix-style modal editor for the browser, built with TypeScript.

Features

  • Selection-first editing - Like Helix, selections are primary
  • Modal editing - Normal, Insert, and Select modes
  • Multiple cursors - Full multi-selection support
  • Pure state - Editor state is immutable and serializable
  • No contenteditable - Clean DOM-based rendering

Quick Start

pnpm install
pnpm dev

Open http://localhost:3000

Key Bindings

Movement (Normal Mode)

Key Action
h/j/k/l Move cursor left/down/up/right
w Select next word
b Select previous word
e Select to end of word
W Select next WORD (whitespace-separated)
B Select previous WORD
E Select to end of WORD
H/K/L Extend selection left/up/right by character
g h Go to line start
g l Go to line end
g g Go to document start
g e Go to document end
0 / $ Go to line start / end
Ctrl+u Half page up (with 5-line scrolloff)
Ctrl+d Half page down (with 5-line scrolloff)
PageUp/PageDown Full page scroll (with scrolloff)

Select Mode (v)

In select mode, all movement commands extend the selection instead of moving it.

Key Action
h/j/k/l Extend selection left/down/up/right
w/b/e Extend by word
W/B/E Extend by WORD
Any movement Extends the selection

Mode Switching

Key Action
i Insert mode (before cursor)
a Insert mode (after cursor)
I Insert at line start (first non-space)
A Insert at line end
v Select mode
Esc Return to normal mode

Selection

Key Action
x Select line
X Extend selection to full lines
% Select all
; Collapse selection to cursor
m Select matching bracket pair

Editing

Key Action
d Delete selection
c Change selection (delete + insert)
y Yank (copy) selection
p Paste
o Open line below
O Open line above
J Join lines
~ Toggle case
D Delete to line end
C Change to line end
> / < Indent / dedent
Ctrl+z Undo
Ctrl+Shift+z Redo

Insert Mode

Key Action
Esc Return to normal mode
Backspace Delete character before
Delete Delete character after
Enter New line
Tab Insert spaces
Arrow keys Move cursor

Architecture

src/
├── core/           # Data models (Document, Selection, State)
├── commands/       # Pure state transformations
├── keybindings/    # Key handling and mapping
├── view/           # DOM rendering
└── editor.ts       # Main orchestrator

Design Principles

  1. Editor state is pure data - No DOM references in state
  2. Rendering is a projection - View derives from state
  3. All edits go through commands - Pure functions: State → State
  4. Selections are first-class - Always at least one selection
  5. Deterministic state transitions - Same input → same output

Development

pnpm dev      # Start dev server
pnpm build    # Build for production
pnpm test     # Run tests
pnpm lint     # Lint code

License

MIT