(
ink: InkLike | undefined,
tmuxPane: { text?: string; paneHeight?: number },
)
| 103 | } |
| 104 | |
| 105 | function buildRendererStructuralProbe( |
| 106 | ink: InkLike | undefined, |
| 107 | tmuxPane: { text?: string; paneHeight?: number }, |
| 108 | ): RendererStructuralProbe { |
| 109 | const frontRows = screenRows(ink?.frontFrame?.screen) |
| 110 | const logicalFrontRows = screenRows(ink?.logicalFrontFrame?.screen) |
| 111 | const backRows = screenRows(ink?.backFrame?.screen) |
| 112 | const logicalBackRows = screenRows(ink?.logicalBackFrame?.screen) |
| 113 | |
| 114 | // capture-pane may include scrollback plus the full visible pane. The app |
| 115 | // frame is painted from the viewport top and may be shorter than the pane, |
| 116 | // so compare it with the top of the visible pane, not the last N rows. |
| 117 | const tmuxVisibleRows = selectObservedFrameRows( |
| 118 | tmuxPane.text, |
| 119 | frontRows.length, |
| 120 | tmuxPane.paneHeight, |
| 121 | ) |
| 122 | |
| 123 | const structuralDiffs: StructuralDiff[] = [] |
| 124 | |
| 125 | function addDiffs(label: string, diffs: RowDiff[]) { |
| 126 | for (const diff of diffs) { |
| 127 | structuralDiffs.push({ |
| 128 | source: label, |
| 129 | row: diff.row, |
| 130 | expected: diff.expected, |
| 131 | actual: diff.actual, |
| 132 | }) |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | const frontVsTmux = compareRows(frontRows, tmuxVisibleRows) |
| 137 | addDiffs('tmux_vs_front', frontVsTmux) |
| 138 | |
| 139 | const logicalFrontVsFront = compareRows( |
| 140 | logicalFrontRows.slice(-frontRows.length), |
| 141 | frontRows, |
| 142 | ) |
| 143 | addDiffs('logical_vs_front', logicalFrontVsFront) |
| 144 | |
| 145 | const logicalBackVsBack = compareRows( |
| 146 | logicalBackRows.slice(-backRows.length), |
| 147 | backRows, |
| 148 | ) |
| 149 | addDiffs('logical_vs_back', logicalBackVsBack) |
| 150 | |
| 151 | const hasFrontTmuxDiff = frontVsTmux.length > 0 |
| 152 | const hasLogicalFrontDiff = logicalFrontVsFront.length > 0 |
| 153 | const hasLogicalBackDiff = logicalBackVsBack.length > 0 |
| 154 | |
| 155 | const verdict: RendererStructuralProbe['verdict'] = |
| 156 | !ink && !tmuxPane.text |
| 157 | ? 'not_observed' |
| 158 | : !hasFrontTmuxDiff && !hasLogicalFrontDiff && !hasLogicalBackDiff |
| 159 | ? 'clean' |
| 160 | : hasLogicalFrontDiff |
| 161 | ? 'logical_corrupt' |
| 162 | : hasLogicalBackDiff |
no test coverage detected