Skip to content

fix(textarea): reach trailing wrapped cursor lines - #1051

Open
LeulTew wants to merge 1 commit into
charmbracelet:mainfrom
LeulTew:leultew-textarea-wrapped-cursor-navigation
Open

LeulTew wants to merge 1 commit into
charmbracelet:mainfrom
LeulTew:leultew-textarea-wrapped-cursor-navigation

Conversation

@LeulTew

@LeulTew LeulTew commented Sep 16, 2026

Copy link
Copy Markdown

Let Down reach the reserved cursor row after an exact-width line, so navigation no longer gets stuck. Preserve wrapping and remembered display columns.

Refs #887.

Validation limits: Windows amd64, Go 1.27.1 only. Configured lint reports 27 unchanged CRLF formatting findings (none in changed files); race checks are unavailable without CGO/a C compiler. No interactive-terminal or cross-platform validation.

Root cause and observed cursor states

The downward probe stopped at len(line)-1, so it could not reach the end-of-line cursor position on the reserved wrapped row. Allowing len(line) fixes the stall without changing wrap(), LineInfo(), or horizontal-column restoration.

Deterministic Model observations, using an effective content width of 20 with prompt and line numbers disabled. The value is 20 ASCII a characters, a newline, then abcdefghijklmnop. Positions below are zero-based (logical line, rune column):

Before: (0,7) --Down--> (0,7)  --Down--> (0,7)
After:  (0,7) --Down--> (0,20) --Down--> (1,7)
        (0,7) <--Up---- (0,20) <--Up---- (1,7)

The intermediate (0,20) is the preserved cursor-only wrapped row. The corresponding real cursor (X,Y) positions are (7,0), (0,1), and (7,2). This is captured Model behavior, not an interactive-terminal screenshot or human visual review.

Regression coverage and local validation

The new key-message test fails in six cases before the fix and passes all nine afterward. It covers exact-width lines, repeated wraps, spaces, CJK/mixed-width runes, remembered display columns, Up reversibility, and buffer boundaries. Short-line, over-width, and word-wrap controls pass before and after; existing view expectations are unchanged.

Passed with session-local Go 1.27.1, GOMAXPROCS=2, and package parallelism limited to one:

go test -mod=readonly -p=1 -count=1 -run '^TestVerticalNavigationThroughSoftWraps$' -v .\textarea
go test -mod=readonly -p=1 -count=1 .\textarea
go test -mod=readonly -p=1 -count=1 .\...
go build -mod=readonly -p=1 .\...
go vet -mod=readonly -p=1 .\...

gofmt -l reports no changes for either modified file. The pinned golangci-lint v2.13.1 run used the existing config and one worker; all 27 reported files match the base and have CRLF checkout line endings. No lint exclusions, unrelated formatting changes, or dependency changes were made.

  • I have read CONTRIBUTING.md.
  • I have created a discussion that was approved by a maintainer (for new features). N/A: bug fix.

Allow downward navigation to reach the end-of-line cursor position instead of clamping to the last rune. This makes the reserved cursor row reachable for exact-width content without changing wrapping or remembered display columns.

Add key-message regressions for exact-width, short, overflowing, word-wrapped, spaced, and wide-rune content, including reverse navigation and buffer boundaries.

Refs charmbracelet#887.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant