({
itemKeys,
heightCache,
getWarmHeight,
estimateItemHeight,
previousViewportHeight,
terminalRows = 0,
coldStartCount = COLD_START_COUNT,
overscanRows = OVERSCAN_ROWS,
}: VirtualScrollColdStartRangeInput)
| 145 | } |
| 146 | |
| 147 | export function computeVirtualScrollColdStartRange({ |
| 148 | itemKeys, |
| 149 | heightCache, |
| 150 | getWarmHeight, |
| 151 | estimateItemHeight, |
| 152 | previousViewportHeight, |
| 153 | terminalRows = 0, |
| 154 | coldStartCount = COLD_START_COUNT, |
| 155 | overscanRows = OVERSCAN_ROWS, |
| 156 | }: VirtualScrollColdStartRangeInput): readonly [number, number] { |
| 157 | coldStartCount = resolveVirtualScrollColdStartCount({ |
| 158 | previousViewportHeight, |
| 159 | terminalRows, |
| 160 | coldStartCount, |
| 161 | }) |
| 162 | const end = itemKeys.length |
| 163 | const fallbackStart = Math.max(0, end - coldStartCount) |
| 164 | const coldStartViewport = |
| 165 | previousViewportHeight > 0 ? previousViewportHeight : terminalRows |
| 166 | |
| 167 | if (end === 0 || coldStartViewport <= 0) { |
| 168 | return [fallbackStart, end] |
| 169 | } |
| 170 | |
| 171 | // Transcript entry is the long-history hot path: prompt mode already had a |
| 172 | // real viewport and often measured the tail rows we are about to show. |
| 173 | // Reuse those measured tail heights during the transient viewportHeight=0 / |
| 174 | // scrollTop<0 pre-layout render so we do not over-mount the fixed 30-row |
| 175 | // cold-start window for giant file/code blocks. If measured/warm heights are |
| 176 | // unavailable, allow a cheap render-time estimate for the tail item. This |
| 177 | // keeps the first transcript-entry mount row-budgeted instead of |
| 178 | // fixed-message-count for giant fenced-code messages, but still falls back |
| 179 | // to the old COLD_START_COUNT behavior when the tail shape is unknown. |
| 180 | const budget = coldStartViewport + overscanRows |
| 181 | let start = end |
| 182 | let coverage = 0 |
| 183 | while (start > fallbackStart && coverage < budget) { |
| 184 | const key = itemKeys[start - 1]! |
| 185 | const height = |
| 186 | heightCache.get(key) ?? |
| 187 | getWarmHeight?.(key) ?? |
| 188 | estimateItemHeight?.(start - 1) |
| 189 | if (height === undefined) { |
| 190 | return [fallbackStart, end] |
| 191 | } |
| 192 | coverage += Math.max(1, height) |
| 193 | start-- |
| 194 | } |
| 195 | |
| 196 | return coverage >= budget ? [start, end] : [fallbackStart, end] |
| 197 | } |
| 198 | |
| 199 | export type VirtualScrollOffsetsState = { |
| 200 | arr: Float64Array |
no test coverage detected