| 188 | * the "you are here" signal IS the point, syntax color can yield. */ |
| 189 | private currentMatchCache = new Map<number, number>() |
| 190 | withCurrentMatch(baseId: number): number { |
| 191 | let id = this.currentMatchCache.get(baseId) |
| 192 | if (id === undefined) { |
| 193 | const baseCodes = this.get(baseId) |
| 194 | // Filter BOTH fg + bg so yellow-via-inverse is unambiguous. |
| 195 | // User-prompt cells have an explicit bg (grey box); with that bg |
| 196 | // still set, inverse swaps yellow-fg↔grey-bg → grey-on-yellow on |
| 197 | // SOME terminals, yellow-on-grey on others (inverse semantics vary |
| 198 | // when both colors are explicit). Filtering both gives clean |
| 199 | // yellow-bg + terminal-default-fg everywhere. Bold/dim/italic |
| 200 | // coexist — keep those. |
| 201 | const codes = baseCodes.filter( |
| 202 | c => c.endCode !== '\x1b[39m' && c.endCode !== '\x1b[49m', |
| 203 | ) |
| 204 | // fg-yellow FIRST so inverse swaps it to bg. Bold after inverse is |
| 205 | // fine — SGR 1 is fg-attribute-only, order-independent vs 7. |
| 206 | codes.push(YELLOW_FG_CODE) |
| 207 | if (!baseCodes.some(c => c.endCode === '\x1b[27m')) |
| 208 | codes.push(INVERSE_CODE) |
| 209 | if (!baseCodes.some(c => c.endCode === '\x1b[22m')) codes.push(BOLD_CODE) |
| 210 | // Underline as the unambiguous marker — yellow-bg can clash with |
| 211 | // existing bg styling (user-prompt bg, syntax bg). If you see |
| 212 | // underline but no yellow on a match, the overlay IS finding it; |
| 213 | // the yellow is just losing a styling fight. |
| 214 | if (!baseCodes.some(c => c.endCode === '\x1b[24m')) |
| 215 | codes.push(UNDERLINE_CODE) |
| 216 | id = this.intern(codes) |
| 217 | this.currentMatchCache.set(baseId, id) |
| 218 | } |
| 219 | return id |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Selection overlay: REPLACE the cell's background with a solid color |