From 37cba82bfcf84a64be145fcc7ee9d69a8867dc5d Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sat, 18 Apr 2026 14:42:03 -0500 Subject: [PATCH] fix(tui): Ctrl+C on in-input selection copies to clipboard instead of clearing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: textInput explicitly ignored Ctrl+C so the app-level handler took over — with no knowledge of the TextInput's own selection — and fell through to clearIn() whenever input had text. Selecting part of the composer and pressing Ctrl+C silently nuked everything you typed. Now: Ctrl+C with an active in-input selection writes the selected substring to the clipboard via OSC 52 and clears the selection. The original semantics (Ctrl+C with no selection → app-level interrupt/clear/die chain) are preserved by still returning early in that case. --- ui-tui/src/components/textInput.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ui-tui/src/components/textInput.tsx b/ui-tui/src/components/textInput.tsx index 6503da4dbf..a0f7c42f3b 100644 --- a/ui-tui/src/components/textInput.tsx +++ b/ui-tui/src/components/textInput.tsx @@ -2,6 +2,8 @@ import type { InputEvent, Key } from '@hermes/ink' import * as Ink from '@hermes/ink' import { useEffect, useMemo, useRef, useState } from 'react' +import { writeOsc52Clipboard } from '../lib/osc52.js' + type InkExt = typeof Ink & { stringWidth: (s: string) => number useDeclaredCursor: (a: { line: number; column: number; active: boolean }) => (el: any) => void @@ -468,10 +470,22 @@ export function TextInput({ return void emitPaste({ cursor: curRef.current, hotkey: true, text: '', value: vRef.current }) } + if (k.ctrl && inp === 'c') { + const range = selRange() + + if (range) { + writeOsc52Clipboard(vRef.current.slice(range.start, range.end)) + clearSel() + + return + } + + return + } + if ( k.upArrow || k.downArrow || - (k.ctrl && inp === 'c') || k.tab || (k.shift && k.tab) || k.pageUp ||