From 93c597ce6bb36179065d93a465d6ee679f7472f7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 19 Mar 2026 19:53:52 -0700 Subject: [PATCH] example: add grid reference traversal example Add a c-vt-grid-ref example that demonstrates the terminal and grid reference APIs end-to-end. The example creates a small 10x3 terminal, writes text with mixed styles via VT sequences, then iterates over every cell in the active area using ghostty_terminal_grid_ref. For each cell it extracts the codepoint, and for each row it inspects the wrap flag and the style bold attribute. The grid_ref.h defgroup gains a @snippet reference to the new example, and vt.h gets the corresponding @example entry and @ref listing. --- example/c-vt-grid-traverse/README.md | 19 ++++++ example/c-vt-grid-traverse/build.zig | 42 ++++++++++++ example/c-vt-grid-traverse/build.zig.zon | 24 +++++++ example/c-vt-grid-traverse/src/main.c | 85 ++++++++++++++++++++++++ include/ghostty/vt.h | 6 ++ include/ghostty/vt/grid_ref.h | 4 ++ 6 files changed, 180 insertions(+) create mode 100644 example/c-vt-grid-traverse/README.md create mode 100644 example/c-vt-grid-traverse/build.zig create mode 100644 example/c-vt-grid-traverse/build.zig.zon create mode 100644 example/c-vt-grid-traverse/src/main.c diff --git a/example/c-vt-grid-traverse/README.md b/example/c-vt-grid-traverse/README.md new file mode 100644 index 000000000..f9a15851a --- /dev/null +++ b/example/c-vt-grid-traverse/README.md @@ -0,0 +1,19 @@ +# Example: `ghostty-vt` Grid Traversal + +This contains a simple example of how to use the `ghostty-vt` terminal and +grid reference APIs to create a terminal, write content into it, and then +traverse the entire grid cell-by-cell using grid refs to inspect codepoints, +row state, and styles. + +This uses a `build.zig` and `Zig` to build the C program so that we +can reuse a lot of our build logic and depend directly on our source +tree, but Ghostty emits a standard C library that can be used with any +C tooling. + +## Usage + +Run the program: + +```shell-session +zig build run +``` diff --git a/example/c-vt-grid-traverse/build.zig b/example/c-vt-grid-traverse/build.zig new file mode 100644 index 000000000..caf174028 --- /dev/null +++ b/example/c-vt-grid-traverse/build.zig @@ -0,0 +1,42 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const run_step = b.step("run", "Run the app"); + + const exe_mod = b.createModule(.{ + .target = target, + .optimize = optimize, + }); + exe_mod.addCSourceFiles(.{ + .root = b.path("src"), + .files = &.{"main.c"}, + }); + + // You'll want to use a lazy dependency here so that ghostty is only + // downloaded if you actually need it. + if (b.lazyDependency("ghostty", .{ + // Setting simd to false will force a pure static build that + // doesn't even require libc, but it has a significant performance + // penalty. If your embedding app requires libc anyway, you should + // always keep simd enabled. + // .simd = false, + })) |dep| { + exe_mod.linkLibrary(dep.artifact("ghostty-vt")); + } + + // Exe + const exe = b.addExecutable(.{ + .name = "c_vt_grid_traverse", + .root_module = exe_mod, + }); + b.installArtifact(exe); + + // Run + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| run_cmd.addArgs(args); + run_step.dependOn(&run_cmd.step); +} diff --git a/example/c-vt-grid-traverse/build.zig.zon b/example/c-vt-grid-traverse/build.zig.zon new file mode 100644 index 000000000..21b6cea18 --- /dev/null +++ b/example/c-vt-grid-traverse/build.zig.zon @@ -0,0 +1,24 @@ +.{ + .name = .c_vt_grid_traverse, + .version = "0.0.0", + .fingerprint = 0xf694dd12db9be040, + .minimum_zig_version = "0.15.1", + .dependencies = .{ + // Ghostty dependency. In reality, you'd probably use a URL-based + // dependency like the one showed (and commented out) below this one. + // We use a path dependency here for simplicity and to ensure our + // examples always test against the source they're bundled with. + .ghostty = .{ .path = "../../" }, + + // Example of what a URL-based dependency looks like: + // .ghostty = .{ + // .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz", + // .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s", + // }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/example/c-vt-grid-traverse/src/main.c b/example/c-vt-grid-traverse/src/main.c new file mode 100644 index 000000000..f07169eb6 --- /dev/null +++ b/example/c-vt-grid-traverse/src/main.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +//! [grid-ref-traverse] +int main() { + // Create a small terminal + GhosttyTerminal terminal; + GhosttyTerminalOptions opts = { + .cols = 10, + .rows = 3, + .max_scrollback = 0, + }; + GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts); + assert(result == GHOSTTY_SUCCESS); + + // Write some content so the grid has interesting data + const char *text = "Hello!\r\n" // Row 0: H e l l o ! + "World\r\n" // Row 1: W o r l d + "\033[1mBold"; // Row 2: B o l d (bold style) + ghostty_terminal_vt_write( + terminal, (const uint8_t *)text, strlen(text)); + + // Get terminal dimensions + uint16_t cols, rows; + ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLS, &cols); + ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_ROWS, &rows); + + // Traverse the entire grid using grid refs + for (uint16_t row = 0; row < rows; row++) { + printf("Row %u: ", row); + for (uint16_t col = 0; col < cols; col++) { + // Resolve the point to a grid reference + GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef); + GhosttyPoint pt = { + .tag = GHOSTTY_POINT_TAG_ACTIVE, + .value = { .coordinate = { .x = col, .y = row } }, + }; + result = ghostty_terminal_grid_ref(terminal, pt, &ref); + assert(result == GHOSTTY_SUCCESS); + + // Read the cell from the grid ref + GhosttyCell cell; + result = ghostty_grid_ref_cell(&ref, &cell); + assert(result == GHOSTTY_SUCCESS); + + // Check if the cell has text + bool has_text = false; + ghostty_cell_get(cell, GHOSTTY_CELL_DATA_HAS_TEXT, &has_text); + + if (has_text) { + uint32_t codepoint = 0; + ghostty_cell_get(cell, GHOSTTY_CELL_DATA_CODEPOINT, &codepoint); + printf("%c", (char)codepoint); + } else { + printf("."); + } + } + + // Also inspect the row for wrap state + GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef); + GhosttyPoint pt = { + .tag = GHOSTTY_POINT_TAG_ACTIVE, + .value = { .coordinate = { .x = 0, .y = row } }, + }; + ghostty_terminal_grid_ref(terminal, pt, &ref); + + GhosttyRow grid_row; + ghostty_grid_ref_row(&ref, &grid_row); + + bool wrap = false; + ghostty_row_get(grid_row, GHOSTTY_ROW_DATA_WRAP, &wrap); + printf(" (wrap=%s", wrap ? "true" : "false"); + + // Check the style of the first cell with text + GhosttyStyle style = GHOSTTY_INIT_SIZED(GhosttyStyle); + ghostty_grid_ref_style(&ref, &style); + printf(", bold=%s)\n", style.bold ? "true" : "false"); + } + + ghostty_terminal_free(terminal); + return 0; +} +//! [grid-ref-traverse] diff --git a/include/ghostty/vt.h b/include/ghostty/vt.h index 8a53c4bd0..a3d0ec57d 100644 --- a/include/ghostty/vt.h +++ b/include/ghostty/vt.h @@ -50,6 +50,7 @@ * - @ref c-vt-paste/src/main.c - Paste safety check example * - @ref c-vt-sgr/src/main.c - SGR parser example * - @ref c-vt-formatter/src/main.c - Terminal formatter example + * - @ref c-vt-grid-traverse/src/main.c - Grid traversal example using grid refs * */ @@ -84,6 +85,11 @@ * contents as plain text. */ +/** @example c-vt-grid-traverse/src/main.c + * This example demonstrates how to traverse the entire terminal grid using + * grid refs to inspect cell codepoints, row wrap state, and cell styles. + */ + #ifndef GHOSTTY_VT_H #define GHOSTTY_VT_H diff --git a/include/ghostty/vt/grid_ref.h b/include/ghostty/vt/grid_ref.h index 0b196dce5..29ecda7b5 100644 --- a/include/ghostty/vt/grid_ref.h +++ b/include/ghostty/vt/grid_ref.h @@ -35,6 +35,10 @@ extern "C" { * built to sustain the framerates needed for rendering large screens. * Use the render state API for that. * + * ## Example + * + * @snippet c-vt-grid-traverse/src/main.c grid-ref-traverse + * * @{ */