From 13680808c7204fac27a358e76b5b459dc47d7c1e Mon Sep 17 00:00:00 2001 From: Nowaker Date: Sat, 10 Oct 2026 21:11:44 -0500 Subject: [PATCH 1/2] fix(tui): delete a paste placeholder whole on word and line deletes ctrl+w (or alt+backspace) right after a "[Pasted ~5 lines]" placeholder deleted only the last word of its label, leaving "[Pasted ~5 " behind with the pasted text detached from it; ctrl+u and ctrl+k did the same when the line edge cut into a placeholder. Backspace and delete already removed it whole. The cause is in @opentui/core: its extmark controller's deleteRange, which every word and line delete goes through, trimmed a virtual extmark instead of treating it as one unit. The fix is upstream as anomalyco/opentui#1628; patches/@opentui%2Fcore@0.4.5.patch backports it to the pinned 0.4.5 until a release with it is adopted. deleteRange now widens its range over every virtual extmark it cuts into. --- bun.lock | 1 + package.json | 3 +- .../prompt-placeholder-delete.test.tsx | 64 +++++++++++++++++ patches/@opentui%2Fcore@0.4.5.patch | 72 +++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 packages/tui/test/component/prompt-placeholder-delete.test.tsx create mode 100644 patches/@opentui%2Fcore@0.4.5.patch diff --git a/bun.lock b/bun.lock index 6404fce15419..5b9a1fcb34ce 100644 --- a/bun.lock +++ b/bun.lock @@ -1070,6 +1070,7 @@ "@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch", "@ai-sdk/amazon-bedrock@4.0.166": "patches/@ai-sdk%2Famazon-bedrock@4.0.166.patch", "@ai-sdk/groq@3.0.31": "patches/@ai-sdk%2Fgroq@3.0.31.patch", + "@opentui/core@0.4.5": "patches/@opentui%2Fcore@0.4.5.patch", "@ai-sdk/xai@3.0.139": "patches/@ai-sdk%2Fxai@3.0.139.patch", "@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch", "pacote@21.5.0": "patches/pacote@21.5.0.patch", diff --git a/package.json b/package.json index 003e39a89fce..7eb9c166f649 100644 --- a/package.json +++ b/package.json @@ -164,6 +164,7 @@ "@ai-sdk/groq@3.0.31": "patches/@ai-sdk%2Fgroq@3.0.31.patch", "@ai-sdk/anthropic@3.0.111": "patches/@ai-sdk%2Fanthropic@3.0.111.patch", "@ai-sdk/amazon-bedrock@4.0.166": "patches/@ai-sdk%2Famazon-bedrock@4.0.166.patch", - "@ai-sdk/openai@3.0.88": "patches/@ai-sdk%2Fopenai@3.0.88.patch" + "@ai-sdk/openai@3.0.88": "patches/@ai-sdk%2Fopenai@3.0.88.patch", + "@opentui/core@0.4.5": "patches/@opentui%2Fcore@0.4.5.patch" } } diff --git a/packages/tui/test/component/prompt-placeholder-delete.test.tsx b/packages/tui/test/component/prompt-placeholder-delete.test.tsx new file mode 100644 index 000000000000..01d6bc7d1219 --- /dev/null +++ b/packages/tui/test/component/prompt-placeholder-delete.test.tsx @@ -0,0 +1,64 @@ +/** @jsxImportSource @opentui/solid */ +import { afterAll, beforeAll, describe, expect, test } from "bun:test" +import type { TextareaRenderable } from "@opentui/core" +import { testRender } from "@opentui/solid" + +// The prompt marks a paste placeholder with a virtual extmark. Word and line deletes go +// through deleteRange, which @opentui/core 0.4.5 is patched to widen over a virtual +// extmark it cuts into (anomalyco/opentui#1628). +const placeholder = "[Pasted ~5 lines]" +const text = `see ${placeholder} x` +const start = "see ".length +const end = start + placeholder.length + +let app: Awaited> +let input: TextareaRenderable + +beforeAll(async () => { + const textarea = Promise.withResolvers() + app = await testRender( + () => ( + +