Download web/src/lib/pty-composition.ts from SaylorTwift/hermes-agent: direct link, hf CLI and curl.
- Browser
- Download file 1.78 kB
-
https://huggingface.co/SaylorTwift/hermes-agent/resolve/main/web/src/lib/pty-composition.ts
- Command line
-
hf download hf://SaylorTwift/hermes-agent/web/src/lib/pty-composition.ts
-
curl -L -o pty-composition.ts https://huggingface.co/SaylorTwift/hermes-agent/resolve/main/web/src/lib/pty-composition.ts
1.78 kB
| /** | |
| * Delays an IME/dead-key commit just long enough for xterm to emit onData. | |
| * | |
| * xterm is authoritative when it emits the commit. Browsers/layouts where it | |
| * does not emit onData still forward the compositionend text on the next turn. | |
| */ | |
| export function createPtyCompositionForwarder(send: (data: string) => void) { | |
| let pending: string | null = null; | |
| let timer: ReturnType<typeof setTimeout> | null = null; | |
| let matchedTerminalPrefix = ""; | |
| let sawUnrelatedTerminalData = false; | |
| const clearPending = () => { | |
| pending = null; | |
| matchedTerminalPrefix = ""; | |
| sawUnrelatedTerminalData = false; | |
| if (timer) { | |
| clearTimeout(timer); | |
| timer = null; | |
| } | |
| }; | |
| return { | |
| onCompositionEnd(data: string | null) { | |
| if (!data) return; | |
| // Preserve rapid consecutive commits instead of discarding the first. | |
| const previous = pending; | |
| clearPending(); | |
| if (previous) send(previous); | |
| pending = data; | |
| timer = setTimeout(() => { | |
| const committed = pending; | |
| clearPending(); | |
| if (committed) send(committed); | |
| }, 16); | |
| }, | |
| noteTerminalData(data: string) { | |
| if (!pending || data.startsWith("\x1b") || sawUnrelatedTerminalData) return; | |
| // xterm may split committed text across callbacks, but only a clean, | |
| // leading match is authoritative. Once unrelated data arrives, retain | |
| // the fallback even if later callbacks happen to spell the composition. | |
| const observed = matchedTerminalPrefix + data; | |
| if (observed.startsWith(pending)) { | |
| clearPending(); | |
| } else if (pending.startsWith(observed)) { | |
| matchedTerminalPrefix = observed; | |
| } else { | |
| sawUnrelatedTerminalData = true; | |
| } | |
| }, | |
| dispose: clearPending, | |
| }; | |
| } | |