feat(simulation): record viewport resizes (#36306)
This commit is contained in:
parent
6216dbae15
commit
be18f22842
8 changed files with 90 additions and 11 deletions
|
|
@ -14,6 +14,7 @@ export interface Harness {
|
|||
readonly renderer: CliRenderer
|
||||
readonly mockInput: MockInput
|
||||
readonly mockMouse: MockMouse
|
||||
readonly resize: (cols: number, rows: number) => void
|
||||
readonly renderOnce: () => Promise<void>
|
||||
readonly screen: () => string
|
||||
}
|
||||
|
|
@ -61,15 +62,20 @@ export function createHarness(renderer: CliRenderer): Harness {
|
|||
renderer,
|
||||
mockInput: setup?.mockInput ?? createMockKeys(renderer),
|
||||
mockMouse: setup?.mockMouse ?? createMockMouse(renderer),
|
||||
resize: setup?.resize ?? ((cols, rows) => renderer.resize(cols, rows)),
|
||||
renderOnce:
|
||||
setup?.renderOnce ??
|
||||
(async () => {
|
||||
renderer.requestRender()
|
||||
await renderer.idle()
|
||||
}),
|
||||
screen:
|
||||
setup?.captureCharFrame ??
|
||||
(() => decoder.decode((Reflect.get(renderer, "currentRenderBuffer") as RenderBuffer).getRealCharBytes(true))),
|
||||
// captureCharFrame follows the test renderer's output sink. Recording
|
||||
// redirects that sink to the timeline, so read the live render buffer
|
||||
// instead; it is also the source used by screenshots.
|
||||
screen: () =>
|
||||
decoder.decode(
|
||||
(Reflect.get(renderer, "currentRenderBuffer") as RenderBuffer).getRealCharBytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,6 +157,13 @@ export async function execute(harness: Harness, action: Action) {
|
|||
case "ui.click":
|
||||
await harness.mockMouse.click(action.x, action.y)
|
||||
break
|
||||
case "ui.resize":
|
||||
if (!Number.isSafeInteger(action.cols) || action.cols <= 0 || !Number.isSafeInteger(action.rows) || action.rows <= 0) {
|
||||
throw new Error("resize cols and rows must be positive integers")
|
||||
}
|
||||
harness.resize(action.cols, action.rows)
|
||||
SimulationRenderer.recordResize(harness.renderer, action.cols, action.rows)
|
||||
break
|
||||
}
|
||||
await harness.renderOnce()
|
||||
return state(harness)
|
||||
|
|
|
|||
|
|
@ -11,21 +11,28 @@ const recordings = new WeakMap<CliRenderer, Timeline>()
|
|||
* module-side so the harness can use supported testing APIs without app
|
||||
* code carrying it around.
|
||||
*/
|
||||
export async function create(options: CliRendererConfig, path?: string): Promise<CliRenderer> {
|
||||
export interface Viewport {
|
||||
readonly cols: number
|
||||
readonly rows: number
|
||||
}
|
||||
|
||||
export async function create(options: CliRendererConfig, path?: string, viewport?: Viewport): Promise<CliRenderer> {
|
||||
const cols = viewport?.cols ?? 100
|
||||
const rows = viewport?.rows ?? 40
|
||||
if (!path) {
|
||||
const setup = await createTestRenderer({
|
||||
...options,
|
||||
width: 100,
|
||||
height: 40,
|
||||
width: cols,
|
||||
height: rows,
|
||||
})
|
||||
setups.set(setup.renderer, setup)
|
||||
return setup.renderer
|
||||
}
|
||||
const recording = await Timeline.create(path, 100, 40)
|
||||
const recording = await Timeline.create(path, cols, rows)
|
||||
const setup = await createTestRenderer({
|
||||
...options,
|
||||
width: 100,
|
||||
height: 40,
|
||||
width: cols,
|
||||
height: rows,
|
||||
stdout: recording as unknown as NodeJS.WriteStream,
|
||||
bufferedOutput: "stdout",
|
||||
onDestroy: () => {
|
||||
|
|
@ -41,6 +48,10 @@ export async function create(options: CliRendererConfig, path?: string): Promise
|
|||
return setup.renderer
|
||||
}
|
||||
|
||||
export function recordResize(renderer: CliRenderer, cols: number, rows: number) {
|
||||
recordings.get(renderer)?.resize(cols, rows)
|
||||
}
|
||||
|
||||
export function setupFor(renderer: CliRenderer): TestRendererSetup | undefined {
|
||||
return setups.get(renderer)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ async function handle(
|
|||
x: request.params.x,
|
||||
y: request.params.y,
|
||||
})
|
||||
case "ui.resize":
|
||||
return SimulationActions.execute(harness, { type: "ui.resize", cols: request.params.cols, rows: request.params.rows })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ export async function create(options: CliRendererConfig): Promise<CliRenderer> {
|
|||
const headless = process.env.OPENCODE_DRIVE_RENDERER === "headless"
|
||||
const manifest = DriveManifest.resolve()
|
||||
const renderer = headless
|
||||
? await SimulationRenderer.create(options, manifest.recording?.timeline)
|
||||
? await SimulationRenderer.create(options, manifest.recording?.timeline, manifest.viewport)
|
||||
: await createCliRenderer(options)
|
||||
if (!headless && manifest.viewport) renderer.resize(manifest.viewport.cols, manifest.viewport.rows)
|
||||
const server = SimulationServer.start(
|
||||
SimulationActions.createHarness(renderer),
|
||||
manifest.endpoints.ui,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue