-
Notifications
You must be signed in to change notification settings - Fork 306
Add StatelessTerminal renderable. Render ANSI as opentui styled text #440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Here is the multiplexing demo running 4 focusable opencode processes with support for mouse, scrolling and keys forwarding Screen.Recording.2025-12-24.at.12.59.23.mov |
- update build.zig for zig 0.15 API (createModule, standardOptimizeOption) - add ghostty-vt dependency for terminal emulation - use -gnu suffix for linux targets to fix PIC linker errors - update CI workflows to use zig 0.15.2 - update all zig source files for 0.15 compatibility
…inux - Update React and Solid workflows to use Zig 0.15.2 (required by ghostty-vt) - Skip macOS targets when building on non-macOS hosts (ghostty's apple-sdk doesn't support cross-compilation from Linux) - Update TypeScript build script to handle missing platform builds gracefully
- Add mitchellh/zig-build-macos-sdk dependency (official SDK used by Ghostty) - Configure SDK paths on module before loading ghostty dependencies - Update to latest ghostty commit - Remove skip logic for macOS targets since SDK is now provided
Native binaries for all platforms are built in the release workflow (build-native.yml on macOS). PR checks only need to build the TypeScript library and run tests.
macOS can cross-compile to all platforms (Linux, Windows, macOS). This avoids the complexity of setting up macOS SDK on Linux runners.
- By default, zig build now only builds for the native platform - Add -Dall option to zig build for building all platforms - Add --all flag to TypeScript build script - Update release workflow to use --all for cross-compilation This allows Linux users to run `bun run build` without failing on macOS targets.
- ArrayList.init(allocator) → ArrayListUnmanaged with allocator per-method - std.fmt.formatIntBuf → std.fmt.bufPrint - std.fmt.formatInt → writer.print - std.zon.parse.Status removed, use fromSlice directly
- Add vterm.zig with ghostty-vt integration for terminal emulation - Add VTerm FFI functions to lib.zig and zig.ts - Add StatelessTerminalRenderable and TerminalRenderable classes - Fix renderer.zig to skip stdout writes in testing mode (fixes hanging tests) - Fix circular dependency by moving VTerm types to lib/vterm-ffi.ts
d0e472d to
b22b0ba
Compare
Adds `-fPIC` flag for musl targets when building highway and simdutf C++ dependencies, matching the existing freebsd behavior. ## What is PIC? Position Independent Code (PIC) generates machine code using relative addresses instead of absolute ones, allowing the code to be loaded at any memory address. This is required when linking static libraries into shared libraries (.so files). ## Why both freebsd and musl need it Both freebsd and musl use strict relocation policies that reject non-PIC code in shared libraries. Without `-fPIC`, linking fails with errors like: ``` relocation R_X86_64_PC32 cannot be used against symbol '__cxa_begin_catch' ``` glibc is more permissive and handles these relocations at runtime, which is why linux-gnu targets work without this flag. ## Context This enables cross-compiling ghostty-vt to musl/Alpine Linux targets. Discovered while integrating ghostty-vt into opentui: anomalyco/opentui#440 --- This PR was created with help from Claude Opus 4.5.
| matrix: | ||
| include: | ||
| - os: ubuntu-latest | ||
| name: linux-x64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added more OS machines in SO that would run the tests. Currently tests are failing for other OS other than linux but the binaries build correctly. I have another branch that fixes the flaky tests in other OSes
… into ghostty-opentui-2
There was a problem hiding this 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 adds terminal rendering support to OpenTUI using the ghostty-vt library. It introduces two new renderables: TerminalRenderable for interactive stateful terminal sessions and StatelessTerminalRenderable for fast rendering of static ANSI output (useful for previews). The implementation includes comprehensive FFI bindings between TypeScript and Zig, integration with React/Solid/Vue frameworks, and support for both glibc and musl Linux targets.
Key changes:
- Adds ghostty-vt dependency for terminal emulation with VT100/ANSI escape sequence parsing
- Implements FFI layer for terminal creation, feeding, resizing, and output retrieval
- Adds terminal renderables with mouse support and stream-based I/O
- Extends build system to support Linux musl targets (Alpine/Docker)
Reviewed changes
Copilot reviewed 27 out of 28 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/zig/vterm.zig | New Zig module implementing terminal emulation FFI, JSON serialization, and terminal state management |
| packages/core/src/zig/lib.zig | Exports VTerm FFI functions and adds log suppression for ghostty-vt |
| packages/core/src/zig.ts | TypeScript FFI bindings and wrapper methods for VTerm functions with buffer management |
| packages/core/src/renderables/Terminal.ts | Two terminal renderables with stream I/O, mouse support, and text rendering |
| packages/core/src/renderables/Terminal.test.ts | Comprehensive test suite with stress tests for large inputs and concurrent operations |
| packages/core/src/lib/vterm-ffi.ts | Helper functions to convert VTerm data to StyledText format |
| packages/react/src/components/index.ts | Registers terminal and stateless-terminal components for React |
| packages/solid/src/elements/index.ts | Registers terminal and stateless_terminal components for Solid |
| packages/vue/src/elements.ts | Registers terminalRenderable and statelessTerminalRenderable for Vue |
| packages/core/src/zig/build.zig | Adds ghostty dependency and musl Linux target support |
| packages/core/src/zig/build.zig.zon | Declares ghostty-vt dependency pinned to specific commit |
| packages/core/scripts/build.ts | Updates build script to handle musl variants |
| .github/workflows/build-core.yml | Restructures CI to build native libraries once and test on multiple platforms |
| packages/solid/examples/components/terminal-grid-demo.tsx | Demo showing 2x2 grid of interactive terminals with PTY spawning |
| packages/core/src/examples/terminal-simple-demo.ts | Simple demo for stateless terminal with ANSI sample output |
| packages/core/src/examples/terminal-interactive-demo.ts | Interactive demo with PTY-backed terminal and button controls |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Deleted the interactive TerminalRenderable to make the PR easier to review. Only StatelessTerminalRenderable remains now, which is what opencode would use to render bash outputs with colors. |
# Conflicts: # bun.lock # packages/vue/src/elements.ts
Stacked on #439 (zig 0.15 upgrade).
Adds terminal rendering support using ghostty-vt:
StatelessTerminalRenderable- fast renderer for first few lines of output (renders in ~ms, for opencode bash previews)The terminal output is renderd line by line instead of using character cells. This should make it pretty fast even for super long ANSI outputs if they don't use many colors. Each line will simply be a line of text in opentui.
Includes VTerm FFI bindings and registration in React, Solid, and Vue.
Here is how bash outputs looks like in opencode using these terminal renderables (only stateless for now):
Screen.Recording.2025-12-24.at.13.15.29.mov