mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-12 04:09:40 +00:00
terminal: expose compression through libghostty-vt
Scrollback compression scheduling was only available to Zig callers that used Terminal directly, leaving C embedders unable to drive the same idle compression policy. Define ABI-aware mode and result enums on Terminal and export activity and compression operations through the C API. Keep scheduling caller-owned, validate C inputs, and document the incremental contract with a complete example. Report unsupported reclamation consistently for full passes so callers can disable compression on targets that cannot retain decommitted mappings.
This commit is contained in:
17
example/c-vt-compression/README.md
Normal file
17
example/c-vt-compression/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Example: Scrollback Compression in C
|
||||
|
||||
This example shows how a libghostty-vt embedding application can track
|
||||
compression-relevant terminal activity and perform incremental scrollback
|
||||
compression after its own idle delay.
|
||||
|
||||
libghostty-vt does not create a timer or background thread. The embedding
|
||||
application remains responsible for scheduling compression and serializing it
|
||||
with other access to the terminal.
|
||||
|
||||
## Usage
|
||||
|
||||
Run the example:
|
||||
|
||||
```shell-session
|
||||
zig build run
|
||||
```
|
||||
32
example/c-vt-compression/build.zig
Normal file
32
example/c-vt-compression/build.zig
Normal file
@@ -0,0 +1,32 @@
|
||||
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"},
|
||||
});
|
||||
|
||||
if (b.lazyDependency("ghostty", .{})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_compression",
|
||||
.root_module = exe_mod,
|
||||
});
|
||||
b.installArtifact(exe);
|
||||
|
||||
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);
|
||||
}
|
||||
14
example/c-vt-compression/build.zig.zon
Normal file
14
example/c-vt-compression/build.zig.zon
Normal file
@@ -0,0 +1,14 @@
|
||||
.{
|
||||
.name = .c_vt_compression,
|
||||
.version = "0.0.0",
|
||||
.fingerprint = 0x3d527aa68a4cf8d,
|
||||
.minimum_zig_version = "0.15.1",
|
||||
.dependencies = .{
|
||||
.ghostty = .{ .path = "../../" },
|
||||
},
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
},
|
||||
}
|
||||
72
example/c-vt-compression/src/main.c
Normal file
72
example/c-vt-compression/src/main.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ghostty/vt.h>
|
||||
|
||||
//! [compression-idle-step]
|
||||
// Perform one step after the application's idle timer fires. Returning true
|
||||
// asks the application to schedule another step while the terminal is idle.
|
||||
static bool compression_idle_step(GhosttyTerminal terminal) {
|
||||
GhosttyTerminalCompressionResult compression_result;
|
||||
GhosttyResult result = ghostty_terminal_compress(
|
||||
terminal,
|
||||
GHOSTTY_TERMINAL_COMPRESSION_MODE_INCREMENTAL,
|
||||
&compression_result);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
switch (compression_result) {
|
||||
case GHOSTTY_TERMINAL_COMPRESSION_RESULT_PENDING:
|
||||
return true;
|
||||
case GHOSTTY_TERMINAL_COMPRESSION_RESULT_COMPLETE:
|
||||
case GHOSTTY_TERMINAL_COMPRESSION_RESULT_UNSUPPORTED:
|
||||
return false;
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//! [compression-idle-step]
|
||||
|
||||
int main(void) {
|
||||
GhosttyTerminal terminal;
|
||||
GhosttyTerminalOptions opts = {
|
||||
.cols = 80,
|
||||
.rows = 24,
|
||||
.max_scrollback = 10 * 1024 * 1024,
|
||||
};
|
||||
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
//! [compression-activity]
|
||||
uint64_t compression_activity;
|
||||
result = ghostty_terminal_compression_activity(
|
||||
terminal,
|
||||
&compression_activity);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
// Terminal mutations may change the token. When it changes, restart the
|
||||
// application's idle timer rather than compressing on the output path.
|
||||
const char *line = "repeated and compressible terminal history\r\n";
|
||||
for (size_t i = 0; i < 4000; i++) {
|
||||
ghostty_terminal_vt_write(
|
||||
terminal,
|
||||
(const uint8_t *)line,
|
||||
strlen(line));
|
||||
}
|
||||
|
||||
uint64_t new_activity;
|
||||
result = ghostty_terminal_compression_activity(terminal, &new_activity);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
if (new_activity != compression_activity) {
|
||||
compression_activity = new_activity;
|
||||
// Restart the application's compression idle timer here.
|
||||
}
|
||||
//! [compression-activity]
|
||||
|
||||
// Simulate the idle timer and its short pending-work continuations.
|
||||
while (compression_idle_step(terminal)) {}
|
||||
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user