( buffer: string, styles: AnsiCode[], stylePool: StylePool, out: ClusteredChar[], )
| 584 | } |
| 585 | |
| 586 | function flushBuffer( |
| 587 | buffer: string, |
| 588 | styles: AnsiCode[], |
| 589 | stylePool: StylePool, |
| 590 | out: ClusteredChar[], |
| 591 | ): void { |
| 592 | // Compute styleId + hyperlink ONCE for the whole style run. |
| 593 | // Every grapheme in this buffer shares the same styles. |
| 594 | // |
| 595 | // Extract and track hyperlinks separately, filter from styles. |
| 596 | // Always check for OSC 8 codes to filter, not just when a URL is |
| 597 | // extracted. The tokenizer treats OSC 8 close codes (empty URL) as |
| 598 | // active styles, so they must be filtered even when no hyperlink |
| 599 | // URL is present. |
| 600 | const hyperlink = extractHyperlinkFromStyles(styles) ?? undefined |
| 601 | const hasOsc8Styles = |
| 602 | hyperlink !== undefined || |
| 603 | styles.some( |
| 604 | s => |
| 605 | s.code.length >= OSC8_PREFIX.length && s.code.startsWith(OSC8_PREFIX), |
| 606 | ) |
| 607 | const filteredStyles = hasOsc8Styles |
| 608 | ? filterOutHyperlinkStyles(styles) |
| 609 | : styles |
| 610 | const styleId = stylePool.intern(filteredStyles) |
| 611 | |
| 612 | for (const { segment: grapheme } of getGraphemeSegmenter().segment(buffer)) { |
| 613 | out.push({ |
| 614 | value: grapheme, |
| 615 | width: stringWidth(grapheme), |
| 616 | styleId, |
| 617 | hyperlink, |
| 618 | }) |
| 619 | } |
| 620 | } |
| 621 | |
| 622 | /** |
| 623 | * Write a single line's characters into the screen buffer. |
no test coverage detected