Skip to content

✨ hardware cursor positioning via text() caret#103

Draft
cowboyd wants to merge 17 commits into
mainfrom
cowboyd/text-caret
Draft

✨ hardware cursor positioning via text() caret#103
cowboyd wants to merge 17 commits into
mainfrom
cowboyd/text-caret

Conversation

@cowboyd

@cowboyd cowboyd commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds a caret?: number property to the text() directive. When declared, the renderer positions the terminal's native cursor at the code-point offset within the text and manages cursor visibility automatically across frames.

Motivation: building a text input on top of the renderer requires the terminal cursor to track the insertion point and disappear when no input is focused. The cell where the caret sits depends on the text's layout and wrapping — information the renderer already has and the caller does not.

While painting a synthetic caret is always a possibility, the native caret is almost always going to be preferable.

2026-06-30 18 14 03

Open questions

  • Clay emits no CLAY_RENDER_COMMAND_TYPE_TEXT for an empty string, so text("", { caret: 0 }) cannot resolve a cell and silently suppresses the cursor. Documented as a test that captures current behavior. The example works around this by rendering a single space when the field is empty — invisible against the input background, but the placeholder is not ideal. One possible fix is for the renderer to fall back to the caret's parent element's bounds, but unsure what the right call is.

  • There are lurking edge cases around padding and fractional cell widths. Need to dive into those before merging.

@pkg-pr-new

pkg-pr-new Bot commented Jun 30, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@bomb.sh/tty@103

commit: 49f5508

@cowboyd cowboyd changed the title ✨ feat(term): hardware cursor positioning via text() caret ✨ hardware cursor positioning via text() caret Jun 30, 2026
@cowboyd cowboyd force-pushed the cowboyd/text-caret branch 2 times, most recently from cfc0338 to 4d7b8ca Compare July 1, 2026 08:05
@codspeed-hq

codspeed-hq Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 10 untouched benchmarks


Comparing cowboyd/text-caret (49f5508) with main (35ce6a0)

Open in CodSpeed

@cowboyd cowboyd force-pushed the cowboyd/text-caret branch from 4d7b8ca to 9d23833 Compare July 2, 2026 15:29
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Size Increased — +0.4 KB

124.6 KB unpacked

cowboyd added 3 commits July 8, 2026 14:16
Adds a normative paragraph to §7.6 stating that a `caret` declaration on
empty content places the cursor at the text element's origin — the cell
where the first code point of `content` would be drawn if it were a
single space. Frames the empty-content case as a rendering commitment
the renderer must honor, without prescribing mechanism.
Substitute a single-space slice for empty text nodes carrying a caret
declaration so the layout engine emits one cell of geometry at the text
element's origin. Replaces the v1-limitation test with one asserting
the spec's outcome (CUP to row 1, col 1 + DECTCEM-show).
The `value || " "` fallback previously worked around the renderer's
inability to attach a caret to an empty text node. That case is now
handled directly by the renderer, so the example can pass the raw
value through and let the caret resolve at the input box's origin.
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