* Render a cell's text and decorations (Pass 2 of two-pass rendering) * Selection foreground color is applied here to match the selection background.
(cell: GhosttyCell, x: number, y: number)
| 586 | * Selection foreground color is applied here to match the selection background. |
| 587 | */ |
| 588 | private renderCellText(cell: GhosttyCell, x: number, y: number): void { |
| 589 | const cellX = x * this.metrics.width; |
| 590 | const cellY = y * this.metrics.height; |
| 591 | const cellWidth = this.metrics.width * cell.width; |
| 592 | |
| 593 | // Skip rendering if invisible |
| 594 | if (cell.flags & CellFlags.INVISIBLE) { |
| 595 | return; |
| 596 | } |
| 597 | |
| 598 | // Check if this cell is selected |
| 599 | const isSelected = this.isInSelection(x, y); |
| 600 | |
| 601 | // Set text style |
| 602 | let fontStyle = ''; |
| 603 | if (cell.flags & CellFlags.ITALIC) fontStyle += 'italic '; |
| 604 | if (cell.flags & CellFlags.BOLD) fontStyle += 'bold '; |
| 605 | this.ctx.font = `${fontStyle}${this.fontSize}px ${this.fontFamily}`; |
| 606 | |
| 607 | // Set text color - use selection foreground if selected |
| 608 | if (isSelected) { |
| 609 | this.ctx.fillStyle = this.theme.selectionForeground; |
| 610 | } else { |
| 611 | // Extract colors and handle inverse |
| 612 | let fg_r = cell.fg_r, |
| 613 | fg_g = cell.fg_g, |
| 614 | fg_b = cell.fg_b; |
| 615 | |
| 616 | if (cell.flags & CellFlags.INVERSE) { |
| 617 | // When inverted, foreground becomes background |
| 618 | fg_r = cell.bg_r; |
| 619 | fg_g = cell.bg_g; |
| 620 | fg_b = cell.bg_b; |
| 621 | } |
| 622 | |
| 623 | this.ctx.fillStyle = this.rgbToCSS(fg_r, fg_g, fg_b); |
| 624 | } |
| 625 | |
| 626 | // Apply faint effect |
| 627 | if (cell.flags & CellFlags.FAINT) { |
| 628 | this.ctx.globalAlpha = 0.5; |
| 629 | } |
| 630 | |
| 631 | // Draw text |
| 632 | const textX = cellX; |
| 633 | const textY = cellY + this.metrics.baseline; |
| 634 | |
| 635 | // Get the character to render - use grapheme lookup for complex scripts |
| 636 | let char: string; |
| 637 | if (cell.grapheme_len > 0 && this.currentBuffer?.getGraphemeString) { |
| 638 | // Cell has additional codepoints - get full grapheme cluster |
| 639 | char = this.currentBuffer.getGraphemeString(y, x); |
| 640 | } else { |
| 641 | // Simple cell - single codepoint |
| 642 | char = String.fromCodePoint(cell.codepoint || 32); // Default to space if null |
| 643 | } |
| 644 | this.ctx.fillText(char, textX, textY); |
| 645 |
no test coverage detected