You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
vi mode: j/k onto a shorter line park the cursor one past the last char, so x deletes the newline and joins lines #2442
Found while continuing the vi "Vim compatibility motions" sweep on master v0.4.1 (built from origin/master @ 3b8c2eca1). Reference: Vim (cursor cannot rest past the last character in NORMAL mode; vertical motion clamps the cursor to the last char of a shorter line and remembers the desired column).
When you move down/up (j/k) from a long line onto a shorter line whose length is less than the current/desired column, Fresh's vi mode parks the cursor one column past the last character (the insert position), instead of clamping it to the last character. Because the cursor is then sitting on the line-ending boundary, pressing x deletes the newline and joins the following line — silent corruption from an ordinary navigate-then-delete.
Steps to reproduce
Create a file whose first lines are a long line followed by a short line, e.g.:
hello world foo bar baz
short
a longer line with many words here
Open it: fresh --no-restore motions.txt.
Enable vi mode: Ctrl+P → "Toggle Vi mode" → Enter.
On line 1, press $ (cursor to the last char z, col 23 — correct).
Press j to move down onto line 2 (short, 5 chars).
Press x.
(Also reproduces without $: from line 1 col 10 — e.g. nine l presses — then j onto short; and upward with k from line 3 onto short.)
Expected behavior (Vim)
After $ then j, the cursor lands on the last char of short (the t, col 5) — Vim clamps a too-large desired column to the last character and never lets the cursor rest past it in NORMAL mode. x then deletes the t, giving shor. x in NORMAL can never delete a newline / join lines.
Actual behavior
After $/j (or any j/k onto the shorter line), the status bar shows Ln 2, Col 6 — i.e. column len+1 on a 5-character line, past the last char. Pressing x then deletes the line-ending newline and joins line 3 onto line 2:
short + a longer line with many words here → shorta longer line with many words here
Reproduced 3/3: via $+j, via l-to-col-10 + j, and via k from line 3 — all land on Col 6 and all join lines on x.
This is specific to vertical motion. Horizontal clamping is correct: pressing $ directly on short lands on Col 5 (the t) and x gives shor (no join); l also stops at the last char. So the column-clamp logic for j/k is off by one relative to $/l.
Workaround
After moving vertically onto a shorter line, press $ (or 0) to re-anchor the cursor onto a real character before using x; or use dl/X carefully. To merge lines deliberately, use J.
Search queries used (no existing issue): vi cursor past end of line j k shorter, vi mode cursor end of line clamp, vi mode cursor end of line.
Filed by the automated black-box TUI QA agent (Run #44).
Confirmed fixed in v0.4.3 built from origin/master @ 4e945b494 (fix commit 4e945b494 "fix(vi): clamp j/k onto a shorter line to its last character").
Re-ran the original repro black-box through the UI:
$ on a longer first line here (Col 24) then j onto short → cursor now lands at Ln 2, Col 5 (was Col 6), and x deletes t → shor — the newline is no longer deleted, no line join.
Col 10 on line 1 then j → clamps to Col 5 on short; continuing j to line 3 restores the goal column (Col 10), matching Vim's desired-column behavior.
k from line 3 onto short → Col 5, and x → shor, line 1 untouched.
3/3 original failure paths pass. Thanks for the fix!
Activity
Run #44: vi-mode sweep — find-char broken w/ operators (#2441) + j/k …
fix(vi): clamp j/k onto a shorter line to its last character (#2442)
sinelaw commentedon Jul 7, 2026
Confirmed fixed in v0.4.3 built from
origin/master@4e945b494(fix commit4e945b494"fix(vi): clamp j/k onto a shorter line to its last character").Re-ran the original repro black-box through the UI:
$ona longer first line here(Col 24) thenjontoshort→ cursor now lands at Ln 2, Col 5 (was Col 6), andxdeletest→shor— the newline is no longer deleted, no line join.j→ clamps to Col 5 onshort; continuingjto line 3 restores the goal column (Col 10), matching Vim's desired-column behavior.kfrom line 3 ontoshort→ Col 5, andx→shor, line 1 untouched.3/3 original failure paths pass. Thanks for the fix!
Generated by Claude Code
Run #50: #2442 confirmed fixed; GLSL/HLSL/WGSL/Slang grammars pass; F…