( s: SelectionState, screen: Screen, firstRow: number, lastRow: number, side: 'above' | 'below', )
| 811 | * side='below': rows scrolling out the bottom (dragging up, anchor=end). |
| 812 | */ |
| 813 | export function captureScrolledRows( |
| 814 | s: SelectionState, |
| 815 | screen: Screen, |
| 816 | firstRow: number, |
| 817 | lastRow: number, |
| 818 | side: 'above' | 'below', |
| 819 | ): void { |
| 820 | const b = selectionBounds(s) |
| 821 | if (!b || firstRow > lastRow) return |
| 822 | const { start, end } = b |
| 823 | // Intersect [firstRow, lastRow] with [start.row, end.row]. Rows outside |
| 824 | // the selection aren't captured — they weren't selected. |
| 825 | const lo = Math.max(firstRow, start.row) |
| 826 | const hi = Math.min(lastRow, end.row) |
| 827 | if (lo > hi) return |
| 828 | |
| 829 | const width = screen.width |
| 830 | const sw = screen.softWrap |
| 831 | const captured: string[] = [] |
| 832 | const capturedSW: boolean[] = [] |
| 833 | for (let row = lo; row <= hi; row++) { |
| 834 | const colStart = row === start.row ? start.col : 0 |
| 835 | const colEnd = row === end.row ? end.col : width - 1 |
| 836 | captured.push(extractRowText(screen, row, colStart, colEnd)) |
| 837 | capturedSW.push(sw[row]! > 0) |
| 838 | } |
| 839 | |
| 840 | if (side === 'above') { |
| 841 | // Newest rows go at the bottom of the above-accumulator (closest to |
| 842 | // the on-screen content in reading order). |
| 843 | s.scrolledOffAbove.push(...captured) |
| 844 | s.scrolledOffAboveSW.push(...capturedSW) |
| 845 | // We just captured the top of the selection. The anchor (=start when |
| 846 | // dragging down) is now pointing at content that will scroll out; its |
| 847 | // col constraint was applied to the captured row. Reset to col 0 so |
| 848 | // the NEXT tick and the final getSelectedText read the full row. |
| 849 | if (s.anchor && s.anchor.row === start.row && lo === start.row) { |
| 850 | s.anchor = { col: 0, row: s.anchor.row } |
| 851 | if (s.anchorSpan) { |
| 852 | s.anchorSpan = { |
| 853 | kind: s.anchorSpan.kind, |
| 854 | lo: { col: 0, row: s.anchorSpan.lo.row }, |
| 855 | hi: { col: width - 1, row: s.anchorSpan.hi.row }, |
| 856 | } |
| 857 | } |
| 858 | } |
| 859 | } else { |
| 860 | // Newest rows go at the TOP of the below-accumulator — they're |
| 861 | // closest to the on-screen content. |
| 862 | s.scrolledOffBelow.unshift(...captured) |
| 863 | s.scrolledOffBelowSW.unshift(...capturedSW) |
| 864 | if (s.anchor && s.anchor.row === end.row && hi === end.row) { |
| 865 | s.anchor = { col: width - 1, row: s.anchor.row } |
| 866 | if (s.anchorSpan) { |
| 867 | s.anchorSpan = { |
| 868 | kind: s.anchorSpan.kind, |
| 869 | lo: { col: 0, row: s.anchorSpan.lo.row }, |
| 870 | hi: { col: width - 1, row: s.anchorSpan.hi.row }, |
no test coverage detected