opentui(copy): theme the selection highlight

Apply the existing theme selectionBg token to the plain <text> content
renderables (TextBufferRenderable supports selectionBg/selectionFg) so a
selection draws a clean solid bar that PRESERVES the text fg (no selectionFg →
no SGR-inverse fragmenting). Applied to:
- messageLine: the flat settled/user/system message text.
- toolPart: the args value lines + the output body lines.
Limitation: assistant answers rendered via the native <markdown> renderable
(MarkdownRenderable extends Renderable, not TextBufferRenderable, and
MarkdownOptions has no selectionBg/selectionFg) cannot take the themed highlight
— they fall back to the renderer's default selection style.
This commit is contained in:
alt-glitch 2026-06-09 07:19:39 +00:00
parent 60c5a82c85
commit 76e9271dce
2 changed files with 9 additions and 4 deletions

View file

@ -56,7 +56,10 @@ export function MessageLine(props: { message: Message }) {
<Show
when={m().streaming && !hasParts()}
fallback={
<text>
// themed selection: a solid muted/accent bar that preserves the
// text fg (no selectionFg → the original color shows through, so a
// highlight over content reads as a clean bar, not SGR-inverse).
<text selectionBg={theme().color.selectionBg}>
<span style={{ fg: bodyFg() }}>{m().text}</span>
</text>
}

View file

@ -148,7 +148,7 @@ export function ToolPart(props: { part: ToolPartState }) {
fallback={
<For each={(props.part.argsText ?? '').split('\n').slice(0, ARGS_MAX)}>
{line => (
<text>
<text selectionBg={theme().color.selectionBg}>
<span style={{ fg: theme().color.muted }}>{truncate(line, bodyWidth() - 2)}</span>
</text>
)}
@ -157,7 +157,7 @@ export function ToolPart(props: { part: ToolPartState }) {
>
<For each={argEntries().slice(0, ARGS_MAX)}>
{([k, v]) => (
<text>
<text selectionBg={theme().color.selectionBg}>
<span style={{ fg: theme().color.muted }}>{truncate(argLine(k, v), bodyWidth() - 2)}</span>
</text>
)}
@ -176,9 +176,11 @@ export function ToolPart(props: { part: ToolPartState }) {
<span style={{ fg: theme().color.label }}>output</span>
</text>
</Show>
{/* output body lines are the copyable content themed selection bar
(preserves fg; same token as message text) (item: theme highlight). */}
<For each={body().lines}>
{line => (
<text>
<text selectionBg={theme().color.selectionBg}>
<span style={{ fg: theme().color.muted }}>{line}</span>
</text>
)}