Skip to content

Conversation

@remorses
Copy link
Contributor

@remorses remorses commented Jan 23, 2026

Uses the same VTerm data structures from #440 to expose terminal buffer content as structured span data.

Adds getSpanLines() to OptimizedBuffer and captureSpans() to test renderer.

Use case: render opentui output to web pages or images. You can render a TUI in a test renderer, extract the spans, and serialize them for web rendering or image generation.

import { createTestRenderer } from "@opentui/core/testing"

const { renderer, renderOnce, captureSpans } = await createTestRenderer({ 
  width: 80, 
  height: 24 
})

// render your components...
await renderOnce()

const data = captureSpans()
// data.lines contains styled spans with text, fg, bg, and style flags
// serialize to JSON, render to canvas, generate SVG, etc.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 23, 2026

@opentui/core

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core@574

@opentui/react

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/react@574

@opentui/solid

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/solid@574

@opentui/core-darwin-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-darwin-arm64@574

@opentui/core-darwin-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-darwin-x64@574

@opentui/core-linux-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-linux-arm64@574

@opentui/core-linux-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-linux-x64@574

@opentui/core-win32-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-win32-arm64@574

@opentui/core-win32-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-win32-x64@574

commit: 1136691

@remorses remorses marked this pull request as ready for review January 23, 2026 14:53
Copilot AI review requested due to automatic review settings January 23, 2026 14:53
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR exposes the contents of the terminal render buffer as structured span data compatible with the VTerm-based terminal rendering work from #440, and wires that into the test renderer for easier inspection in tests.

Changes:

  • Add VTermStyleFlags, VTermSpan, VTermLine, and VTermData types to describe styled terminal span output.
  • Implement OptimizedBuffer.getSpanLines() to group contiguous cells with identical styling into spans and convert RGBA + attribute data into the VTerm span format.
  • Extend the test renderer with captureSpans() and add capture-spans.test.ts to verify text, colors, attributes, cursor position, and span grouping behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/core/src/types.ts Defines VTerm-related flag and data interfaces used to describe captured terminal span output.
packages/core/src/buffer.ts Adds attribute-to-VTerm flag mapping and the getSpanLines() method that converts the optimized buffer into VTerm-style span lines.
packages/core/src/testing/test-renderer.ts Exposes a new captureSpans() helper on the test renderer that returns VTermData from the current render buffer.
packages/core/src/testing/capture-spans.test.ts Adds tests that exercise captureSpans() end-to-end, validating dimensions, colors, attributes, cursor position, and span grouping/splitting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const { char, fg, bg, attributes } = this.buffers
const lines: VTermLine[] = []

const rgbaToHex = (r: number, g: number, b: number, a: number): string | null => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a rgbToHex method already in RGBA.ts and I wouldn't redefine such a method inline.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, using RGBA class and rgbToHex from lib now.

@remorses remorses requested a review from simonklee as a code owner January 24, 2026 15:42
@kommander
Copy link
Collaborator

I am a little confused as to what this is being used for? The FrameBuffer has a format that allows each cell to be rendered as such with all the info needed to generate ANSI or an image.

@remorses
Copy link
Contributor Author

The raw buffer data is available via renderer.currentRenderBuffer.buffers, but using it requires knowing internal memory layout:

const { char, fg, bg, attributes } = buffer.buffers
for (let i = 0; i < buffer.width * buffer.height; i++) {
  const codepoint = char[i]
  const fgR = fg[i * 4], fgG = fg[i * 4 + 1], fgB = fg[i * 4 + 2], fgA = fg[i * 4 + 3]
  // etc...
}

This layout could change in the future. getSpanLines() provides a stable, easier-to-use API that also handles span grouping for you.

@remorses
Copy link
Contributor Author

Another use case is tests - quickly finding styled text without manual buffer iteration:

import { VTermStyleFlags } from "@opentui/core"

const { captureSpans, renderOnce } = await createTestRenderer({ width: 80, height: 24 })

// render components...
await renderOnce()

const { lines } = captureSpans()

// Find all bold text in the frame
const boldSpans = lines.flatMap(line => 
  line.spans.filter(span => span.flags & VTermStyleFlags.BOLD)
)

expect(boldSpans.map(s => s.text.trim())).toContain("Important")

@kommander
Copy link
Collaborator

I see, that makes sense. Any way we could re-use the styled-text types for this, like for the flags, instead of introducing additional types? It seems like the spans are close to what styled text/styled chunks describe kind of.

@remorses
Copy link
Contributor Author

Refactored to use existing types: removed VTermStyleFlags, now uses TextAttributes directly and RGBA objects instead of hex strings. Added RGBA.equals() method. Net -19 lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants