Keep SSH typing replies inside narrow split terminal panes (#24682)

This commit is contained in:
Neil
2026-10-02 02:39:34 -07:00
committed by GitHub
parent 66799f7e8f
commit d9fbb4eecf
3 changed files with 23 additions and 10 deletions
@@ -15,7 +15,7 @@ export function remoteTypingLoadScript(runId: string): string {
' for (const char of chunk) {',
" if (char === '\\r' || char === '\\n') continue",
' seq += 1',
` process.stdout.write('\\x1b[' + statusRow + ';2H\\x1b[2KREMOTE_KEY_${runId}_' + seq + '_' + char)`,
` process.stdout.write('\\x1b[' + statusRow + ';2H\\x1b[2KKEY_${runId}_' + seq + '_' + char)`,
' }',
'})'
].join(';')
@@ -2,20 +2,31 @@ import '../../../src/main/daemon/xterm-env-polyfill'
import { EventEmitter } from 'node:events'
import { runInNewContext } from 'node:vm'
import { Terminal } from '@xterm/headless'
import { SerializeAddon } from '@xterm/addon-serialize'
import { expect, it } from 'vitest'
import { remoteTypingLoadScript } from './remote-typing-load-script'
it.each([12, 24, 40])(
'keeps typed output visible through background pressure at %i rows',
async (rows) => {
const terminal = new Terminal({ rows, cols: 80, scrollback: 1000, allowProposedApi: true })
it.each([
{ rows: 12, cols: 80 },
{ rows: 24, cols: 80 },
{ rows: 40, cols: 80 },
{ rows: 12, cols: 35 },
{ rows: 24, cols: 35 },
{ rows: 40, cols: 35 }
])(
'keeps typed output visible through background pressure at $rows rows and $cols columns',
async ({ rows, cols }) => {
const terminal = new Terminal({ rows, cols, scrollback: 1000, allowProposedApi: true })
const serializer = new SerializeAddon()
terminal.loadAddon(serializer)
const runId = cols === 80 ? 'test' : '1790930671681_active'
const input = new EventEmitter()
const chunks: string[] = []
let background = (): void => {
throw new Error('Background pressure did not start')
}
try {
runInNewContext(remoteTypingLoadScript('test'), {
runInNewContext(remoteTypingLoadScript(runId), {
process: {
stdin: {
isTTY: true,
@@ -24,7 +35,7 @@ it.each([12, 24, 40])(
resume() {},
on: input.on.bind(input)
},
stdout: { rows, write: (chunk: string) => chunks.push(chunk) },
stdout: { rows, cols, write: (chunk: string) => chunks.push(chunk) },
exit() {}
},
setTimeout: (callback: () => void) => callback(),
@@ -34,7 +45,7 @@ it.each([12, 24, 40])(
},
clearInterval() {}
})
input.emit('data', 'ab\r\ncd')
input.emit('data', cols === 80 ? 'ab\r\ncd' : 'abcdefghij\r\n')
for (let frame = 0; frame < 40; frame += 1) {
background()
}
@@ -48,7 +59,9 @@ it.each([12, 24, 40])(
.getLine(terminal.buffer.active.baseY + row)
?.translateToString(true) ?? ''
).join('\n')
expect(screen).toContain('REMOTE_KEY_test_4_d')
const reply = cols === 80 ? 'KEY_test_4_d' : `KEY_${runId}_10_j`
expect(screen).toContain(reply)
expect(serializer.serialize()).toContain(reply)
} finally {
terminal.dispose()
}
+1 -1
View File
@@ -86,7 +86,7 @@ async function measureRemoteTyping(
const latencies: number[] = []
for (let index = 0; index < KEY_LATENCY_SAMPLES.length; index += 1) {
const char = KEY_LATENCY_SAMPLES[index]
const marker = `REMOTE_KEY_${runId}_${index + 1}_${char}`
const marker = `KEY_${runId}_${index + 1}_${char}`
const started = performance.now()
await page.evaluate(({ ptyId, char }) => window.api.pty.write(ptyId, char, 'driving'), {
ptyId,