import assert from "node:assert/strict"; function tags(frame) { return frame.styleRows.flatMap((cells, y) => y > 0 && cells.some((cell) => cell[2] & 128) ? [y] : []); } function pane(frame, name) { const rows = tags(frame); const top = rows.find((row) => frame.lines[row].includes(name)); assert.notEqual(top, undefined, `missing pane ${name}`); const bottom = rows.find((row) => row > top) ?? frame.rows; return { top, bottom, lines: frame.lines.slice(top + 1, bottom) }; } function styled(frame) { const source = pane(frame, "touch-fixture.zig"); for (const [line, word, fg, bold] of [ ["pub fn choose", "fn", 0xcf87e8, true], ["pub fn choose", "choose", 0xbdbdbd, false], ["if (value", "if", 0xcf87e8, true], ["if (value", "42", 0xe3c78a, false], ["if (value", '"touch fixture"', 0xe3c78a, false], ]) { const row = source.lines.findIndex((text) => text.includes(line)); assert(row >= 0, `missing source line ${line}`); const col = source.lines[row].indexOf(word); for (let x = col; x < col + word.length; x++) { const style = frame.styleRows[source.top + 1 + row][x]; assert.equal(style[0], fg, `${word} cell ${x - col} foreground`); assert.equal(Boolean(style[2] & 1), bold, `${word} cell ${x - col} bold`); } } for (const [row, line] of source.lines.entries()) { const number = /\b(\d+),/.exec(line); if (!number) continue; for (let x = number.index; x < number.index + number[1].length; x++) { assert.equal(frame.styleRows[source.top + 1 + row][x][0], 0xe3c78a, `row ${row} number foreground`); } } } export default async function ({ grid, touch, wait, stable, delay }) { await stable(100, 5000); let frame = await grid(); assert.equal(tags(frame).length, 1); styled(frame); const link = "/virtual/pane/1/body"; const row = frame.lines.findIndex((text) => text.includes(link)); const col = frame.lines[row].indexOf(link) + 5; let finger = await touch("down", 1, col, row, null); finger = await touch("move", 1, col + 0.2, row + 0.1, finger); await touch("up", 1, col + 0.2, row + 0.1, finger); await wait(async () => tags(await grid()).length === 2, 5000, "Look opening the reflected body"); await stable(100, 5000); frame = await grid(); styled(frame); const reflected = pane(frame, link); assert(reflected.lines.some((text) => text.includes("pub fn choose"))); const original = pane(frame, "touch-fixture.zig"); const sharedRows = Math.min(reflected.lines.length, original.lines.length); assert(sharedRows >= 6); assert.deepEqual(reflected.lines.slice(0, sharedRows), original.lines.slice(0, sharedRows), "Look must read the source pane body"); const center = Math.floor(frame.cols / 2); const separator = Math.max(original.top, reflected.top) - 1; const distance = original.top < reflected.top ? 4 : -4; finger = await touch("down", 2, center, separator, null); for (let step = 1; step <= 8; step++) { finger = await touch("move", 2, center, separator + distance * step / 8, finger); await delay(20); } await touch("up", 2, center, separator + distance, finger); await stable(100, 5000); frame = await grid(); assert.equal(tags(frame).length, 2); const resized = pane(frame, "touch-fixture.zig"); assert(resized.lines.length >= original.lines.length + 3, "separator drag must resize, not scroll the body"); assert.equal(resized.lines[0], original.lines[0], "resizing must preserve the source viewport"); styled(frame); const beforeScroll = resized.lines[0]; const reflectedBeforeScroll = pane(frame, link).lines; const from = resized.bottom - 3; const to = Math.max(resized.top + 2, from - 7); finger = await touch("down", 3, center, from, null); for (let step = 1; step <= 12; step++) { finger = await touch("move", 3, center, from + (to - from) * step / 12, finger); await delay(20); } await touch("up", 3, center, to, finger); await stable(100, 5000); frame = await grid(); assert.equal(tags(frame).length, 2, "scroll must not also Look"); const scrolled = pane(frame, "touch-fixture.zig"); assert.equal(scrolled.top, resized.top, "body scrolling must not resize"); assert.notEqual(scrolled.lines[0], beforeScroll, "source must scroll"); assert(Number(scrolled.lines[0].trim().split(/\s+/)[0]) > 1, "scroll advances source line numbers"); assert.deepEqual(pane(frame, link).lines, reflectedBeforeScroll, "scrolling the source must leave its neighbor alone"); }