Skip to content

fix(renderer): move the cursor when the model changes it in place - #1860

Open
awss1i wants to merge 1 commit into
charmbracelet:mainfrom
awss1i:fix/cursor-in-place
Open

awss1i wants to merge 1 commit into
charmbracelet:mainfrom
awss1i:fix/cursor-in-place

Conversation

@awss1i

@awss1i awss1i commented Oct 11, 2026

Copy link
Copy Markdown
  • I have read CONTRIBUTING.md.
  • I have created a discussion that was approved by a maintainer (for new features).

Fixes #1784

The bug

render stored the model's *Cursor as is, and flush kept that view as lastView. When a model moves the cursor it already passed in, viewEquals compares the cursor with itself, so with unchanged content the frame is skipped and the terminal cursor stays where it was. Because the renderer reads that cursor from its own goroutine, -race also reports a data race between Update and viewEquals.

Fix

Copy the cursor in render so each frame keeps its own position.

Testing

  • Added TestCursedRenderer_movesCursorChangedInPlace. It fails on main, passes with the fix, and checks that the next unchanged frame writes nothing.
  • In tmux, m.cursor.X++ over static text left the cursor at column 0 on main and now moves it one column per key press. A new cursor per frame writes the same bytes as before.
  • go test -race -count 4 -cpu 1,4 ./..., go vet ./... and golangci-lint v2.9 pass.

The renderer kept the model's *Cursor in the last rendered view, so a
cursor changed in place compared equal to itself and flush skipped the
frame. Copy the cursor in render so each frame keeps its own position.
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.

Seems a type View Update Bug

1 participant