1import { chunkTerminalWrite, encodeTerminalPaste } from "./terminalInput";
2
3interface TerminalPasteInput {
4 readonly readText: () => Promise<string>;
5 readonly write: (data: string) => Promise<boolean>;
6 readonly onReadError: (cause: unknown) => void;
7}
8
9export interface TerminalPasteSession {
10 readonly reset: (active: boolean) => void;
11 readonly paste: (input: TerminalPasteInput) => Promise<void>;
12}
13
14/** Coordinates clipboard reads and writes for the currently attached pty. */
15export function createTerminalPasteSession(): TerminalPasteSession {
16 let liveTarget: object | null = null;
17 let latestRequest = 0;
18 let writeTail: Promise<void> = Promise.resolve();
19
20 return {
21 reset(active) {
22 liveTarget = active ? {} : null;
23 },
24
25 async paste({ readText, write, onReadError }) {
26 const target = liveTarget;
27 if (target === null) {
28 return;
29 }
30 const request = ++latestRequest;
31 const isCurrent = () => liveTarget === target && latestRequest === request;
32
33 let text: string;
34 try {
35 text = await readText();
36 } catch (cause) {
37 onReadError(cause);
38 return;
39 }
40
41 if (!isCurrent()) {
42 return;
43 }
44
45 const writePaste = async () => {
46 for (const chunk of chunkTerminalWrite(encodeTerminalPaste(text))) {
47 if (!isCurrent() || !(await write(chunk))) {
48 return;
49 }
50 }
51 };
52 const queuedWrite = writeTail.then(writePaste, writePaste);
53 writeTail = queuedWrite.then(
54 () => undefined,
55 () => undefined,
56 );
57 await queuedWrite;
58 },
59 };
60}