( line: string, beforeEnd: number, afterStart: number, afterLen: number, strictAfter = false, )
| 1141 | * Preserves styling from before the overlay that should affect content after it. |
| 1142 | */ |
| 1143 | export function extractSegments( |
| 1144 | line: string, |
| 1145 | beforeEnd: number, |
| 1146 | afterStart: number, |
| 1147 | afterLen: number, |
| 1148 | strictAfter = false, |
| 1149 | ): { before: string; beforeWidth: number; after: string; afterWidth: number } { |
| 1150 | let before = "", |
| 1151 | beforeWidth = 0, |
| 1152 | after = "", |
| 1153 | afterWidth = 0; |
| 1154 | let currentCol = 0, |
| 1155 | i = 0; |
| 1156 | let pendingAnsiBefore = ""; |
| 1157 | let afterStarted = false; |
| 1158 | const afterEnd = afterStart + afterLen; |
| 1159 | |
| 1160 | // Track styling state so "after" inherits styling from before the overlay |
| 1161 | pooledStyleTracker.clear(); |
| 1162 | |
| 1163 | while (i < line.length) { |
| 1164 | const ansi = extractAnsiCode(line, i); |
| 1165 | if (ansi) { |
| 1166 | // Track all SGR codes to know styling state at afterStart |
| 1167 | pooledStyleTracker.process(ansi.code); |
| 1168 | // Include ANSI codes in their respective segments |
| 1169 | if (currentCol < beforeEnd) { |
| 1170 | pendingAnsiBefore += ansi.code; |
| 1171 | } else if (currentCol >= afterStart && currentCol < afterEnd && afterStarted) { |
| 1172 | // Only include after we've started "after" (styling already prepended) |
| 1173 | after += ansi.code; |
| 1174 | } |
| 1175 | i += ansi.length; |
| 1176 | continue; |
| 1177 | } |
| 1178 | |
| 1179 | let textEnd = i; |
| 1180 | while (textEnd < line.length && !extractAnsiCode(line, textEnd)) textEnd++; |
| 1181 | |
| 1182 | for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) { |
| 1183 | const w = graphemeWidth(segment); |
| 1184 | |
| 1185 | if (currentCol < beforeEnd && currentCol + w <= beforeEnd) { |
| 1186 | if (pendingAnsiBefore) { |
| 1187 | before += pendingAnsiBefore; |
| 1188 | pendingAnsiBefore = ""; |
| 1189 | } |
| 1190 | before += segment; |
| 1191 | beforeWidth += w; |
| 1192 | } else if (currentCol >= afterStart && currentCol < afterEnd) { |
| 1193 | const fits = !strictAfter || currentCol + w <= afterEnd; |
| 1194 | if (fits) { |
| 1195 | // On first "after" grapheme, prepend inherited styling from before overlay |
| 1196 | if (!afterStarted) { |
| 1197 | after += pooledStyleTracker.getActiveCodes(); |
| 1198 | afterStarted = true; |
| 1199 | } |
| 1200 | after += segment; |
no test coverage detected