Commit Graph
1115 Commits
Author SHA1 Message Date
Simon Klee 7a0dca8d5e web: add rendered terminal examples to docs (#1446)
Show actual OpenTUI output beside documentation examples so readers
can see component behavior without running an application.
2026-08-26 21:04:05 +02:00
Simon Klee 33203b5029 native: prove styled text without JavaScript (#1419) 2026-08-26 17:29:03 +02:00
Simon Klee e1ad51afcd ssh: assert error code for occupied ports (#1444) 2026-08-26 16:41:47 +02:00
Simon Klee c1f2409947 ffi: preserve viewport lookup success result (#1443)
The native viewport lookup reports whether a view exists, but the FFI
binding discarded that result. Preserve the boolean so callers can
distinguish missing views from successful lookups.
2026-08-26 14:36:41 +02:00
m-paandSimon Klee 010c07df29 fix(core): align bordered hit-grid clipping (#1441)
## Summary
- align hit-grid scissor coordinates with bordered content bounds
- preserve correct clipping for buffered, nested, partial-border, and
scrollable containers
- add regression coverage for final-row and final-column hit targets

Fixes anomalyco/opentui#1231

## Verification
`bun test src/tests/scrollbox-hitgrid.test.ts`

---------

Co-authored-by: Simon Klee <hello@simonklee.dk>
2026-08-26 11:04:09 +00:00
Simon Klee 352c1fc59b renderer: ignore invalid terminal dimensions (#1440)
Prevent resize signals with unavailable terminal dimensions from
resetting the renderer to an arbitrary 80x24 fallback.

Supersede #687
2026-08-26 10:50:26 +02:00
Sebastian 465c3ccad0 refactor(core): clarify text layout units (#1429) 2026-08-25 22:52:07 +02:00
Sebastian d2089a81ae refactor(core): make wrapped layout byte-accurate (#1428) 2026-08-25 22:33:47 +02:00
Sebastian 8046c846cf feat(native): export audio module to Zig consumers (#1431) 2026-08-25 16:05:01 +02:00
Simon Klee dd3dce90dd renderer: preserve wide grapheme updates (#1424)
Incremental updates could start output within a wide grapheme and corrupt
it. Begin updates at printable cells to preserve the grapheme.
2026-08-25 09:20:22 +02:00
Simon Klee da717b74a1 renderer: resolve snapshot links from snapshot pool (#1418) 2026-08-25 09:16:46 +02:00
Simon Kleeandcopilot-swe-agent[bot] 29243aa294 renderer: prevent backpressure revive (#1170)
A backpressured frame could schedule a retry after its callback paused
or
stopped the renderer, reviving a cancelled continuous loop.

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-08-25 06:52:42 +02:00
James Long a7fb4ec78e feat(native): filter Ghostty logs (#1426)
## Summary
- recognize the selected Ghostty `std.log` scopes in OpenTUI's root
logger
- keep all standard-library logs silent by default
- read `OTUI_GHOSTTY_LOG_LEVEL` inside the native `logFn` and forward
enabled messages through the existing `logger.logMessage` path
- support `error`/`err`, `warn`/`warning`, `info`, and `debug`
thresholds
- document the environment variable

## Behavior
Unset or invalid `OTUI_GHOSTTY_LOG_LEVEL` values emit no `std.log`
messages. Recognized Ghostty scopes are forwarded up to the configured
severity. Logs from every other scope are discarded. Explicit OpenTUI
logger calls are unchanged.

## Testing
- release `bun run build` from `packages/core`
- `bun run test:native` from `packages/core` (2066 passed, 8 skipped)
- `zig fmt --check packages/native/src/lib.zig
packages/native/src/logger.zig`
- `oxfmt --check packages/web/src/content/docs/reference/env-vars.mdx`
2026-08-24 16:58:16 -04:00
James Long 189f1007f8 fix(native): silence standard library logs (#1425)
## Summary
- install a root `std_options.logFn` that discards `std.log` output
- leave Zig's default compile-time log level unchanged
- keep explicit OpenTUI `logger.logMessage` output flowing through the
existing JavaScript callback

## Why
OpenTUI imports native dependencies such as Ghostty into its Zig root
module. Their `std.log` calls otherwise use Zig's default stderr logger,
bypass the renderer, and can corrupt the terminal display. OpenTUI
already has a separate explicit logger for messages intended for
JavaScript and file logging, so standard-library logs should not write
directly to the host terminal.

## Testing
- `zig fmt --check packages/native/src/lib.zig`
- release `bun run build` from `packages/core`
- `bun run test:native` from `packages/core` (2066 passed, 8 skipped)
2026-08-24 22:23:04 +02:00
James Long 247199db66 fix(core): normalize embedded terminal keys (#1423)
## Summary
- reject parser escape codes such as `[A` and `[27u` as physical key
identifiers
- infer Web-style physical identities (`ArrowUp`, `KeyC`, `Digit1`,
`Escape`) before calling Ghostty
- derive the unshifted codepoint from that normalized physical identity
- cover raw arrow input and nested Kitty character/escape re-encoding

## Why this is needed
OpenTUI key events use `code` for two different kinds of values. Kitty
and raw escape parsing can produce parser codes such as `[A` for Up or
`[27u` for Kitty Escape, while other events provide Web-style physical
codes such as `KeyA`. Ghostty's key encoder accepts the latter physical
identities, not parser escape fragments. Passing `[A` through as the
physical key leaves Ghostty unable to encode an arrow key.

Embedded terminals also need to re-encode input when the program inside
them enables the Kitty keyboard protocol. In that mode, text alone is
insufficient for modified and disambiguated keys: Ghostty needs a
normalized physical identity and its unshifted codepoint. Raw character
events may not include `code`, so this change infers `KeyA`/`Digit1`;
Kitty escape events whose parser code is `[27u` fall back to `Escape`.
The regression verifies that Ctrl+C and Escape are re-emitted as Kitty
sequences for a nested terminal.

## Testing
- `bun test src/renderables/EmbeddedTerminal.test.ts` (16 passed)
- `oxlint packages/core/src/renderables/EmbeddedTerminal.ts
packages/core/src/renderables/EmbeddedTerminal.test.ts`
- `oxfmt --check packages/core/src/renderables/EmbeddedTerminal.ts
packages/core/src/renderables/EmbeddedTerminal.test.ts`
2026-08-24 13:27:33 -04:00
Simon Klee 21b0021742 Release v0.5.8 v0.5.8 2026-08-24 15:03:23 +02:00
Simon Klee bc94b6e540 ci: include hidden core dump files (#1422)
Upload dot-prefixed core dump files so crash diagnostics are not
silently omitted from CI artifacts.
2026-08-24 14:07:22 +02:00
Simon Klee 403b7637bb terminal: match Ghostty wide grapheme widths (#1415)
Ghostty 1.3 renders certain multi-code-point graphemes two columns wide.
Use its width profile for direct sessions so rendering, wrapping, and
cursor placement stay aligned with the terminal.

Fix #1401
2026-08-24 13:54:37 +02:00
Simon Klee 0b06560ed4 readme: clarify project overview (#1417) 2026-08-24 13:38:24 +02:00
Simon Klee 4d983f032b mouse: track buttons independently (#1416)
Keep left-button selection state until its own release so right-click
interactions do not interrupt dragging.
2026-08-24 09:03:34 +02:00
Simon Klee 6b3a9e46cb ci: save Linux core dumps from failed tests (#1414)
Linux test crashes left no data to investigate after the runner stopped.
The CI system now saves core dumps and program files to help find the
cause.
2026-08-23 13:23:45 +02:00
Simon Klee a6d993da72 utf8: count Thai spacing marks in widths (#1413)
Thai SARA AM occupies an additional cell within a grapheme. Count
positive-width spacing marks to keep output coordinates aligned with
terminals.

Fix #479
2026-08-23 09:52:44 +02:00
Simon Klee 2ba1c36cba ci: run all matrix tests after failures (#1412)
Preserve results from every supported platform when one matrix job
fails.

Trying to avoid it cancelling all jobs when one thing fails.
2026-08-23 09:02:33 +02:00
Simon Klee 5ec3f33e85 Release v0.5.7 v0.5.7 2026-08-23 08:35:31 +02:00
Wu ShuwenandSimon Klee fba0ebe10a fix(core): correlate OSC 66 probe responses (#1384)
## Summary

- correlate cursor-position reports with the two emitted OSC 66 probes
- keep the startup cursor report out of capability detection
- require the exact expected columns instead of accepting larger echoed
payload widths

Terminals that echo an unsupported OSC 66 payload can leave the cursor
well past the expected probe column. Treating any row-1 report at or
beyond the expected column therefore enables capabilities the terminal
does not support. The probe state now consumes only the two ordered
responses emitted by `queryTerminalSend`, while an unrelated cursor
report cannot enable text scaling.

Closes #1383.

## Testing

- filtered Zig 0.16 native tests: 2 passed
- full Zig 0.16 native suite: 2,013 passed, 8 skipped
- native hello example
- `bun run build`
- `bun run fmt:check`
- `bun run lint`
- `zig fmt --check packages/native/src/terminal.zig
packages/native/src/tests/terminal_test.zig`

---------

Co-authored-by: Simon Klee <hello@simonklee.dk>
2026-08-23 08:07:19 +02:00
Simon Klee a15a383c89 core: test u32 cell attributes on all platforms (#1411)
Node FFI paths can truncate cell attributes when native types differ
across
platforms. Exercise every per-cell entry point under Node on all
runners.
2026-08-23 07:52:20 +02:00
Simon Klee fa14b96ad4 node: support Node.js 26.4 and later (#1410)
Keep 26.4.0 as the minimum supported version while allowing later
releases.
2026-08-23 06:56:30 +02:00
Simon Klee e3937cf0dd core: fix portable boolean FFI calls (#1409)
Model native flags as numeric bytes so Bun and Node share one FFI
contract. Keep split-footer commits within Darwin ARM64's eight argument
registers to prevent stack marshalling from losing frame-finalization
state.
2026-08-23 06:56:08 +02:00
Simon Klee 03f4c14d2a core: add double/triple click support (#1407)
Fix https://github.com/anomalyco/opentui/issues/74 

Double-click selects a word. Triple-click selects the line. A first
click still selects nothing.

Renderer counts left presses. A second press on the same cell within 500
ms asks for a word. A third press asks for a line.

Drag after a word click keeps the spaces between words. Shift+arrow
after a multi-click extends by cell, not by word.

ASCII font and tables stay cell-only. The click interval and the
word-character set are hard-coded for now.
2026-08-23 06:42:00 +02:00
Simon Klee eaf1d41e92 web: add OpenTUI Mono typeface (#1404)
Replace Commit Mono with a project-owned Iosevka build so the site
typeface can evolve with OpenTUI's visual identity. Add a private font
lab to compare future builds before publishing them.
2026-08-22 11:11:30 +02:00
ea89dcd083 fix(core): selection no longer collapses with y below, x left of text (#1381)
This fixes the selection breaking when `x` is before the text, but `y`
below it. Without the fix, the show selection is flipped.

---------

Co-authored-by: Ofek Doitch <Ofek@WeedonAndScott.com>
Co-authored-by: Simon Klee <hello@simonklee.dk>
2026-08-21 20:32:45 +00:00
Simon Klee 6f7833d097 renderer: reject forced Sixel for non-hosts (#1387)
Apple Terminal and terminal multiplexers cannot render forced Sixel
output. Fall back to blocks unless the detected host supports Sixel.
2026-08-21 22:10:04 +02:00
Simon Klee a84a0bac70 core: add configurable selection occupancy (#1393)
Selection combines half-open forward ranges with an inclusive backward
workaround. Replaying a local selection can change its range, and
extending
by one display column can split a wide grapheme.

Add an explicit occupancy model. Cell occupancy includes both endpoint
graphemes for Vim-style behavior. Boundary occupancy uses a half-open
range between insertion points. This behavior matches conventional thin
cursors.

Keep occupancy independent of cursor paint. Normalize endpoints to whole
graphemes. This keeps highlighting, copied text, deletion, cursor sync,
and wrapped-line navigation consistent in both directions.

A press without movement keeps the selection empty. Preserve half-open
offset selections. A cursor at the end of a line does not occupy the
newline, but crossing the line boundary selects it.

Supersedes the boundary-semantics direction of PR
https://github.com/anomalyco/opentui/pull/1389.
2026-08-21 22:06:49 +02:00
Simon Klee cf0287f657 web: update font (#1402) 2026-08-21 21:57:46 +02:00
Simon Klee fa20a6bc20 web: font size consistency (#1399) 2026-08-21 12:44:58 +02:00
Simon Klee caf15c037d docs: add section-aware documentation search (#1392)
Let readers find relevant API details without manually scanning the
documentation tree. Return ranked section links with matching context.
2026-08-20 23:26:44 +02:00
Simon Klee c1ae55b4ec fix: pin Bun types to 1.3.14 v0.5.6 2026-08-20 23:06:41 +02:00
Simon Klee b7b4a95f18 Release v0.5.6 2026-08-20 22:52:43 +02:00
Sebastian e69cf0cc54 ci: migrate npm publishing to OIDC (#1395) oidc-1-snapshot 2026-08-20 18:42:01 +02:00
Simon Klee fdf893d285 Release v0.5.5 v0.5.5 2026-08-20 15:55:30 +02:00
Luke Parker 2e7f96f547 fix(core): pass transient FFI buffers directly (#1394)
## Summary

- use `buffer` ABI parameters and pass typed-array owners directly for
transient synchronous Bun FFI calls
- lower portable `buffer` parameters to Node's stable `pointer` path
while still passing owner objects directly
- keep `ptr` only for nullable, mixed native-pointer, raw `ArrayBuffer`,
callback, and retained-memory cases
- stabilize retained text-memory views through `.buffer` before
resolving their native address
- preserve raw-pointer compatibility while allowing direct buffers in
supersample, packed-buffer, matrix, and grayscale APIs
- document the Bun 1.3.14 and Bun 1.4+ ownership rules in `AGENTS.md`

## Why

A Bun `FastTypedArray` may store its data inline. Calling `ptr(view)`
captures that address, but a later first access to `view.buffer` can
move the data into separate `ArrayBuffer` storage and leave the native
address stale. Passing the owner directly lets the FFI backend borrow
the current storage for synchronous calls and allows Bun's `buffer` fast
path to keep the owner visible to the JIT.

This keeps nullable and true native-pointer parameters on `ptr`, where
`buffer` cannot represent the ABI, while avoiding pre-resolved addresses
for transient memory. Retained pointers explicitly materialize stable
backing storage before `ptr(view)` and keep the view alive for the
native lifetime.

Node 26.4's Linux optimized `buffer` trampoline delivered a null pointer
to a multi-argument audio call in CI. OpenTUI therefore maps its
portable `buffer` descriptor to Node `pointer`, whose documented
owner-borrowing path passes the same views correctly. Bun continues to
receive the `buffer` descriptor.

Related Bun investigation: oven-sh/bun#32054 and oven-sh/bun#32055.

## Testing

- `bunx bun@1.3.14 test
src/tests/ffi-borrowed-pointer-callsites.test.ts` (23 passed)
- `bun test src/tests/ffi-borrowed-pointer-callsites.test.ts` on Bun 1.4
canary (23 passed)
- `bun run test:js` (5,397 passed, 23 skipped)
- `bun run test:js:node` with Node 26.4.0 (4,665 passed, 6 skipped)
- `bun run test:dist`
- `bun run build:lib`
- `bun run fmt:check`
- `bun run lint`
2026-08-20 15:42:54 +02:00
Simon Klee 27cdb18e8e examples: run native build script
Use the package build command when refreshing host artifacts so the examples build follows the supported native build workflow.
2026-08-20 13:29:31 +02:00
Simon Klee 6e09f4b68b core: vendor Zig dependencies (#1386)
Make native builds use a pinned local archive instead of fetching
Zig dependencies from remote package servers. This removes network
availability from CI and makes the supplied source inputs reproducible.
2026-08-20 11:54:15 +02:00
Simon Klee 6dec16a77c native: move Zig sources into packages/native (#1391)
Separate the native implementation from the TypeScript bindings. Keep
core on
the public bindings and keep the current native artifact packages and
release
workflows.

packages/native owns the Zig source, tests, benches, and vendor updates.
The
package is private and unpublished for now Core still packages the
@opentui/core-* artifacts. build:native, test:native, and bench:native
still
work from core and delegate to native.

Expose a Zig import root and a no-JS hello example for proof of concept,
not a focus point, just a smoke test.
2026-08-20 11:34:03 +02:00
Simon Klee 2417a2c0b7 docs: clarify embedded terminal behavior (#1390)
Describe the renderable as the owner of terminal state and event
handling. This makes I/O, layout, focus, and failure behavior clearer to
callers.
2026-08-19 14:08:54 +02:00
Simon Klee 0dcb68578c docs: add embedded terminal docs (#1388) 2026-08-19 13:45:23 +02:00
8cae8eddee feat(core): add embedded terminal renderable (#1340)
---------

Co-authored-by: Simon Klee <hello@simonklee.dk>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Sebastian Herrlinger <hasta84@gmail.com>
Co-authored-by: quintoo-bot <sebastian+quintoo-github@anoma.ly>
Co-authored-by: quintoo-bot <317894163+quintoo-bot@users.noreply.github.com>
2026-08-18 22:17:56 +02:00
Simon Klee 7f5b19b640 Release v0.5.4 v0.5.4 2026-08-18 13:26:44 +02:00
Simon Klee b428e73ae6 core: fix GNU Screen OSC 52 passthrough (#1334)
Screen handles DCS payloads differently from tmux and consumes the inner
ST, leaving the outer terminal with an unterminated OSC 52 request. Use
BEL and bounded payload framing so Screen forwards complete clipboard
sequences, including large values.

Reference: https://github.com/anomalyco/opencode/issues/28590
2026-08-18 13:19:06 +02:00
Simon Klee ffb3c96adf renderer: clear stale mouse input (#1382)
The terminal can send mouse reports after OpenTUI releases stdin.
Clear pending input during shutdown. This stops the next app from
reading stale escape sequences.
Keep input received after suspend(). The app owns terminal input then.

Close #1360
2026-08-18 12:11:36 +02:00