Conversation
This feels cleaner, and makes for a better API in onRender
We *shouldn't* get other values, but if we do we fall back to 'block'
If users always use the default block shape, writing the cursor shape sequence is wasteful---and potentially a bug, if they are trying to use Cursor in an environment that does not support cursor shape sequences.
Potentially, changing shape while not visible could result in the terminal not actually updating, so we update previousCursorShape now only on when the cursor was actually active
|
I agree that Ink should support an inline cursor, and the I manually verified several correctness issues: padding is counted twice when positioning the cursor, the marker lets text escape The common problem is representing renderer state as an OSC hyperlink plus a Unicode character. Wrapping, truncation, clipping, transforms, and accessibility all process the fake character before it is extracted, so each path needs special handling. I think cursor position should remain out-of-band metadata. Either put a cursor offset on the containing Text node, as the Gemini Ink fork does, or make |
|
Thank you for the thorough review! I'll see if I can get those correctness
issues you mentioned repro'd as tests. TIL about DECSCUSR 0 for resetting
the cursor shape!
The reason I went with the hyperlink is the word wrapping can handle it
gracefully and keep the cursor aligned to the text without too much fuss.
My guess is that getting an offset-based solution to match word wrapping
will be fairly challenging, and when I tried a dedicated element I ran into
similar problems, but I can take another look.
…On Wed, Sep 16, 2026, 12:00 AM Sindre Sorhus ***@***.***> wrote:
*sindresorhus* left a comment (vadimdemedes/ink#1002)
<#1002 (comment)>
I agree that Ink should support an inline cursor, and the <Cursor /> API
makes sense for text inputs and IME. I don't think the marker-based
implementation is safe to merge yet.
I manually verified several correctness issues: padding is counted twice
when positioning the cursor, the marker lets text escape overflow="hidden",
all three truncation modes lose a visible character, and screen-reader mode
writes the internal OSC hyperlink verbatim. Cursor shape cleanup is also
incorrect: removing a shaped cursor before exit leaves that shape active,
while non-interactive output emits a reset despite never setting one.
Resetting to steady block also overrides the user's terminal default.
The common problem is representing renderer state as an OSC hyperlink plus
a Unicode character. Wrapping, truncation, clipping, transforms, and
accessibility all process the fake character before it is extracted, so
each path needs special handling.
I think cursor position should remain out-of-band metadata. Either put a
cursor offset on the containing Text node, as the Gemini Ink fork does, or
make <Cursor /> a special internal child that text flattening converts
into an offset without serializing it into the content. I would also move
cursor shape into a seperate PR, track whether Ink actually emitted a
shape, and restore DECSCUSR 0 on cleanup. The onRender addition can
probably wait as well.
—
Reply to this email directly, view it on GitHub
<#1002?email_source=notifications&email_token=AAGHIFQ5QMT55CC27YA7WGL5PIF4DA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKNRZGE4DEMRZGA32M4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KYZTPN52GK4S7MNWGSY3L#issuecomment-5691822907>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGHIFVT6GA4VGLA2OK2WS35PIF4DAVCNFSNUABEKJSXA33TNF2G64TZHM4TIMBWGEZTANZ3JFZXG5LFHM2TINRSGA3DEMRTG2QXMAQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
Think we can probably close this in favor of #1004 |
This is an alternative to #872 that also address #870 and #251.
<Cursor />renders inline within<Text />, following it naturally with Ink's word wraps. Wherever<Cursor />is rendered within the output is where Ink will place the system cursor.How
<Cursor />renders a zero-width ANSI hyperlink thatOutputdetects and extracts, so (once we upgrade to https://github.com/AlCalzone/ansi-tokenize/releases/tag/v0.3.1; wasn't sure if you'd want that package noise in this PR) there should be no leakage into the rendered content. With the extracted cursor in hand,Inksimply uses the existing cursor management to place it where it needs to be.<Cursor />also supports ashapeparam, which gets carried by the hyperlink URI, so you can declaratively set the cursor shape as well (see discussion below).Details
<Cursor />is mutually exclusive withuseCursor, enforced at runtime. In component mode, the absence of a rendered Cursor in the output means to hide the cursor, butuseCursorwill never render one in the output so clearing the component cursor would also clear any set byuseCursor. There might be a clever way to use the CursorContext to indicate toInkthat auseCursorhook is mounted, but that didn't seem worth it."block"cursor) shouldn't see any ANSI noise. It would be a little annoying to separate out perhaps, however if you like this feature but want to land them separately I could do that.cursorproperty to the params ofonRender. Not married to this API—the param name is "Metrics" so feels unintentional—but we do get the position on each render so it felt natural. I could also see a dedicatedonCursorPositionChangedcallback that does diffing and only emits if it actually changed, but that wasn't necessary for my purposes so didn't want to invest in it.cursor-ime-componentexample that also has basic cursor movement support via the arrow keys, for playing with the wrapping behavior.