Repository navigation
libghostty: add initial C API for terminal, formatter #11506
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
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
302e68f
vt: expose ghostty_terminal_new/free
mitchellh 18fdc15
vt: ghostty_terminal_vt_write
mitchellh 8b9afe3
vt: ghostty_terminal_scroll_viewport
mitchellh fe6e7fb
vt: ghostty_terminal_resize
mitchellh aa3e6e2
vt: ghostty_terminal_reset
mitchellh 34acdfc
vt: update terminal.h docs
mitchellh 8e6bf82
terminal/osc: don't export context/semantic prompts to libvt yet
mitchellh b5fb7ec
vt: wip formatter api
mitchellh 4e494cc
lib: lib.Struct can convert packed structs to extern structs
mitchellh 09d3ebd
vt: use explicit options structs
mitchellh a2d570b
vt: add sized struct pattern and types.h
mitchellh 7c12d6e
agents: skill for writing commit messages
mitchellh 3c8feda
vt: add format_alloc to C API formatter
mitchellh 1e21ac1
example: add c-vt-formatter example
mitchellh 4ad7d03
terminal/formatter: safely cast discarding.count to usize
mitchellh 647f5ad
terminal/formatter: safely cast discarding.count to usize
mitchellh f730eed
vt: fix missing formatter docs in doxygen
mitchellh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| --- | ||
| name: writing-commit-messages | ||
| description: >- | ||
| Writes Git commit messages. Activates when the user asks to write | ||
| a commit message, draft a commit message, or similar. | ||
| --- | ||
|
|
||
| # Writing Commit Messages | ||
|
|
||
| Write commit messages that follow commit style guidelines for the project. | ||
|
|
||
| ## Format | ||
|
|
||
| ``` | ||
| <subsystem>: <summary> | ||
|
|
||
| <reference issues/PRs/etc.> | ||
|
|
||
| <long form description> | ||
| ``` | ||
|
|
||
| ## Rules | ||
|
|
||
| ### Subject line | ||
|
|
||
| - **Subsystem prefix**: Use a short, lowercase identifier for the | ||
| area of code changed (e.g., `terminal`, `vt`, `lib`, `config`, | ||
| `font`). Determine this from the file paths in the diff. If | ||
| changes span the macOS app, use `macos`. For GTK, use `gtk`. For | ||
| build system, use `build`. Use nested subsystems with `/` when | ||
| helpful and exclusive (e.g., `terminal/osc`). | ||
| - **Summary**: Lowercase start (not capitalized), imperative mood, | ||
| no trailing period. Keep it concise—ideally under 60 characters | ||
| total for the whole subject line. | ||
|
|
||
| ### References | ||
|
|
||
| - If the change relates to a GitHub issue, PR, or discussion, list | ||
| the relevant numbers on their own lines after the subject, separated | ||
| by a blank line. E.g. `#1234` | ||
| - If there are no references, omit this section entirely (no blank | ||
| line). | ||
|
|
||
| ### Long form description | ||
|
|
||
| - Describe **what changed**, **what the previous behavior was**, | ||
| and **how the new behavior works** at a high level. | ||
| - Use plain prose, not bullet points. Wrap lines at ~72 characters. | ||
| - Focus on the _why_ and _how_ rather than restating the diff. | ||
| - Keep the tone direct and technical without no filler phrases. | ||
| - Don't exceed a handful of paragraphs; less is more. | ||
|
|
||
| ## Workflow | ||
|
|
||
| - If `.jj` is present, use `jj` instead of `git` for all commands. | ||
| - Run a diff to see what changes are present since the last commit. | ||
| - Identify the subsystem from the changed file paths. | ||
| - Identify any referenced issues/PRs from the diff context or | ||
| branch name. | ||
| - Draft the commit message following the format above. | ||
| - Apply the commit | ||
| - Don't push the commit; leave that to the user. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Example: `ghostty-vt` Terminal Formatter | ||
|
|
||
| This contains a simple example of how to use the `ghostty-vt` terminal and | ||
| formatter APIs to create a terminal, write VT-encoded content into it, and | ||
| format the screen contents as plain text. | ||
|
|
||
| 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 | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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_formatter", | ||
| .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); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| .{ | ||
| .name = .c_vt_formatter, | ||
| .version = "0.0.0", | ||
| .fingerprint = 0x9e3758265677a0c4, | ||
| .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", | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| #include <assert.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <ghostty/vt.h> | ||
|
|
||
| int main() { | ||
| // Create a terminal with a small grid | ||
| GhosttyTerminal terminal; | ||
| GhosttyTerminalOptions opts = { | ||
| .cols = 80, | ||
| .rows = 24, | ||
| .max_scrollback = 0, | ||
| }; | ||
| GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts); | ||
| assert(result == GHOSTTY_SUCCESS); | ||
|
|
||
| // Write VT-encoded content into the terminal to exercise various | ||
| // cursor movement and styling sequences. | ||
| const char *commands[] = { | ||
| "Line 1: Hello World!\r\n", // Simple text on row 1 | ||
| "Line 2: \033[1mBold\033[0m and " // Bold text on row 2 | ||
| "\033[4mUnderline\033[0m\r\n", | ||
| "Line 3: placeholder\r\n", // Will be overwritten below | ||
| "\033[3;1H", // CUP: move cursor back to row 3, col 1 | ||
| "\033[2K", // EL: erase the entire line | ||
| "Line 3: Overwritten!\r\n", // Rewrite row 3 with new content | ||
| "\033[5;10H", // CUP: jump to row 5, col 10 | ||
| "Placed at (5,10)", // Write at that position | ||
| "\033[1;72H", // CUP: jump to row 1, col 72 | ||
| "RIGHT->", // Near the right edge of row 1 | ||
| }; | ||
| for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { | ||
| ghostty_terminal_vt_write(terminal, (const uint8_t *)commands[i], | ||
| strlen(commands[i])); | ||
| } | ||
|
|
||
| // Create a plain-text formatter for the terminal | ||
| GhosttyFormatterTerminalOptions fmt_opts = GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions); | ||
| fmt_opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN; | ||
| fmt_opts.trim = true; | ||
|
|
||
| GhosttyFormatter formatter; | ||
| result = ghostty_formatter_terminal_new(NULL, &formatter, terminal, fmt_opts); | ||
| assert(result == GHOSTTY_SUCCESS); | ||
|
|
||
| // Format into an allocated buffer | ||
| uint8_t *buf = NULL; | ||
| size_t len = 0; | ||
| result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len); | ||
| assert(result == GHOSTTY_SUCCESS); | ||
|
|
||
| // Print the formatted output | ||
| printf("Formatted output (%zu bytes):\n", len); | ||
| fwrite(buf, 1, len, stdout); | ||
| printf("\n"); | ||
|
|
||
| // Clean up | ||
| free(buf); | ||
| ghostty_formatter_free(formatter); | ||
| ghostty_terminal_free(terminal); | ||
| return 0; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 snuck this in here <_<