Clone this repository
For self-hosted knots, clone URLs may differ based on your setup.
When the cursor lands on a '\n' — reachable in normal Helix use by
pressing l past the last visible char of a line — the wire contract
reports cursor_start=N cursor_end=N+1 with text[N]=='\n'. My renderer
emitted <span class="cursor">\n</span> which inside <pre> renders as
a plain line break with no visible highlight glyph. Fix: when the
cursor grapheme is a line terminator, substitute a non-breaking space
inside the span for the highlight, then emit the actual newline as
plain text so the line still breaks. Same treatment for empty slice
(cursor past EOF).
Also fix insert-mode caret in the same scenario: a border-left on a
'\n' has no glyph to attach to, so switch to the caret-eof zero-width
marker when the char under the caret is a line terminator.
Rust-side regression test cursor_can_sit_on_line_terminator_after_moving_
past_last_char pins the wire contract so future rendering work can
trust that (cursor_start..cursor_end) may span exactly a '\n'.
renderSnapshot now consumes selectionStart/selectionEnd alongside
cursorStart/cursorEnd. In normal/select mode it draws a subtle
.selection tint over the body and a stronger .cursor highlight over
the block-cursor grapheme inside it — so multi-char selections (w, e, x)
finally show up visually. In insert mode it applies a border-left to
the character at cursor position (no more inline-block caret, which
disrupted the monospace grid and caused the c cursor to visually shift
a pixel). EOF caret handled separately with a zero-width span.
Fixes the two things user asked for: highlighting renders, and the c
cursor is now visually where the underlying data says it is.
primary_cursor_range now derives cursor position from Range::cursor(text) —
the same accessor helix-view's CursorCache uses — instead of raw
Range::head. After commands like c that delete a selection and enter
insert mode, Selection::ensure_invariants width-1-expands the collapsed
range, so Range::head lands one grapheme past the visual cursor. Range::
cursor accounts for that; using it fixes an off-by-1 for c specifically
and matches Helix's own render path in every mode.
New primary_selection_range returns the primary Range body
(from, to), so the frontend can draw the actual selection highlight —
previously we only exposed the cursor block, so multi-grapheme selections
(w, e, x, W, etc.) rendered as if collapsed. Snapshot gains
selectionStart / selectionEnd; the JSON-shape test lists them alongside
cursorStart / cursorEnd.
Three regression tests cover the wire contract: word_selection_reports_
selection_body_range, insert_mode_reports_zero_width_cursor_at_head, and
change_command_leaves_caret_at_start_of_deletion (the c off-by-1
reproduction).