diff --git a/packages/app/src/components/terminal-emulator.tsx b/packages/app/src/components/terminal-emulator.tsx index 094ec9198..285c5aa65 100644 --- a/packages/app/src/components/terminal-emulator.tsx +++ b/packages/app/src/components/terminal-emulator.tsx @@ -24,6 +24,7 @@ import { TerminalEmulatorRuntime, type TerminalOutputData, } from "../terminal/runtime/terminal-emulator-runtime"; +import { encodeTerminalPaste } from "../terminal/runtime/terminal-paste"; import type { TerminalLocalFileLinkSource, TerminalLocalFileLinkTarget, @@ -303,6 +304,18 @@ export default function TerminalEmulator({ const dropActiveTimeoutRef = useRef | null>(null); const domBridgeRef = useRef(null); + const pasteText = useCallback((text: string) => { + if (text.length === 0) { + return; + } + mountCallbacksRef.current.onInput?.( + encodeTerminalPaste({ + text, + bracketedPaste: runtimeRef.current?.getInputModeState().bracketedPaste ?? false, + }), + ); + }, []); + useDOMImperativeHandle( domBridgeRef, (): DOMImperativeFactory => ({ @@ -325,7 +338,7 @@ export default function TerminalEmulator({ paste: (...args) => { const text = args[0]; if (typeof text === "string" && text.length > 0) { - mountCallbacksRef.current.onInput?.(text); + pasteText(text); } }, copySelection: async () => "", @@ -340,7 +353,7 @@ export default function TerminalEmulator({ runtimeRef.current?.blur(); }, }), - [], + [pasteText], ); useImperativeHandle( ref, @@ -355,9 +368,7 @@ export default function TerminalEmulator({ runtimeRef.current?.renderSnapshot({ state }); }, paste: (text: string) => { - if (text.length > 0) { - mountCallbacksRef.current.onInput?.(text); - } + pasteText(text); }, copySelection: async () => "", clear: () => { @@ -371,7 +382,7 @@ export default function TerminalEmulator({ runtimeRef.current?.blur(); }, }), - [], + [pasteText], ); useEffect(() => { diff --git a/packages/app/src/components/terminal-pane.tsx b/packages/app/src/components/terminal-pane.tsx index 185278b83..6599c3367 100644 --- a/packages/app/src/components/terminal-pane.tsx +++ b/packages/app/src/components/terminal-pane.tsx @@ -810,9 +810,10 @@ export function TerminalPane({ const toggleModifier = useCallback( (modifier: keyof ModifierState) => { setModifiers((current) => ({ ...current, [modifier]: !current[modifier] })); + requestTerminalFocus(); requestTerminalReflow(); }, - [requestTerminalReflow], + [requestTerminalFocus, requestTerminalReflow], ); const sendVirtualKey = useCallback( @@ -825,6 +826,7 @@ export function TerminalPane({ meta: false, }); clearPendingModifiers(); + requestTerminalFocus(); requestTerminalReflow(); }, [ @@ -832,6 +834,7 @@ export function TerminalPane({ modifiers.alt, modifiers.ctrl, modifiers.shift, + requestTerminalFocus, requestTerminalReflow, sendTerminalKey, ], diff --git a/packages/app/src/terminal/runtime/terminal-emulator-runtime.test.ts b/packages/app/src/terminal/runtime/terminal-emulator-runtime.test.ts index f4bb97b72..003813290 100644 --- a/packages/app/src/terminal/runtime/terminal-emulator-runtime.test.ts +++ b/packages/app/src/terminal/runtime/terminal-emulator-runtime.test.ts @@ -308,6 +308,16 @@ describe("terminal-emulator-runtime", () => { ]); }); + it("exposes the tracked input mode state", () => { + const { runtime } = createRuntimeWithTerminal(); + + runtime.write({ data: terminalOutput("\x1b[?2004h") }); + + expect(runtime.getInputModeState()).toMatchObject({ + bracketedPaste: true, + }); + }); + it("commits each drained plain write through its own xterm callback", () => { const { runtime, writeTexts, writeCallbacks } = createRuntimeWithTerminal(); const committed: string[] = []; diff --git a/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts b/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts index 07fecd23e..1eebd957b 100644 --- a/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts +++ b/packages/app/src/terminal/runtime/terminal-emulator-runtime.ts @@ -210,6 +210,10 @@ export class TerminalEmulatorRuntime { this.pendingModifiers = input.pendingModifiers; } + getInputModeState(): TerminalInputModeState { + return this.inputModeTracker.getState(); + } + mount(input: TerminalEmulatorRuntimeMountInput): void { this.unmount(); diff --git a/packages/app/src/terminal/webview/terminal-emulator-webview-html.ts b/packages/app/src/terminal/webview/terminal-emulator-webview-html.ts index 4e6b219d5..fd5fe5fae 100644 --- a/packages/app/src/terminal/webview/terminal-emulator-webview-html.ts +++ b/packages/app/src/terminal/webview/terminal-emulator-webview-html.ts @@ -2,4 +2,4 @@ // Do not edit by hand. export const terminalEmulatorWebViewHtml = - '\n\n \n \n \n \n \n \n \n'; + '\n\n \n \n \n \n \n \n \n';