| 216 | * the "you are here" signal IS the point, syntax color can yield. */ |
| 217 | private currentMatchCache = new Map<number, number>() |
| 218 | withCurrentMatch(baseId: number): number { |
| 219 | let id = this.currentMatchCache.get(baseId) |
| 220 | if (id === undefined) { |
| 221 | const baseCodes = this.get(baseId) |
| 222 | // Filter BOTH fg + bg so yellow-via-inverse is unambiguous. |
| 223 | // User-prompt cells have an explicit bg (grey box); with that bg |
| 224 | // still set, inverse swaps yellow-fg↔grey-bg → grey-on-yellow on |
| 225 | // SOME terminals, yellow-on-grey on others (inverse semantics vary |
| 226 | // when both colors are explicit). Filtering both gives clean |
| 227 | // yellow-bg + terminal-default-fg everywhere. Bold/dim/italic |
| 228 | // coexist — keep those. |
| 229 | const codes = baseCodes.filter( |
| 230 | c => c.endCode !== '\x1b[39m' && c.endCode !== '\x1b[49m', |
| 231 | ) |
| 232 | // fg-yellow FIRST so inverse swaps it to bg. Bold after inverse is |
| 233 | // fine — SGR 1 is fg-attribute-only, order-independent vs 7. |
| 234 | codes.push(YELLOW_FG_CODE) |
| 235 | if (!baseCodes.some(c => c.endCode === '\x1b[27m')) |
| 236 | codes.push(INVERSE_CODE) |
| 237 | if (!baseCodes.some(c => c.endCode === '\x1b[22m')) codes.push(BOLD_CODE) |
| 238 | // Underline as the unambiguous marker — yellow-bg can clash with |
| 239 | // existing bg styling (user-prompt bg, syntax bg). If you see |
| 240 | // underline but no yellow on a match, the overlay IS finding it; |
| 241 | // the yellow is just losing a styling fight. |
| 242 | if (!baseCodes.some(c => c.endCode === '\x1b[24m')) |
| 243 | codes.push(UNDERLINE_CODE) |
| 244 | id = this.intern(codes) |
| 245 | this.currentMatchCache.set(baseId, id) |
| 246 | } |
| 247 | return id |
| 248 | } |
| 249 | |
| 250 | /** |
| 251 | * Selection overlay: REPLACE the cell's background with a solid color |