Compare commits

..

No commits in common. "main" and "v1.3.1" have entirely different histories.
main ... v1.3.1

534 changed files with 41224 additions and 94691 deletions

64
.agents/commands/gh-issue Executable file
View File

@ -0,0 +1,64 @@
#!/usr/bin/env nu
# A command to generate an agent prompt to diagnose and formulate
# a plan for resolving a GitHub issue.
#
# IMPORTANT: This command is prompted to NOT write any code and to ONLY
# produce a plan. You should still be vigilant when running this but that
# is the expected behavior.
#
# The `<issue>` parameter can be either an issue number or a full GitHub
# issue URL.
def main [
issue: any, # Ghostty issue number or URL
--repo: string = "ghostty-org/ghostty" # GitHub repository in the format "owner/repo"
] {
# TODO: This whole script doesn't handle errors very well. I actually
# don't know Nu well enough to know the proper way to handle it all.
let issueData = gh issue view $issue --json author,title,number,body,comments | from json
let comments = $issueData.comments | each { |comment|
$"
### Comment by ($comment.author.login)
($comment.body)
" | str trim
} | str join "\n\n"
$"
Deep-dive on this GitHub issue. Find the problem and generate a plan.
Do not write code. Explain the problem clearly and propose a comprehensive plan
to solve it.
# ($issueData.title) \(($issueData.number)\)
## Description
($issueData.body)
## Comments
($comments)
## Your Tasks
You are an experienced software developer tasked with diagnosing issues.
1. Review the issue context and details.
2. Examine the relevant parts of the codebase. Analyze the code thoroughly
until you have a solid understanding of how it works.
3. Explain the issue in detail, including the problem and its root cause.
4. Create a comprehensive plan to solve the issue. The plan should include:
- Required code changes
- Potential impacts on other parts of the system
- Necessary tests to be written or updated
- Documentation updates
- Performance considerations
- Security implications
- Backwards compatibility \(if applicable\)
- Include the reference link to the source issue and any related discussions
4. Think deeply about all aspects of the task. Consider edge cases, potential
challenges, and best practices for addressing the issue. Review the plan
with the oracle and adjust it based on its feedback.
**ONLY CREATE A PLAN. DO NOT WRITE ANY CODE.** Your task is to create
a thorough, comprehensive strategy for understanding and resolving the issue.
" | str trim
}

View File

@ -1,62 +0,0 @@
---
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.

44
.gitattributes vendored
View File

@ -1,47 +1,3 @@
#--------------------------------------------------------------------
# Line endings
#--------------------------------------------------------------------
# Source code - always LF
*.zig text eol=lf
*.c text eol=lf
*.h text eol=lf
*.cpp text eol=lf
*.m text eol=lf
*.swift text eol=lf
*.py text eol=lf
*.sh text eol=lf
*.glsl text eol=lf
*.blp text eol=lf
# Config/build files - always LF
*.zon text eol=lf
*.nix text eol=lf
*.md text eol=lf
*.json text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.toml text eol=lf
CMakeLists.txt text eol=lf
*.cmake text eol=lf
Makefile text eol=lf
# Text data files - always LF (embedded in Zig, parsed with \n split)
*.txt text eol=lf
# Windows resource files - preserve as-is (native Windows tooling)
*.rc -text
*.manifest -text
# Binary files
*.png binary
*.ico binary
*.icns binary
*.ttf binary
*.otf binary
#--------------------------------------------------------------------
# Linguist
#--------------------------------------------------------------------
build.zig.zon.nix linguist-generated=true
build.zig.zon.txt linguist-generated=true
build.zig.zon.json linguist-generated=true

104
.github/VOUCHED.td vendored
View File

@ -19,256 +19,152 @@
# discussion by the author. Maintainers can denounce users by commenting
# "!denounce" or "!denounce [username]" on a discussion.
00-kat
007hacky007
00jciv00
04cb
0xdvc
-4rh1t3ct0r7
52dyd
aalhendi
aaron-ang
abdurrahmanski
abudvytis
adrum
agoodkind
aindriu80
ajiblock
akimiojr
alaasdk
alanmoyano
alaviss
alexfeijoo44
alexjuca
alosarjos
amadeus
andrejdaskalov
anhthang
anmitalidev
anthonyzhoon
athaapa
atomk
b0uks
b1nar10
balazs-szucs
barutsrb
bch
bennettp123
benodiwal
bernsno
beryesa
bitigchi
bkircher
bleikurr
bo2themax
brentschroeter
brianc442
c0x0o
cespare
charliie-dev
chernetskyi
chronologos
cmwetherell
crayxt
craziestowl
curtismoncoq
-cznorth Automated advertising + likely AI communication
d-dudas
-daedaevibin
daiimus
damyanbogoev
danneu
danulqua
dariogriffo
davidsanchez222
deblasis
dervedro
devsunb
diaaeddin
dkinzler
dmehala
dobbylee
doprz
douglance
douglas
douglas-macgregor
drepper
dzhlobo
ekaterinepapava
elias8
-enkr1
enzowilliam
ephemera
-eric-assetpass Try talking, not botting
eriksremess
erral
-f1813483-netizen
faukah
filip7
flou
fornwall
francescarpi
fru1tworld
gagbo
ghokun
gmile
gordonbondon
gpanders
guilhermetk
h3nock
hakonhagland
halosatrio
heaths
heddxh heddxh
-highimpact-dev Disrespectful AI user
hlcfan
hqnna
hulet
i999rri
icodesign
illiakrauchanka
j0hnm4r5
jacobsandlund
jake-stewart
jamylak
jarred-sumner
jcollie
jesusvazquez
jguthmiller
jmcgover
jmr
johnslavik
jordandm
josephmart
jparise
juniqlim
justonia
karesansui-u
kataokatsuki
kawarimidoll
kayleung
kenvandine
khipp
kierancanter
kirwiisp
kjvdven
kloneets
knu
-kody-w
koranir
kristina8888
kristofersoler
kylesower
laxystem
lebdron
lepips
liby
linustalacko
lonsagisawa
louisunlimited
luisnquin
lynicis
mac0ne
mahnokropotkinvich
marijagjorgjieva
markdorison
markhuot
marler8997
marrocco-simone
masterflitzer
matkotiric
mattn
micaeljarniac
michielvk
miguelelgallo
mihi314
mikailmm
minorcell
misairuzame
mischief
mitchellh
miupa
mjbommar
mohshami
molechowski
moonmao42
-morgengeluk Appears to be using AI inappropriately even after it was requested they abide by the AI policy (there is clear evidence of the person-in-the-loop not attempting to clean up AI generated text, and their AI disclosure itself reads like AI-generated text and shows no signs of remorse or intent to improve).
mpatankar6
mrconnorkenway
mrmage
mtak
natesmyth
neo773
neurosnap
nicholas-ochoa
nicosuave
nikicat
nmggithub
noib3
nolinmcfarland
nouritsu
nwehg
ocean6954
oshdubh
otomn
paaloeye
pan93412
pangoraw
pauley-unsaturated
peilingjiang
peterdavehello
philocalyst
phush0
piedrahitac
pluiedev
pouwerkerk
poweruser64
prakhar54-byte
priyans-hu
puzza007
qwerasd205
raphamorim
reo101
rewdy
rgehan
rhodes-b
rightaditya
rjwittams
rmengelbrecht
rmunn
rockorager
rpfaeffle
samasaur1
sandydoo
secrus
seruman
seyoungjeong
silveirapf
slsrepo
sunshine-syz
tbrundige
tdgroot
tdslot
thirstycrow
thoutbeckers
ticclick
tnagatomi
trag1c
tristan957
turbolent
tweedbeetle
uhojin
unphased
uzaaft
vancluever
vaughanandrews
viruslobster
vlsi
voidnv
wyounas
yabbal
yamshta
ydah
-zaviro
zenyr
zeshi09
zubb

View File

@ -1,5 +0,0 @@
Hi @{author}, thanks for your interest!
Non-maintainers are not allowed to create issues in this repository — we ask that you create a discussion first. For more details on the why, see #3558 and our [CONTRIBUTING.md](https://github.com/ghostty-org/ghostty/blob/main/CONTRIBUTING.md).
This issue will be closed automatically.

View File

@ -41,7 +41,7 @@ jobs:
mkdir dist
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
- uses: flatpak/flatpak-github-actions/flatpak-builder@401fe28a8384095fc1531b9d320b292f0ee45adb # v6.7
- uses: flatpak/flatpak-github-actions/flatpak-builder@92ae9851ad316786193b1fd3f40c4b51eb5cb101 # v6.6
with:
bundle: com.mitchellh.ghostty
manifest-path: dist/flatpak/com.mitchellh.ghostty.yml

View File

@ -11,9 +11,6 @@ on:
jobs:
update-milestone:
# Ignore bot-authored pull requests (dependabot, app bots, etc)
# and CI-only PRs.
if: github.event_name == 'issues' || (github.event.pull_request.user.type != 'Bot' && !startsWith(github.event.pull_request.title, 'ci:'))
runs-on: namespace-profile-ghostty-sm
name: Milestone Update
steps:

View File

@ -39,18 +39,18 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix
/zig
- name: Setup Nix
uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"

View File

@ -56,7 +56,7 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Important so that build number generation works
fetch-depth: 0
@ -80,20 +80,20 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
- uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -113,7 +113,7 @@ jobs:
nix develop -c minisign -S -m "ghostty-source.tar.gz" -s minisign.key < minisign.password
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: source-tarball
path: |-
@ -134,10 +134,10 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
cache: |
xcode
@ -147,13 +147,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main
with:
determinate: true
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.3.app
run: sudo xcode-select -s /Applications/Xcode_26.2.app
- name: Xcode Version
run: xcodebuild -version
@ -282,7 +282,7 @@ jobs:
zip -9 -r --symlinks ../../../ghostty-macos-universal-dsym.zip Ghostty.app.dSYM/
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: macos
path: |-
@ -319,7 +319,7 @@ jobs:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download macOS Artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
@ -353,7 +353,7 @@ jobs:
mv appcast_new.xml appcast.xml
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: sparkle
path: |-

View File

@ -33,19 +33,19 @@ jobs:
commit: ${{ steps.extract_build_info.outputs.commit }}
commit_long: ${{ steps.extract_build_info.outputs.commit_long }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Important so that build number generation works
fetch-depth: 0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
- uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -75,7 +75,7 @@ jobs:
needs: [setup, build-macos]
if: needs.setup.outputs.should_skip != 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Tip Tag
run: |
git config user.name "github-actions[bot]"
@ -90,7 +90,7 @@ jobs:
env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install sentry-cli
run: |
@ -113,7 +113,7 @@ jobs:
env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install sentry-cli
run: |
@ -136,7 +136,7 @@ jobs:
env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install sentry-cli
run: |
@ -163,22 +163,22 @@ jobs:
github.ref_name == 'main'
)
)
runs-on: namespace-profile-ghostty-sm
runs-on: namespace-profile-ghostty-md
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
- uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -195,7 +195,7 @@ jobs:
nix develop -c minisign -S -m ghostty-source.tar.gz -s minisign.key < minisign.password
- name: Update Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
@ -206,165 +206,6 @@ jobs:
ghostty-source.tar.gz.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }}
source-tarball-lib-vt:
needs: [setup]
if: |
needs.setup.outputs.should_skip != 'true' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.repository_owner == 'ghostty-org' &&
github.ref_name == 'main'
)
)
runs-on: namespace-profile-ghostty-sm
env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Create Tarball
run: |
rm -rf zig-out/dist
nix develop -c zig build dist -Demit-lib-vt=true
cp zig-out/dist/*.tar.gz libghostty-vt-source.tar.gz
- name: Sign Tarball
run: |
echo -n "${{ secrets.MINISIGN_KEY }}" > minisign.key
echo -n "${{ secrets.MINISIGN_PASSWORD }}" > minisign.password
nix develop -c minisign -S -m libghostty-vt-source.tar.gz -s minisign.key < minisign.password
- name: Update Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
tag_name: tip
target_commitish: ${{ github.sha }}
files: |
libghostty-vt-source.tar.gz
libghostty-vt-source.tar.gz.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }}
- name: Prep R2 Storage
run: |
mkdir -p blob/${GHOSTTY_COMMIT_LONG}
cp libghostty-vt-source.tar.gz blob/${GHOSTTY_COMMIT_LONG}/libghostty-vt-source.tar.gz
- name: Upload to R2
uses: ryand56/r2-upload-action@b801a390acbdeb034c5e684ff5e1361c06639e7c # v1.4
with:
r2-account-id: ${{ secrets.CF_R2_TIP_ACCOUNT_ID }}
r2-access-key-id: ${{ secrets.CF_R2_TIP_AWS_KEY }}
r2-secret-access-key: ${{ secrets.CF_R2_TIP_SECRET_KEY }}
r2-bucket: ghostty-tip
source-dir: blob
destination-dir: ./
- name: Echo Release URLs
run: |
echo "Release URLs:"
echo " Source Tarball: https://tip.files.ghostty.org/${GHOSTTY_COMMIT_LONG}/libghostty-vt-source.tar.gz"
build-lib-vt-xcframework:
needs: [setup]
if: |
needs.setup.outputs.should_skip != 'true' &&
(
github.event_name == 'workflow_dispatch' ||
(
github.repository_owner == 'ghostty-org' &&
github.ref_name == 'main'
)
)
runs-on: namespace-profile-ghostty-macos-tahoe
env:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
ZIG_LOCAL_CACHE_DIR: /Users/runner/zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
with:
cache: |
xcode
path: |
/Users/runner/zig
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
with:
determinate: true
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Xcode Select
run: sudo xcode-select -s /Applications/Xcode_26.3.app
- name: Build XCFramework
run: nix develop -c zig build -Demit-lib-vt -Doptimize=ReleaseFast
- name: Zip XCFramework
run: |
cd zig-out/lib
zip -9 -r ../../ghostty-vt.xcframework.zip ghostty-vt.xcframework
- name: Sign XCFramework
run: |
echo -n "${{ secrets.MINISIGN_KEY }}" > minisign.key
echo -n "${{ secrets.MINISIGN_PASSWORD }}" > minisign.password
nix develop -c minisign -S -m ghostty-vt.xcframework.zip -s minisign.key < minisign.password
- name: Update Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
tag_name: tip
target_commitish: ${{ github.sha }}
files: |
ghostty-vt.xcframework.zip
ghostty-vt.xcframework.zip.minisig
token: ${{ secrets.GH_RELEASE_TOKEN }}
- name: Prep R2 Storage
run: |
mkdir -p blob/${GHOSTTY_COMMIT_LONG}
cp ghostty-vt.xcframework.zip blob/${GHOSTTY_COMMIT_LONG}/ghostty-vt.xcframework.zip
- name: Upload to R2
uses: ryand56/r2-upload-action@b801a390acbdeb034c5e684ff5e1361c06639e7c # v1.4
with:
r2-account-id: ${{ secrets.CF_R2_TIP_ACCOUNT_ID }}
r2-access-key-id: ${{ secrets.CF_R2_TIP_AWS_KEY }}
r2-secret-access-key: ${{ secrets.CF_R2_TIP_SECRET_KEY }}
r2-bucket: ghostty-tip
source-dir: blob
destination-dir: ./
- name: Echo Release URLs
run: |
echo "Release URLs:"
echo " XCFramework: https://tip.files.ghostty.org/${GHOSTTY_COMMIT_LONG}/ghostty-vt.xcframework.zip"
build-macos:
needs: [setup]
if: |
@ -387,13 +228,13 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Important so that build number generation works
fetch-depth: 0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
cache: |
xcode
@ -404,13 +245,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main
with:
determinate: true
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.3.app
run: sudo xcode-select -s /Applications/Xcode_26.2.app
- name: Xcode Version
run: xcodebuild -version
@ -537,7 +378,7 @@ jobs:
# Update Release
- name: Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
@ -615,7 +456,7 @@ jobs:
EOF
- name: Upload Release URLs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v6.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0
with:
name: release-urls-${{ inputs.pr || '0' }}
path: release-urls.txt
@ -643,13 +484,13 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Important so that build number generation works
fetch-depth: 0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
cache: |
xcode
@ -660,13 +501,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main
with:
determinate: true
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.3.app
run: sudo xcode-select -s /Applications/Xcode_26.2.app
- name: Xcode Version
run: xcodebuild -version
@ -786,7 +627,7 @@ jobs:
# Update Release
- name: Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
@ -840,13 +681,13 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /Users/runner/zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Important so that build number generation works
fetch-depth: 0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
cache: |
xcode
@ -857,13 +698,13 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main
with:
determinate: true
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_26.3.app
run: sudo xcode-select -s /Applications/Xcode_26.2.app
- name: Xcode Version
run: xcodebuild -version
@ -983,7 +824,7 @@ jobs:
# Update Release
- name: Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true

View File

@ -38,7 +38,7 @@ jobs:
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix

File diff suppressed because it is too large Load Diff

View File

@ -17,22 +17,22 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
with:
path: |
/nix
/zig
- name: Setup Nix
uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1 # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@ -79,7 +79,7 @@ jobs:
run: nix build .#ghostty
- name: Create pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
with:
title: Update iTerm2 colorschemes
base: main

View File

@ -8,21 +8,15 @@ jobs:
check:
runs-on: namespace-profile-ghostty-xsm
steps:
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout: .github/issue-unvouched-message
- uses: mitchellh/vouch/action/check-issue@52aec3d64655edf2fdb58f298e02da754a056daf # unreleased main
- uses: mitchellh/vouch/action/check-issue@c6d80ead49839655b61b422700b7a3bc9d0804a9 # v1.4.2
with:
issue-number: ${{ github.event.issue.number }}
auto-close: true
auto-lock: true
template-file: .github/issue-unvouched-message
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}

View File

@ -8,7 +8,7 @@ jobs:
check:
runs-on: namespace-profile-ghostty-xsm
steps:
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ secrets.VOUCH_APP_ID }}

View File

@ -12,13 +12,13 @@ jobs:
manage:
runs-on: namespace-profile-ghostty-xsm
steps:
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ steps.app-token.outputs.token }}

View File

@ -12,13 +12,13 @@ jobs:
manage:
runs-on: namespace-profile-ghostty-xsm
steps:
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ steps.app-token.outputs.token }}

View File

@ -13,13 +13,13 @@ jobs:
sync:
runs-on: namespace-profile-ghostty-xsm
steps:
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ secrets.VOUCH_APP_ID }}
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ steps.app-token.outputs.token }}

3
.gitignore vendored
View File

@ -10,9 +10,6 @@
zig-cache/
.zig-cache/
zig-out/
build-cmake/
CMakeCache.txt
CMakeFiles/
/build.zig.zon.bak
/result*
/.nixos-test-history

View File

@ -26,6 +26,3 @@ website/.next
# fuzz corpus files
test/fuzz-libghostty/corpus/
test/fuzz-libghostty/afl-out/
# Swift example build outputs
example/swift-vt-xcframework/.build/

View File

@ -16,15 +16,6 @@ A file for [guiding coding agents](https://agents.md/).
- **Formatting (Swift)**: `swiftlint lint --strict --fix`
- **Formatting (other)**: `prettier -w .`
## libghostty-vt
- Build: `zig build -Demit-lib-vt`
- Build WASM: `zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall`
- Test: `zig build test-lib-vt -Dtest-filter=<filter>`
- Prefer this when the change is in a libghostty-vt file
- All C enums in `include/ghostty/vt/` must have a `_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE`
sentinel as the last entry to force int enum sizing (pre-C23 portability).
## Directory Structure
- Shared Zig core: `src/`

View File

@ -1 +0,0 @@
AGENTS.md

View File

@ -1,377 +0,0 @@
# CMake wrapper for libghostty-vt
#
# This file delegates to `zig build -Demit-lib-vt` to produce the shared library,
# headers, and pkg-config file. It exists so that CMake-based projects can
# consume libghostty-vt without interacting with the Zig build system
# directly. However, downstream users do still require `zig` on the PATH.
# Please consult the Ghostty docs for the required Zig version:
#
# https://ghostty.org/docs/install/build
#
# Building within the Ghostty repo
# ---------------------------------
#
# cmake -B build
# cmake --build build
# cmake --install build --prefix /usr/local
#
# Pass extra flags to the Zig build with GHOSTTY_ZIG_BUILD_FLAGS:
#
# cmake -B build -DGHOSTTY_ZIG_BUILD_FLAGS="-Demit-macos-app=false"
#
# Integrating into a downstream CMake project
# ---------------------------------------------
#
# Option 1 FetchContent (recommended, no manual install step):
#
# include(FetchContent)
# FetchContent_Declare(ghostty
# GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
# GIT_TAG main
# )
# FetchContent_MakeAvailable(ghostty)
#
# target_link_libraries(myapp PRIVATE ghostty-vt) # shared
# target_link_libraries(myapp PRIVATE ghostty-vt-static) # static
#
# To use a local checkout instead of fetching:
#
# cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=/path/to/ghostty
#
# Option 2 find_package (after installing to a prefix):
#
# find_package(ghostty-vt REQUIRED)
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt) # shared
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt-static) # static
#
# Cross-compilation
# -------------------
#
# For building libghostty-vt for a non-native Zig target (e.g. cross-
# compiling), use the ghostty_vt_add_target() function after FetchContent:
#
# FetchContent_MakeAvailable(ghostty)
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
#
# target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64) # static
# target_link_libraries(myapp PRIVATE ghostty-vt-linux-amd64) # shared
#
# This handles zig discovery, build-type-to-optimize mapping, and output
# path conventions internally. Extra flags can be forwarded with ZIG_FLAGS:
#
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu
# ZIG_FLAGS -Dsimd=false)
#
# See dist/cmake/README.md for more details, example/c-vt-cmake/ for a
# complete working example, and example/c-vt-cmake-cross/ for a cross-
# compilation example.
cmake_minimum_required(VERSION 3.19)
project(ghostty-vt VERSION 0.1.0 LANGUAGES C)
# --- Options ----------------------------------------------------------------
set(GHOSTTY_ZIG_BUILD_FLAGS "" CACHE STRING "Additional flags to pass to zig build")
# Map CMake build types to Zig optimization levels. The result is stored in
# _GHOSTTY_ZIG_OPT_FLAG so both the native build and ghostty_vt_add_target()
# can reuse it without duplicating the mapping logic.
set(_GHOSTTY_ZIG_OPT_FLAG "")
if(CMAKE_BUILD_TYPE)
string(TOUPPER "${CMAKE_BUILD_TYPE}" _bt)
if(_bt STREQUAL "RELEASE" OR _bt STREQUAL "MINSIZEREL" OR _bt STREQUAL "RELWITHDEBINFO")
set(_GHOSTTY_ZIG_OPT_FLAG "-Doptimize=ReleaseFast")
endif()
unset(_bt)
endif()
if(_GHOSTTY_ZIG_OPT_FLAG)
list(APPEND GHOSTTY_ZIG_BUILD_FLAGS "${_GHOSTTY_ZIG_OPT_FLAG}")
endif()
# --- Find Zig ----------------------------------------------------------------
find_program(ZIG_EXECUTABLE zig REQUIRED)
message(STATUS "Found zig: ${ZIG_EXECUTABLE}")
# --- Build via zig build -----------------------------------------------------
# The zig build installs into zig-out/ relative to the source tree.
set(ZIG_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zig-out")
# Shared library names (zig build produces both shared and static).
if(APPLE)
set(GHOSTTY_VT_LIBNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(GHOSTTY_VT_SONAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt.0${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(GHOSTTY_VT_REALNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt.0.1.0${CMAKE_SHARED_LIBRARY_SUFFIX}")
elseif(WIN32)
set(GHOSTTY_VT_LIBNAME "ghostty-vt.dll")
set(GHOSTTY_VT_REALNAME "ghostty-vt.dll")
set(GHOSTTY_VT_IMPLIB "ghostty-vt.lib")
else()
set(GHOSTTY_VT_LIBNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(GHOSTTY_VT_SONAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}.0")
set(GHOSTTY_VT_REALNAME "${CMAKE_SHARED_LIBRARY_PREFIX}ghostty-vt${CMAKE_SHARED_LIBRARY_SUFFIX}.0.1.0")
endif()
if(WIN32)
set(GHOSTTY_VT_SHARED_LIBRARY "${ZIG_OUT_DIR}/bin/${GHOSTTY_VT_REALNAME}")
else()
set(GHOSTTY_VT_SHARED_LIBRARY "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_REALNAME}")
endif()
# Static library name.
# On Windows, the static lib is named "ghostty-vt-static.lib" to avoid
# colliding with the DLL import library "ghostty-vt.lib".
if(WIN32)
set(GHOSTTY_VT_STATIC_REALNAME "ghostty-vt-static.lib")
else()
set(GHOSTTY_VT_STATIC_REALNAME "libghostty-vt.a")
endif()
set(GHOSTTY_VT_STATIC_LIBRARY "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_STATIC_REALNAME}")
# Ensure the output directories exist so CMake doesn't reject the
# INTERFACE_INCLUDE_DIRECTORIES before the zig build has run.
file(MAKE_DIRECTORY "${ZIG_OUT_DIR}/include")
# Custom command: run zig build -Demit-lib-vt (produces both shared and static)
add_custom_command(
OUTPUT "${GHOSTTY_VT_SHARED_LIBRARY}" "${GHOSTTY_VT_STATIC_LIBRARY}" "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_IMPLIB}"
COMMAND "${ZIG_EXECUTABLE}" build -Demit-lib-vt ${GHOSTTY_ZIG_BUILD_FLAGS}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Building libghostty-vt via zig build..."
USES_TERMINAL
)
add_custom_target(zig_build_lib_vt ALL
DEPENDS "${GHOSTTY_VT_SHARED_LIBRARY}" "${GHOSTTY_VT_STATIC_LIBRARY}"
)
# Tell CMake's clean target to also remove Zig's output directory.
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_CLEAN_FILES "${ZIG_OUT_DIR}"
)
# --- IMPORTED library targets ------------------------------------------------
# Shared
add_library(ghostty-vt SHARED IMPORTED GLOBAL)
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_LOCATION "${GHOSTTY_VT_SHARED_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${ZIG_OUT_DIR}/include"
)
if(APPLE)
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_SONAME "@rpath/${GHOSTTY_VT_SONAME}"
)
elseif(WIN32)
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_IMPLIB "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_IMPLIB}"
)
else()
set_target_properties(ghostty-vt PROPERTIES
IMPORTED_SONAME "${GHOSTTY_VT_SONAME}"
)
endif()
add_dependencies(ghostty-vt zig_build_lib_vt)
# Static
#
# On Linux and macOS, the static library is a fat archive that bundles
# the vendored SIMD dependencies (highway, simdutf). Consumers
# only need to link libc.
#
# On Windows, the SIMD dependencies are not bundled and must be linked
# separately.
#
# Building with -Dsimd=false removes all runtime dependencies.
add_library(ghostty-vt-static STATIC IMPORTED GLOBAL)
set_target_properties(ghostty-vt-static PROPERTIES
IMPORTED_LOCATION "${GHOSTTY_VT_STATIC_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${ZIG_OUT_DIR}/include"
INTERFACE_COMPILE_DEFINITIONS "GHOSTTY_STATIC"
)
if(WIN32)
# On Windows, the Zig standard library uses NT API functions
# (NtClose, NtCreateSection, etc.) and kernel32 functions that
# consumers must link when using the static library.
set_target_properties(ghostty-vt-static PROPERTIES
INTERFACE_LINK_LIBRARIES "ntdll;kernel32"
)
endif()
add_dependencies(ghostty-vt-static zig_build_lib_vt)
# --- Install ------------------------------------------------------------------
include(GNUInstallDirs)
# Install shared library
if(WIN32)
# On Windows, install the DLL and PDB to bin/ and the import library to lib/
install(FILES "${GHOSTTY_VT_SHARED_LIBRARY}" "${ZIG_OUT_DIR}/bin/ghostty-vt.pdb" TYPE BIN)
install(FILES "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_IMPLIB}" TYPE LIB)
else()
install(FILES "${GHOSTTY_VT_SHARED_LIBRARY}" TYPE LIB)
# Install symlinks
install(CODE "
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
\"${GHOSTTY_VT_REALNAME}\"
\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${GHOSTTY_VT_SONAME}\")
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
\"${GHOSTTY_VT_SONAME}\"
\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${GHOSTTY_VT_LIBNAME}\")
")
endif()
# Install static library
install(FILES "${GHOSTTY_VT_STATIC_LIBRARY}" TYPE LIB)
# Install headers
install(DIRECTORY "${ZIG_OUT_DIR}/include/ghostty" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
# --- CMake package config for find_package() ----------------------------------
include(CMakePackageConfigHelpers)
# Generate the config file
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/dist/cmake/ghostty-vt-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghostty-vt"
)
# Generate the version file
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config-version.cmake"
VERSION "${PROJECT_VERSION}"
COMPATIBILITY SameMajorVersion
)
# Install the config files
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/ghostty-vt-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghostty-vt"
)
# --- Cross-compilation helper ------------------------------------------------
#
# For downstream projects that need to build libghostty-vt for a specific
# Zig target triple. For native builds, use the IMPORTED targets above
# (ghostty-vt, ghostty-vt-static) directly.
#
# Usage (in a downstream CMakeLists.txt after FetchContent_MakeAvailable):
#
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
#
# Creates:
# ghostty-vt-static-linux-amd64 (IMPORTED STATIC library)
# ghostty-vt-linux-amd64 (IMPORTED SHARED library)
#
# Optional ZIG_FLAGS to pass additional flags to zig build:
#
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu
# ZIG_FLAGS -Dsimd=false)
function(ghostty_vt_add_target)
cmake_parse_arguments(PARSE_ARGV 0 _GVT "" "NAME;ZIG_TARGET" "ZIG_FLAGS")
if(NOT _GVT_NAME)
message(FATAL_ERROR "ghostty_vt_add_target: NAME is required")
endif()
if(NOT _GVT_ZIG_TARGET)
message(FATAL_ERROR "ghostty_vt_add_target: ZIG_TARGET is required")
endif()
set(_src_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}")
set(_prefix "${CMAKE_CURRENT_BINARY_DIR}/ghostty-${_GVT_NAME}")
# Build flags
set(_flags
-Demit-lib-vt
-Dtarget=${_GVT_ZIG_TARGET}
--prefix "${_prefix}"
)
# Default to ReleaseFast when no build type is set. Debug builds enable
# UBSan in zig, and the sanitizer runtime is not available for all
# cross-compilation targets.
if(_GHOSTTY_ZIG_OPT_FLAG)
list(APPEND _flags "${_GHOSTTY_ZIG_OPT_FLAG}")
else()
list(APPEND _flags "-Doptimize=ReleaseFast")
endif()
if(_GVT_ZIG_FLAGS)
list(APPEND _flags ${_GVT_ZIG_FLAGS})
endif()
# Output paths
set(_include_dir "${_prefix}/include")
if(_GVT_ZIG_TARGET MATCHES "windows")
set(_static_lib "${_prefix}/lib/ghostty-vt-static.lib")
set(_shared_lib "${_prefix}/bin/ghostty-vt.dll")
set(_implib "${_prefix}/lib/ghostty-vt.lib")
elseif(_GVT_ZIG_TARGET MATCHES "darwin|macos")
set(_static_lib "${_prefix}/lib/libghostty-vt.a")
set(_shared_lib "${_prefix}/lib/libghostty-vt.0.1.0.dylib")
else()
set(_static_lib "${_prefix}/lib/libghostty-vt.a")
set(_shared_lib "${_prefix}/lib/libghostty-vt.so.0.1.0")
endif()
file(MAKE_DIRECTORY "${_include_dir}")
# Custom command: invoke zig build
add_custom_command(
OUTPUT "${_static_lib}" "${_shared_lib}"
COMMAND "${ZIG_EXECUTABLE}" build ${_flags}
WORKING_DIRECTORY "${_src_dir}"
COMMENT "Building libghostty-vt for ${_GVT_ZIG_TARGET}..."
USES_TERMINAL
)
set(_build_target "zig_build_lib_vt_${_GVT_NAME}")
add_custom_target(${_build_target} ALL
DEPENDS "${_static_lib}" "${_shared_lib}"
)
# Static target
set(_static_target "ghostty-vt-static-${_GVT_NAME}")
add_library(${_static_target} STATIC IMPORTED GLOBAL)
set_target_properties(${_static_target} PROPERTIES
IMPORTED_LOCATION "${_static_lib}"
INTERFACE_INCLUDE_DIRECTORIES "${_include_dir}"
INTERFACE_COMPILE_DEFINITIONS "GHOSTTY_STATIC"
)
if(_GVT_ZIG_TARGET MATCHES "windows")
set_target_properties(${_static_target} PROPERTIES
INTERFACE_LINK_LIBRARIES "ntdll;kernel32"
)
endif()
add_dependencies(${_static_target} ${_build_target})
# Shared target
set(_shared_target "ghostty-vt-${_GVT_NAME}")
add_library(${_shared_target} SHARED IMPORTED GLOBAL)
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_LOCATION "${_shared_lib}"
INTERFACE_INCLUDE_DIRECTORIES "${_include_dir}"
)
if(_GVT_ZIG_TARGET MATCHES "windows")
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_IMPLIB "${_implib}"
)
elseif(_GVT_ZIG_TARGET MATCHES "darwin|macos")
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_SONAME "@rpath/libghostty-vt.0.dylib"
)
else()
set_target_properties(${_shared_target} PROPERTIES
IMPORTED_SONAME "libghostty-vt.so.0"
)
endif()
add_dependencies(${_shared_target} ${_build_target})
endfunction()

View File

@ -162,17 +162,14 @@
/src/surface_mouse.zig @ghostty-org/terminal
# Localization
/po/README_TRANSLATORS.md @ghostty-org/manager # *localization* manager.
/po/com.mitchellh.ghostty.pot @ghostty-org/manager
/src/os/i18n_locales.zig @ghostty-org/manager
/po/be.po @ghostty-org/be_BY
/po/README_TRANSLATORS.md @ghostty-org/localization
/po/com.mitchellh.ghostty.pot @ghostty-org/localization
/po/bg.po @ghostty-org/bg_BG
/po/ca.po @ghostty-org/ca_ES
/po/de.po @ghostty-org/de_DE
/po/es_AR.po @ghostty-org/es_AR
/po/es_BO.po @ghostty-org/es_BO
/po/es_ES.po @ghostty-org/es_ES
/po/eu.po @ghostty-org/eu_ES
/po/fr.po @ghostty-org/fr_FR
/po/ga.po @ghostty-org/ga_IE
/po/he.po @ghostty-org/he_IL

View File

@ -177,6 +177,11 @@ item is identified, it is moved to the issue tracker. **This pattern
makes it easier for maintainers or contributors to find issues to work on
since _every issue_ is ready to be worked on.**
If you are experiencing a bug and have clear steps to reproduce it, please
open an issue. If you are experiencing a bug but you are not sure how to
reproduce it or aren't sure if it's a bug, please open a discussion.
If you have an idea for a feature, please open a discussion.
### Pull Requests Implement an Issue
Pull requests should be associated with a previously accepted issue.

View File

@ -67,14 +67,6 @@ sudo xcode-select --switch /Applications/Xcode.app
> You do not need to be running on macOS 26 to build Ghostty, you can
> still use Xcode 26 on macOS 15 stable.
> [!WARNING]
>
> Zig 0.15.x has a [known linking issue](https://codeberg.org/ziglang/zig/issues/31658)
> with **Xcode 26.4**. If you are on Xcode 26.4, you must use a
> Homebrew-installed Zig (`brew install zig@0.15`) or our Nix flake,
> both of which contain a patch that works around the issue. Alternatively,
> you can downgrade to **Xcode 26.3**.
## AI and Agents
If you're using AI assistance with Ghostty, Ghostty provides an

145
README.md
View File

@ -7,8 +7,6 @@
<p align="center">
Fast, native, feature-rich terminal emulator pushing modern features.
<br />
A native GUI or embeddable library via <code>libghostty</code>.
<br />
<a href="#about">About</a>
·
<a href="https://ghostty.org/download">Download</a>
@ -28,13 +26,20 @@ fast, feature-rich, and native. While there are many excellent terminal
emulators available, they all force you to choose between speed,
features, or native UIs. Ghostty provides all three.
**`libghostty`** is a cross-platform, zero-dependency C and Zig library
for building terminal emulators or utilizing terminal functionality
(such as style parsing). Anyone can use `libghostty` to build a terminal
emulator or embed a terminal into their own applications. See
[Ghostling](https://github.com/ghostty-org/ghostling) for a minimal complete project
example or the [`examples` directory](https://github.com/ghostty-org/ghostty/tree/main/example)
for smaller examples of using `libghostty` in C and Zig.
In all categories, I am not trying to claim that Ghostty is the
best (i.e. the fastest, most feature-rich, or most native). But
Ghostty is competitive in all three categories and Ghostty
doesn't make you choose between them.
Ghostty also intends to push the boundaries of what is possible with a
terminal emulator by exposing modern, opt-in features that enable CLI tool
developers to build more feature rich, interactive applications.
While aiming for this ambitious goal, our first step is to make Ghostty
one of the best fully standards compliant terminal emulator, remaining
compatible with all existing shells and software while supporting all of
the latest terminal innovations in the ecosystem. You can use Ghostty
as a drop-in replacement for your existing terminal emulator.
For more details, see [About Ghostty](https://ghostty.org/docs/about).
@ -56,37 +61,30 @@ to get involved with Ghostty's development as well should also read the
## Roadmap and Status
Ghostty is stable and in use by millions of people and machines daily.
The high-level ambitious plan for the project, in order:
| # | Step | Status |
| :-: | ------------------------------------------------------- | :----: |
| 1 | Standards-compliant terminal emulation | ✅ |
| 2 | Competitive performance | ✅ |
| 3 | Rich windowing features -- multi-window, tabbing, panes | ✅ |
| 4 | Native Platform Experiences | ✅ |
| 5 | Cross-platform `libghostty` for Embeddable Terminals | ✅ |
| 6 | Ghostty-only Terminal Control Sequences | ❌ |
| # | Step | Status |
| :-: | --------------------------------------------------------- | :----: |
| 1 | Standards-compliant terminal emulation | ✅ |
| 2 | Competitive performance | ✅ |
| 3 | Basic customizability -- fonts, bg colors, etc. | ✅ |
| 4 | Richer windowing features -- multi-window, tabbing, panes | ✅ |
| 5 | Native Platform Experiences (i.e. Mac Preference Panel) | ⚠️ |
| 6 | Cross-platform `libghostty` for Embeddable Terminals | ⚠️ |
| 7 | Windows Terminals (including PowerShell, Cmd, WSL) | ❌ |
| N | Fancy features (to be expanded upon later) | ❌ |
Additional details for each step in the big roadmap below:
#### Standards-Compliant Terminal Emulation
Ghostty implements all of the regularly used control sequences and
can run every mainstream terminal program without issue. For legacy sequences,
we've done a [comprehensive xterm audit](https://github.com/ghostty-org/ghostty/issues/632)
Ghostty implements enough control sequences to be used by hundreds of
testers daily for over the past year. Further, we've done a
[comprehensive xterm audit](https://github.com/ghostty-org/ghostty/issues/632)
comparing Ghostty's behavior to xterm and building a set of conformance
test cases.
In addition to legacy sequences (what you'd call real "terminal" emulation),
Ghostty also supports more modern sequences than almost any other terminal
emulator. These features include things like the Kitty graphics protocol,
Kitty image protocol, clipboard sequences, synchronized rendering,
light/dark mode notifications, and many, many more.
We believe Ghostty is one of the most compliant and feature-rich terminal
emulators available.
We believe Ghostty is one of the most compliant terminal emulators available.
Terminal behavior is partially a de jure standard
(i.e. [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/))
@ -98,30 +96,33 @@ views as a "standard."
#### Competitive Performance
Ghostty is generally in the same performance category as the other highest
performing terminal emulators.
We need better benchmarks to continuously verify this, but Ghostty is
generally in the same performance category as the other highest performing
terminal emulators.
"The same performance category" means that Ghostty is much faster than
traditional or "slow" terminals and is within an unnoticeable margin of the
well-known "fast" terminals. For example, Ghostty and Alacritty are usually within
a few percentage points of each other on various benchmarks, but are both
something like 100x faster than Terminal.app and iTerm. However, Ghostty
is much more feature rich than Alacritty and has a much more native app
experience.
For rendering, we have a multi-renderer architecture that uses OpenGL on
Linux and Metal on macOS. As far as I'm aware, we're the only terminal
emulator other than iTerm that uses Metal directly. And we're the only
terminal emulator that has a Metal renderer that supports ligatures (iTerm
uses a CPU renderer if ligatures are enabled). We can maintain around 60fps
under heavy load and much more generally -- though the terminal is
usually rendering much lower due to little screen changes.
This performance is achieved through high-level architectural decisions and
low-level optimizations. At a high-level, Ghostty has a multi-threaded
architecture with a dedicated read thread, write thread, and render thread
per terminal. Our renderer uses OpenGL on Linux and Metal on macOS.
Our read thread has a heavily optimized terminal parser that leverages
CPU-specific SIMD instructions. Etc.
For IO, we have a dedicated IO thread that maintains very little jitter
under heavy IO load (i.e. `cat <big file>.txt`). On benchmarks for IO,
we're usually within a small margin of other fast terminal emulators.
For example, reading a dump of plain text is 4x faster compared to iTerm and
Kitty, and 2x faster than Terminal.app. Alacritty is very fast but we're still
around the same speed (give or take) and our app experience is much more
feature rich.
#### Rich Windowing Features
> [!NOTE]
> Despite being _very fast_, there is a lot of room for improvement here.
#### Richer Windowing Features
The Mac and Linux (build with GTK) apps support multi-window, tabbing, and
splits with additional features such as tab renaming, coloring, etc. These
features allow for a higher degree of organization and customization than
single-window terminals.
splits.
#### Native Platform Experiences
@ -132,15 +133,10 @@ in Zig but we do a lot of platform-native things:
- The macOS app is a true SwiftUI-based application with all the things you
would expect such as real windowing, menu bars, a settings GUI, etc.
- macOS uses a true Metal renderer with CoreText for font discovery.
- macOS supports AppleScript, Apple Shortcuts (AppIntents), etc.
- The Linux app is built with GTK.
- The Linux app integrates deeply with systemd if available for things
like always-on, new windows in a single instance, cgroup isolation, etc.
Our goal with Ghostty is for users of whatever platform they run Ghostty
on to think that Ghostty was built for their platform first and maybe even
exclusively. We want Ghostty to feel like a native app on every platform,
for the best definition of "native" on each platform.
There are more improvements to be made. The macOS settings window is still
a work-in-progress. Similar improvements will follow with Linux.
#### Cross-platform `libghostty` for Embeddable Terminals
@ -149,40 +145,21 @@ C-compatible library for embedding a fast, feature-rich terminal emulator
in any 3rd party project. This library is called `libghostty`.
Due to the scope of this project, we're breaking libghostty down into
separate libraries, starting with `libghostty-vt`. The goal of
separate actually libraries, starting with `libghostty-vt`. The goal of
this project is to focus on parsing terminal sequences and maintaining
terminal state. This is covered in more detail in this
[blog post](https://mitchellh.com/writing/libghostty-is-coming).
`libghostty-vt` is already available and usable today for Zig and C and
is compatible for macOS, Linux, Windows, and WebAssembly. The functionality
is extremely stable (since its been proven in Ghostty GUI for a long time),
but the API signatures are still in flux.
is compatible for macOS, Linux, Windows, and WebAssembly. At the time of
writing this, the API isn't stable yet and we haven't tagged an official
release, but the core logic is well proven (since Ghostty uses it) and
we're working hard on it now.
`libghostty` is already heavily in use. See [`examples`](https://github.com/ghostty-org/ghostty/tree/main/example)
for small examples of using `libghostty` in C and Zig or the
[Ghostling](https://github.com/ghostty-org/ghostling) project for a
complete example. See [awesome-libghostty](https://github.com/Uzaaft/awesome-libghostty)
for a list of projects and resources related to `libghostty`.
We haven't tagged libghostty with a version yet and we're still working
on a better docs experience, but our [Doxygen website](https://libghostty.tip.ghostty.org/)
is a good resource for the C API.
#### Ghostty-only Terminal Control Sequences
We want and believe that terminal applications can and should be able
to do so much more. We've worked hard to support a wide variety of modern
sequences created by other terminal emulators towards this end, but we also
want to fill the gaps by creating our own sequences.
We've been hesitant to do this up until now because we don't want to create
more fragmentation in the terminal ecosystem by creating sequences that only
work in Ghostty. But, we do want to balance that with the desire to push the
terminal forward with stagnant standards and the slow pace of change in the
terminal ecosystem.
We haven't done any of this yet.
The ultimate goal is not hypothetical! The macOS app is a `libghostty` consumer.
The macOS app is a native Swift app developed in Xcode and `main()` is
within Swift. The Swift app links to `libghostty` and uses the C API to
render terminals.
## Crash Reports

124
build.zig
View File

@ -3,17 +3,11 @@ const assert = std.debug.assert;
const builtin = @import("builtin");
const buildpkg = @import("src/build/main.zig");
/// App version from build.zig.zon.
const app_zon_version = @import("build.zig.zon").version;
/// Libghostty version. We use a separate version from the app.
const lib_version = "0.1.0-dev";
/// Minimum required zig version.
const minimum_zig_version = @import("build.zig.zon").minimum_zig_version;
const appVersion = @import("build.zig.zon").version;
const minimumZigVersion = @import("build.zig.zon").minimum_zig_version;
comptime {
buildpkg.requireZig(minimum_zig_version);
buildpkg.requireZig(minimumZigVersion);
}
pub fn build(b: *std.Build) !void {
@ -21,24 +15,7 @@ pub fn build(b: *std.Build) !void {
// want to know what options are available, you can run `--help` or
// you can read `src/build/Config.zig`.
// If we have a VERSION file (present in source tarballs) then we
// use that as the version source of truth. Otherwise we fall back
// to what is in the build.zig.zon.
const file_version: ?[]const u8 = if (b.build_root.handle.readFileAlloc(
b.allocator,
"VERSION",
128,
)) |content| std.mem.trim(
u8,
content,
&std.ascii.whitespace,
) else |_| null;
const config = try buildpkg.Config.init(
b,
file_version orelse app_zon_version,
lib_version,
);
const config = try buildpkg.Config.init(b, appVersion);
const test_filters = b.option(
[][]const u8,
"test-filter",
@ -58,6 +35,7 @@ pub fn build(b: *std.Build) !void {
// All our steps which we'll hook up later. The steps are shown
// up here just so that they are more self-documenting.
const libvt_step = b.step("lib-vt", "Build libghostty-vt");
const run_step = b.step("run", "Run the app");
const run_valgrind_step = b.step(
"run-valgrind",
@ -113,6 +91,16 @@ pub fn build(b: *std.Build) !void {
check_step.dependOn(dist.install_step);
}
// libghostty (internal, big)
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
b,
&deps,
);
const libghostty_static = try buildpkg.GhosttyLib.initStatic(
b,
&deps,
);
// libghostty-vt
const libghostty_vt_shared = shared: {
if (config.target.result.cpu.arch.isWasm()) {
@ -127,49 +115,9 @@ pub fn build(b: *std.Build) !void {
&mod,
);
};
libghostty_vt_shared.install(libvt_step);
libghostty_vt_shared.install(b.getInstallStep());
// libghostty-vt static lib
const libghostty_vt_static = try buildpkg.GhosttyLibVt.initStatic(
b,
&mod,
);
if (config.is_dep) {
// If we're a dependency, we need to install everything as-is
// so that dep.artifact("ghostty-vt-static") works.
libghostty_vt_static.install(b.getInstallStep());
} else {
// If we're not a dependency, we rename the static lib to
// be idiomatic. On Windows, we use a distinct name to avoid
// colliding with the DLL import library (ghostty-vt.lib).
const static_lib_name = if (config.target.result.os.tag == .windows)
"ghostty-vt-static.lib"
else
"libghostty-vt.a";
b.getInstallStep().dependOn(&b.addInstallLibFile(
libghostty_vt_static.output,
static_lib_name,
).step);
}
// libghostty-vt xcframework (Apple only, universal binary).
// Only when building on macOS (not cross-compiling) since
// xcodebuild is required.
if (config.emit_lib_vt and
config.emit_xcframework and
builtin.os.tag.isDarwin() and
config.target.result.os.tag.isDarwin())
{
const apple_libs = try buildpkg.GhosttyLibVt.initStaticAppleUniversal(
b,
&config,
&deps,
&mod,
);
const xcframework = buildpkg.GhosttyLibVt.xcframework(&apple_libs, b);
b.getInstallStep().dependOn(xcframework.step);
}
// Helpgen
if (config.emit_helpgen) deps.help_strings.install();
@ -180,35 +128,26 @@ pub fn build(b: *std.Build) !void {
resources.install();
if (i18n) |v| v.install();
}
} else if (!config.emit_lib_vt) {
// The macOS Ghostty Library
} else {
// Libghostty
//
// This is NOT libghostty (even though its named that for historical
// reasons). It is just the glue between Ghostty GUI on macOS and
// the full Ghostty GUI core.
const lib_shared = try buildpkg.GhosttyLib.initShared(b, &deps);
const lib_static = try buildpkg.GhosttyLib.initStatic(b, &deps);
// Note: libghostty is not stable for general purpose use. It is used
// heavily by Ghostty on macOS but it isn't built to be reusable yet.
// As such, these build steps are lacking. For example, the Darwin
// build only produces an xcframework.
// We shouldn't have this guard but we don't currently
// build on macOS this way ironically so we need to fix that.
if (!config.target.result.os.tag.isDarwin()) {
lib_shared.installHeader(); // Only need one header
if (config.target.result.os.tag == .windows) {
lib_shared.install("ghostty-internal.dll");
lib_static.install("ghostty-internal-static.lib");
} else {
lib_shared.install("ghostty-internal.so");
lib_static.install("ghostty-internal.a");
}
libghostty_shared.installHeader(); // Only need one header
libghostty_shared.install("libghostty.so");
libghostty_static.install("libghostty.a");
}
}
// macOS only artifacts. These will error if they're initialized for
// other targets. In lib-vt mode emit_xcframework controls the lib-vt
// xcframework above, not this one.
if (!config.emit_lib_vt and config.target.result.os.tag.isDarwin() and
(config.emit_xcframework or config.emit_macos_app))
{
// other targets.
if (config.target.result.os.tag.isDarwin()) {
// Ghostty xcframework
const xcframework = try buildpkg.GhosttyXCFramework.init(
b,
@ -263,10 +202,7 @@ pub fn build(b: *std.Build) !void {
// On macOS we can run the macOS app. For "run" we always force
// a native-only build so that we can run as quickly as possible.
if (!config.emit_lib_vt and
config.target.result.os.tag.isDarwin() and
(config.emit_xcframework or config.emit_macos_app))
{
if (config.target.result.os.tag.isDarwin()) {
const xcframework_native = try buildpkg.GhosttyXCFramework.init(
b,
&deps,
@ -335,8 +271,8 @@ pub fn build(b: *std.Build) !void {
test_lib_vt_step.dependOn(&mod_vt_c_test_run.step);
}
// Tests (skip when building libghostty-vt)
if (!config.emit_lib_vt) {
// Tests
{
// Full unit tests
const test_exe = b.addTest(.{
.name = "ghostty-test",

View File

@ -1,6 +1,6 @@
.{
.name = .ghostty,
.version = "1.3.2-dev",
.version = "1.3.1",
.paths = .{""},
.fingerprint = 0x64407a2a0b4147e5,
.minimum_zig_version = "0.15.2",
@ -76,6 +76,7 @@
.opengl = .{ .path = "./pkg/opengl", .lazy = true },
.sentry = .{ .path = "./pkg/sentry", .lazy = true },
.simdutf = .{ .path = "./pkg/simdutf", .lazy = true },
.utfcpp = .{ .path = "./pkg/utfcpp", .lazy = true },
.wuffs = .{ .path = "./pkg/wuffs", .lazy = true },
.zlib = .{ .path = "./pkg/zlib", .lazy = true },
@ -90,8 +91,8 @@
.lazy = true,
},
.wayland_protocols = .{
.url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
.hash = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
.url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
.hash = "N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
.lazy = true,
},
.plasma_wayland_protocols = .{
@ -116,8 +117,8 @@
.apple_sdk = .{ .path = "./pkg/apple-sdk" },
.android_ndk = .{ .path = "./pkg/android-ndk" },
.iterm2_themes = .{
.url = "https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz",
.hash = "N-V-__8AAGi9AwC7QV7hLqjN6iBkXA2y5dxw285nkSLlVB7I",
.url = "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz",
.hash = "N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF",
.lazy = true,
},
},

36
build.zig.zon.json generated
View File

@ -32,7 +32,7 @@
"gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-": {
"name": "gobject",
"url": "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst",
"hash": "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc="
"hash": "sha256-2b1DBvAIHY5LhItq3+q9L6tJgi7itnnrSAHc7fXWDEg="
},
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
"name": "gtk4_layer_shell",
@ -54,10 +54,10 @@
"url": "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz",
"hash": "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs="
},
"N-V-__8AAGi9AwC7QV7hLqjN6iBkXA2y5dxw285nkSLlVB7I": {
"N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF": {
"name": "iterm2_themes",
"url": "https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz",
"hash": "sha256-HGujRdQdWtVIf3GwCgQgjV9lbwWxJSIDJOWq3gOX3kU="
"url": "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz",
"hash": "sha256-FCALuGoMgUq2lgnVALKAs5a20uuDXt8Gdt5KeJwKqP0="
},
"N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": {
"name": "jetbrains_mono",
@ -72,7 +72,7 @@
"libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs": {
"name": "libxev",
"url": "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
"hash": "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg="
"hash": "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc="
},
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
"name": "libxml2",
@ -109,6 +109,11 @@
"url": "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz",
"hash": "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M="
},
"N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH": {
"name": "utfcpp",
"url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz",
"hash": "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8="
},
"uucode-0.1.0-ZZjBPj96QADXyt5sqwBJUnhaDYs_qBeeKijZvlRa0eqM": {
"name": "uucode",
"url": "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732",
@ -117,12 +122,12 @@
"uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9": {
"name": "uucode",
"url": "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz",
"hash": "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg="
"hash": "sha256-0KvuD0+L1urjwFF3fhbnxC2JZKqqAVWRxOVlcD9GX5U="
},
"vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS": {
"name": "vaxis",
"url": "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz",
"hash": "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y="
"hash": "sha256-LnIzK8icW1Qexua9SHaeHz+3V8QAbz0a+UC1T5sIjvY="
},
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
"name": "wayland",
@ -134,11 +139,6 @@
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
"hash": "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg="
},
"N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA": {
"name": "wayland_protocols",
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
"hash": "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM="
},
"N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs": {
"name": "wuffs",
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
@ -147,32 +147,32 @@
"z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ": {
"name": "z2d",
"url": "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz",
"hash": "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E="
"hash": "sha256-afIdou/V7gk3/lXE0J5Ir8T7L5GgHvFnyMJ1rgRnl/c="
},
"zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh": {
"name": "zf",
"url": "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz",
"hash": "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY="
"hash": "sha256-OwFdkorwTp4mJyvBXrTbtNmp1GnrbSkKDdrmc7d8RWg="
},
"zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi": {
"name": "zig_js",
"url": "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
"hash": "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4="
"hash": "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M="
},
"zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK": {
"name": "zig_objc",
"url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
"hash": "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM="
"hash": "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw="
},
"wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe": {
"name": "zig_wayland",
"url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
"hash": "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw="
"hash": "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4="
},
"zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms": {
"name": "zigimg",
"url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
"hash": "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A="
"hash": "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM="
},
"N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
"name": "zlib",

97
build.zig.zon.nix generated
View File

@ -2,12 +2,10 @@
{
lib,
linkFarm,
fetchzip,
fetchurl,
fetchgit,
runCommandLocal,
zig_0_15,
zstd,
name ? "zig-packages",
}: let
unpackZigArtifact = {
@ -19,7 +17,7 @@
nativeBuildInputs = [zig_0_15];
}
''
hash="$(cd "$TMPDIR" && zig fetch --global-cache-dir "$TMPDIR" ${artifact})"
hash="$(zig fetch --global-cache-dir "$TMPDIR" ${artifact})"
mv "$TMPDIR/p/$hash" "$out"
chmod 755 "$out"
'';
@ -28,16 +26,8 @@
name,
url,
hash,
unpack,
}: let
artifact =
if unpack
then
fetchzip {
inherit url hash;
nativeBuildInputs = [zstd];
}
else fetchurl {inherit url hash;};
artifact = fetchurl {inherit url hash;};
in
unpackZigArtifact {inherit name artifact;};
@ -66,7 +56,6 @@
name,
url,
hash,
unpack,
}: let
parts = lib.splitString "://" url;
proto = builtins.elemAt parts 0;
@ -81,11 +70,11 @@
url = "https://${path}";
};
http = fetchZig {
inherit name hash unpack;
inherit name hash;
url = "http://${path}";
};
https = fetchZig {
inherit name hash unpack;
inherit name hash;
url = "https://${path}";
};
};
@ -99,7 +88,6 @@ in
name = "bindings";
url = "https://deps.files.ghostty.org/DearBindings_v0.17_ImGui_v1.92.5-docking.tar.gz";
hash = "sha256-i/7FAOAJJvZ5hT7iPWfMOS08MYFzPKRwRzhlHT9wuqM=";
unpack = false;
};
}
{
@ -108,7 +96,6 @@ in
name = "breakpad";
url = "https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz";
hash = "sha256-bMqYlD0amQdmzvYQd8Ca/1k4Bj/heh7+EijlQSttatk=";
unpack = false;
};
}
{
@ -117,7 +104,6 @@ in
name = "fontconfig";
url = "https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz";
hash = "sha256-O6LdkhWHGKzsXKrxpxYEO1qgVcJ7CB2RSvPMtA3OilU=";
unpack = false;
};
}
{
@ -126,7 +112,6 @@ in
name = "freetype";
url = "https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz";
hash = "sha256-QnIB9dUVFnDQXB9bRb713aHy592XHvVPD+qqf/0quQw=";
unpack = false;
};
}
{
@ -135,7 +120,6 @@ in
name = "gettext";
url = "https://deps.files.ghostty.org/gettext-0.24.tar.gz";
hash = "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc=";
unpack = false;
};
}
{
@ -144,7 +128,6 @@ in
name = "glslang";
url = "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz";
hash = "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U=";
unpack = false;
};
}
{
@ -152,8 +135,7 @@ in
path = fetchZigArtifact {
name = "gobject";
url = "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst";
hash = "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc=";
unpack = true;
hash = "sha256-2b1DBvAIHY5LhItq3+q9L6tJgi7itnnrSAHc7fXWDEg=";
};
}
{
@ -162,7 +144,6 @@ in
name = "gtk4_layer_shell";
url = "https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz";
hash = "sha256-mChCgSYKXu9bT2OlXxbEv2p4ihAgptsDfssPcfozaYg=";
unpack = false;
};
}
{
@ -171,7 +152,6 @@ in
name = "harfbuzz";
url = "https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz";
hash = "sha256-8WNRuv4hRyX+LB1bWfDZPkmQWkskeJn7kNcM/5U6K5s=";
unpack = false;
};
}
{
@ -180,7 +160,6 @@ in
name = "highway";
url = "https://deps.files.ghostty.org/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz";
hash = "sha256-h9T4iT704I8iSXNgj/6/lCaKgTgLp5wS6IQZaMgKohI=";
unpack = false;
};
}
{
@ -189,16 +168,14 @@ in
name = "imgui";
url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz";
hash = "sha256-yBbCDox18+Fa6Gc1DnmSVQLRpqhZOLsac7iSfl8x+cs=";
unpack = false;
};
}
{
name = "N-V-__8AAGi9AwC7QV7hLqjN6iBkXA2y5dxw285nkSLlVB7I";
name = "N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF";
path = fetchZigArtifact {
name = "iterm2_themes";
url = "https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz";
hash = "sha256-HGujRdQdWtVIf3GwCgQgjV9lbwWxJSIDJOWq3gOX3kU=";
unpack = false;
url = "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz";
hash = "sha256-FCALuGoMgUq2lgnVALKAs5a20uuDXt8Gdt5KeJwKqP0=";
};
}
{
@ -207,7 +184,6 @@ in
name = "jetbrains_mono";
url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz";
hash = "sha256-xXppHouCrQmLWWPzlZAy5AOPORCHr3cViFulkEYQXMQ=";
unpack = false;
};
}
{
@ -216,7 +192,6 @@ in
name = "libpng";
url = "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz";
hash = "sha256-/syVtGzwXo4/yKQUdQ4LparQDYnp/fF16U/wQcrxoDo=";
unpack = false;
};
}
{
@ -224,8 +199,7 @@ in
path = fetchZigArtifact {
name = "libxev";
url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz";
hash = "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg=";
unpack = true;
hash = "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc=";
};
}
{
@ -234,7 +208,6 @@ in
name = "libxml2";
url = "https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz";
hash = "sha256-bCgFni4+60K1tLFkieORamNGwQladP7jvGXNxdiaYhU=";
unpack = false;
};
}
{
@ -243,7 +216,6 @@ in
name = "nerd_fonts_symbols_only";
url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz";
hash = "sha256-EWTRuVbUveJI17LwmYxDzJT1ICQxoVZKeTiVsec7DQQ=";
unpack = false;
};
}
{
@ -252,7 +224,6 @@ in
name = "oniguruma";
url = "https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz";
hash = "sha256-ABqhIC54RI9MC/GkjHblVodrNvFtks4yB+zP1h2Z8qA=";
unpack = false;
};
}
{
@ -261,7 +232,6 @@ in
name = "pixels";
url = "https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d83b5801a932dcd44917424c8806.tar.gz";
hash = "sha256-Veg7FtCRCCUCvxSb9FfzH0IJLFmCZQ4/+657SIcb8Ro=";
unpack = false;
};
}
{
@ -270,7 +240,6 @@ in
name = "plasma_wayland_protocols";
url = "https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz";
hash = "sha256-XFi6IUrNjmvKNCbcCLAixGqN2Zeymhs+KLrfccIN9EE=";
unpack = false;
};
}
{
@ -279,7 +248,6 @@ in
name = "sentry";
url = "https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz";
hash = "sha256-KsZJfMjWGo0xCT5HrduMmyxFsWsHBbszSoNbZCPDGN8=";
unpack = false;
};
}
{
@ -288,7 +256,14 @@ in
name = "spirv_cross";
url = "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz";
hash = "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M=";
unpack = false;
};
}
{
name = "N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH";
path = fetchZigArtifact {
name = "utfcpp";
url = "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz";
hash = "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8=";
};
}
{
@ -297,7 +272,6 @@ in
name = "uucode";
url = "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732";
hash = "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8=";
unpack = true;
};
}
{
@ -305,8 +279,7 @@ in
path = fetchZigArtifact {
name = "uucode";
url = "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz";
hash = "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg=";
unpack = true;
hash = "sha256-0KvuD0+L1urjwFF3fhbnxC2JZKqqAVWRxOVlcD9GX5U=";
};
}
{
@ -314,8 +287,7 @@ in
path = fetchZigArtifact {
name = "vaxis";
url = "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz";
hash = "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y=";
unpack = true;
hash = "sha256-LnIzK8icW1Qexua9SHaeHz+3V8QAbz0a+UC1T5sIjvY=";
};
}
{
@ -324,7 +296,6 @@ in
name = "wayland";
url = "https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz";
hash = "sha256-6kGR1o5DdnflHzqs3ieCmBAUTpMdOXoyfcYDXiw5xQ0=";
unpack = false;
};
}
{
@ -333,16 +304,6 @@ in
name = "wayland_protocols";
url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz";
hash = "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg=";
unpack = false;
};
}
{
name = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA";
path = fetchZigArtifact {
name = "wayland_protocols";
url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz";
hash = "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM=";
unpack = false;
};
}
{
@ -351,7 +312,6 @@ in
name = "wuffs";
url = "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz";
hash = "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM=";
unpack = false;
};
}
{
@ -359,8 +319,7 @@ in
path = fetchZigArtifact {
name = "z2d";
url = "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz";
hash = "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E=";
unpack = true;
hash = "sha256-afIdou/V7gk3/lXE0J5Ir8T7L5GgHvFnyMJ1rgRnl/c=";
};
}
{
@ -368,8 +327,7 @@ in
path = fetchZigArtifact {
name = "zf";
url = "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz";
hash = "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY=";
unpack = true;
hash = "sha256-OwFdkorwTp4mJyvBXrTbtNmp1GnrbSkKDdrmc7d8RWg=";
};
}
{
@ -377,8 +335,7 @@ in
path = fetchZigArtifact {
name = "zig_js";
url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz";
hash = "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4=";
unpack = true;
hash = "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M=";
};
}
{
@ -386,8 +343,7 @@ in
path = fetchZigArtifact {
name = "zig_objc";
url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz";
hash = "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM=";
unpack = true;
hash = "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw=";
};
}
{
@ -395,8 +351,7 @@ in
path = fetchZigArtifact {
name = "zig_wayland";
url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz";
hash = "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw=";
unpack = true;
hash = "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4=";
};
}
{
@ -404,8 +359,7 @@ in
path = fetchZigArtifact {
name = "zigimg";
url = "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz";
hash = "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A=";
unpack = true;
hash = "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM=";
};
}
{
@ -414,7 +368,6 @@ in
name = "zlib";
url = "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz";
hash = "sha256-F+iIY/NgBnKrSRgvIXKBtvxNPHYr3jYZNeQ2qVIU0Fw=";
unpack = false;
};
}
]

4
build.zig.zon.txt generated
View File

@ -6,7 +6,7 @@ https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918
https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz
https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz
https://deps.files.ghostty.org/gettext-0.24.tar.gz
https://deps.files.ghostty.org/ghostty-themes-release-20260525-155808-7335c0a.tgz
https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz
https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz
https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst
https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz
@ -20,6 +20,7 @@ https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d8
https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz
https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz
https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz
https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz
https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz
https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz
https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz
@ -33,4 +34,3 @@ https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz

View File

@ -1,74 +0,0 @@
# GhosttyZigCompiler.cmake set up zig cc as a cross compiler
#
# Provides ghostty_zig_compiler() which configures zig cc / zig c++ as
# the C/CXX compiler for a given Zig target triple. It creates small
# wrapper scripts (shell on Unix, .cmd on Windows) and sets the
# following CMake variables in the caller's scope:
#
# CMAKE_C_COMPILER, CMAKE_CXX_COMPILER,
# CMAKE_C_COMPILER_FORCED, CMAKE_CXX_COMPILER_FORCED,
# CMAKE_SYSTEM_NAME, CMAKE_EXECUTABLE_SUFFIX (Windows only)
#
# This file is self-contained with no dependencies on the ghostty
# source tree. Copy it into your project and include it directly.
# It cannot be consumed via FetchContent because it must run before
# project(), but FetchContent_MakeAvailable triggers project()
# internally.
#
# Must be called BEFORE project() CMake reads the compiler variables
# at project() time and won't re-detect after that.
#
# Usage:
#
# cmake_minimum_required(VERSION 3.19)
#
# include(cmake/GhosttyZigCompiler.cmake)
# ghostty_zig_compiler(ZIG_TARGET x86_64-linux-gnu)
#
# project(myapp LANGUAGES C CXX)
#
# FetchContent_MakeAvailable(ghostty)
# ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
# target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
#
# See example/c-vt-cmake-cross/ for a complete working example.
include_guard(GLOBAL)
function(ghostty_zig_compiler)
cmake_parse_arguments(PARSE_ARGV 0 _GZC "" "ZIG_TARGET" "")
if(NOT _GZC_ZIG_TARGET)
message(FATAL_ERROR "ghostty_zig_compiler: ZIG_TARGET is required")
endif()
find_program(_GZC_ZIG zig REQUIRED)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(_cc "${CMAKE_CURRENT_BINARY_DIR}/zig-cc.cmd")
set(_cxx "${CMAKE_CURRENT_BINARY_DIR}/zig-cxx.cmd")
file(WRITE "${_cc}" "@\"${_GZC_ZIG}\" cc -target ${_GZC_ZIG_TARGET} %*\n")
file(WRITE "${_cxx}" "@\"${_GZC_ZIG}\" c++ -target ${_GZC_ZIG_TARGET} %*\n")
else()
set(_cc "${CMAKE_CURRENT_BINARY_DIR}/zig-cc")
set(_cxx "${CMAKE_CURRENT_BINARY_DIR}/zig-c++")
file(WRITE "${_cc}" "#!/bin/sh\nexec \"${_GZC_ZIG}\" cc -target ${_GZC_ZIG_TARGET} \"$@\"\n")
file(WRITE "${_cxx}" "#!/bin/sh\nexec \"${_GZC_ZIG}\" c++ -target ${_GZC_ZIG_TARGET} \"$@\"\n")
file(CHMOD "${_cc}" "${_cxx}"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
endif()
set(CMAKE_C_COMPILER "${_cc}" PARENT_SCOPE)
set(CMAKE_CXX_COMPILER "${_cxx}" PARENT_SCOPE)
set(CMAKE_C_COMPILER_FORCED TRUE PARENT_SCOPE)
set(CMAKE_CXX_COMPILER_FORCED TRUE PARENT_SCOPE)
if(_GZC_ZIG_TARGET MATCHES "windows")
set(CMAKE_SYSTEM_NAME Windows PARENT_SCOPE)
set(CMAKE_EXECUTABLE_SUFFIX ".exe" PARENT_SCOPE)
elseif(_GZC_ZIG_TARGET MATCHES "linux")
set(CMAKE_SYSTEM_NAME Linux PARENT_SCOPE)
elseif(_GZC_ZIG_TARGET MATCHES "darwin|macos")
set(CMAKE_SYSTEM_NAME Darwin PARENT_SCOPE)
endif()
endfunction()

102
dist/cmake/README.md vendored
View File

@ -1,102 +0,0 @@
# CMake Support for libghostty-vt
The top-level `CMakeLists.txt` wraps the Zig build system so that CMake
projects can consume libghostty-vt without invoking `zig build` manually.
Running `cmake --build` triggers `zig build -Demit-lib-vt` automatically.
This means downstream projects do require a working Zig compiler on
`PATH` to build, but don't need to know any Zig-specific details.
## Using FetchContent (recommended)
Add the following to your project's `CMakeLists.txt`:
```cmake
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
FetchContent_MakeAvailable(ghostty)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt)
```
This fetches the Ghostty source, builds libghostty-vt via Zig during your
CMake build, and links it into your target. Headers are added to the
include path automatically.
### Using a local checkout
If you already have the Ghostty source checked out, skip the download by
pointing CMake at it:
```shell-session
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=/path/to/ghostty
cmake --build build
```
## Using find_package (install-based)
Build and install libghostty-vt first:
```shell-session
cd /path/to/ghostty
cmake -B build
cmake --build build
cmake --install build --prefix /usr/local
```
Then in your project:
```cmake
find_package(ghostty-vt REQUIRED)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt)
```
## Cross-compilation
For cross-compiling to a different Zig target triple, use
`ghostty_vt_add_target()` after `FetchContent_MakeAvailable`:
```cmake
FetchContent_MakeAvailable(ghostty)
ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
```
### Using zig cc as the C/CXX compiler
When cross-compiling, the host C compiler can't link binaries for the
target platform. `GhosttyZigCompiler.cmake` provides
`ghostty_zig_compiler()` to set up `zig cc` as the C/CXX compiler for
the cross target. It creates wrapper scripts (shell on Unix, `.cmd` on
Windows) and configures `CMAKE_C_COMPILER`, `CMAKE_CXX_COMPILER`, and
`CMAKE_SYSTEM_NAME`.
The module is self-contained — copy it into your project (e.g. to
`cmake/`) and include it directly. It cannot be consumed via
FetchContent because it must run before `project()`, but
`FetchContent_MakeAvailable` triggers `project()` internally:
```cmake
cmake_minimum_required(VERSION 3.19)
include(cmake/GhosttyZigCompiler.cmake)
ghostty_zig_compiler(ZIG_TARGET x86_64-linux-gnu)
project(myapp LANGUAGES C CXX)
FetchContent_MakeAvailable(ghostty)
ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
add_executable(myapp main.c)
target_link_libraries(myapp PRIVATE ghostty-vt-static-linux-amd64)
```
See `example/c-vt-cmake-cross/` for a complete working example.

View File

@ -1,65 +0,0 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
set(_ghostty_vt_libdir "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@")
# Shared library target
if(NOT TARGET ghostty-vt::ghostty-vt)
add_library(ghostty-vt::ghostty-vt SHARED IMPORTED)
if(WIN32)
set(_ghostty_vt_shared_location "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_BINDIR@/@GHOSTTY_VT_REALNAME@")
else()
set(_ghostty_vt_shared_location "${_ghostty_vt_libdir}/@GHOSTTY_VT_REALNAME@")
endif()
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_LOCATION "${_ghostty_vt_shared_location}"
INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@"
)
unset(_ghostty_vt_shared_location)
if(APPLE)
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_SONAME "@rpath/@GHOSTTY_VT_SONAME@"
INTERFACE_LINK_DIRECTORIES "${_ghostty_vt_libdir}"
)
# Ensure consumers can find the @rpath dylib at runtime
set_property(TARGET ghostty-vt::ghostty-vt APPEND PROPERTY
INTERFACE_LINK_OPTIONS "LINKER:-rpath,${_ghostty_vt_libdir}"
)
elseif(WIN32)
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_IMPLIB "${_ghostty_vt_libdir}/@GHOSTTY_VT_IMPLIB@"
)
else()
set_target_properties(ghostty-vt::ghostty-vt PROPERTIES
IMPORTED_SONAME "@GHOSTTY_VT_SONAME@"
)
endif()
endif()
# Static library target
#
# Consumers must link transitive dependencies themselves. By default (with
# SIMD enabled): libc, libc++ (or libstdc++ on Linux), highway, and
# simdutf. Building with -Dsimd=false removes the C++ / highway / simdutf
# dependencies.
if(NOT TARGET ghostty-vt::ghostty-vt-static)
add_library(ghostty-vt::ghostty-vt-static STATIC IMPORTED)
set_target_properties(ghostty-vt::ghostty-vt-static PROPERTIES
IMPORTED_LOCATION "${_ghostty_vt_libdir}/@GHOSTTY_VT_STATIC_REALNAME@"
INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@"
)
if(WIN32)
set_target_properties(ghostty-vt::ghostty-vt-static PROPERTIES
INTERFACE_LINK_LIBRARIES "ntdll;kernel32"
)
endif()
endif()
unset(_ghostty_vt_libdir)
check_required_components(ghostty-vt)

View File

@ -7,4 +7,5 @@ Actions=RunGhosttyDir
[Desktop Action RunGhosttyDir]
Name=Open Ghostty Here
Icon=com.mitchellh.ghostty
Exec=ghostty +new-window --working-directory=%F
Exec=ghostty --working-directory=%F --gtk-single-instance=false

2
example/.gitignore vendored
View File

@ -2,5 +2,3 @@
dist/
node_modules/
example.wasm*
build/
.build/

View File

@ -1,39 +0,0 @@
# Example Libghostty Projects
Each example is a standalone project with its own `build.zig`,
`build.zig.zon`, `README.md`, and `src/main.c` (or `.zig`). Examples are
auto-discovered by CI via `example/*/build.zig.zon`, so no workflow file
edits are needed when adding a new example.
## Adding a New Example
1. Copy an existing example directory (e.g., `c-vt-encode-focus/`) as a
starting point.
2. Update `build.zig.zon`: change `.name`, generate a **new unique**
`.fingerprint` value (a random `u64` hex literal), and keep
`.minimum_zig_version` matching the others.
3. Update `build.zig`: change the executable `.name` to match the directory.
4. Write a `README.md` following the existing format.
## Doxygen Snippet Tags
Example source files use Doxygen `@snippet` tags so the corresponding
header in `include/ghostty/vt/` can reference them. Wrap the relevant
code with `//! [snippet-name]` markers:
```c
//! [my-snippet]
int main() { ... }
//! [my-snippet]
```
The header then uses `@snippet <dir>/src/main.c my-snippet` instead of
inline `@code` blocks. Never duplicate example code inline in the
headers — always use `@snippet`. When modifying example code, keep the
snippet markers in sync with the headers in `include/ghostty/vt/`.
## Conventions
- Executable names use underscores: `c_vt_encode_focus` (not hyphens).
- All C examples link `ghostty-vt` via `lazyDependency("ghostty", ...)`.
- `build.zig` files follow a common template — keep them consistent.

View File

@ -1,17 +0,0 @@
# Examples
Standalone projects demonstrating the Ghostty library APIs.
The directories starting with `c-` use the C API and the directories
starting with `zig-` use the Zig API.
Every example can be built and run using `zig build` and `zig build run`
from within the respective example directory.
Even the C API examples use the Zig build system (not the language) to
build the project.
## Running an Example
```shell-session
cd example/<dir>
zig build run
```

View File

@ -1,17 +0,0 @@
# Example: `ghostty-vt` Build Info
This contains a simple example of how to use the `ghostty-vt` build info
API to query compile-time build configuration.
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
```

View File

@ -1,42 +0,0 @@
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_build_info",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_build_info,
.version = "0.0.0",
.fingerprint = 0xc6b57ed4f83fb16,
.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",
},
}

View File

@ -1,52 +0,0 @@
#include <stdio.h>
#include <ghostty/vt.h>
//! [build-info-query]
void query_build_info() {
bool simd = false;
bool kitty_graphics = false;
bool tmux_control_mode = false;
ghostty_build_info(GHOSTTY_BUILD_INFO_SIMD, &simd);
ghostty_build_info(GHOSTTY_BUILD_INFO_KITTY_GRAPHICS, &kitty_graphics);
ghostty_build_info(GHOSTTY_BUILD_INFO_TMUX_CONTROL_MODE, &tmux_control_mode);
printf("SIMD: %s\n", simd ? "enabled" : "disabled");
printf("Kitty graphics: %s\n", kitty_graphics ? "enabled" : "disabled");
printf("Tmux control mode: %s\n", tmux_control_mode ? "enabled" : "disabled");
GhosttyString version_string = {0};
size_t version_major = 0;
size_t version_minor = 0;
size_t version_patch = 0;
GhosttyString version_pre = {0};
GhosttyString version_build = {0};
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_STRING, &version_string);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_MAJOR, &version_major);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_MINOR, &version_minor);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_PATCH, &version_patch);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_PRE, &version_pre);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_BUILD, &version_build);
printf("Version: %.*s\n", (int)version_string.len, version_string.ptr);
printf("Version major: %zu\n", version_major);
printf("Version minor: %zu\n", version_minor);
printf("Version patch: %zu\n", version_patch);
if (version_pre.len > 0) {
printf("Version pre : %.*s\n", (int)version_pre.len, version_pre.ptr);
} else {
printf("Version pre : (none)\n");
}
if (version_build.len > 0) {
printf("Version build: %.*s\n", (int)version_build.len, version_build.ptr);
} else {
printf("Version build: (none)\n");
}
}
//! [build-info-query]
int main() {
query_build_info();
return 0;
}

View File

@ -1,59 +0,0 @@
cmake_minimum_required(VERSION 3.19)
# --- Determine cross-compilation target before project() --------------------
#
# We need to know the target before project() so we can set up zig cc as the
# C/C++ compiler for the cross target.
# Pick a cross-compilation target: build for a different OS than the host.
# Can be overridden with -DZIG_TARGET=... on the command line.
if(NOT ZIG_TARGET)
# CMAKE_HOST_SYSTEM_PROCESSOR may not be set before project(), so
# fall back to `uname -m`.
if(CMAKE_HOST_SYSTEM_PROCESSOR)
set(_arch "${CMAKE_HOST_SYSTEM_PROCESSOR}")
else()
execute_process(COMMAND uname -m OUTPUT_VARIABLE _arch OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
if(_arch MATCHES "^(x86_64|AMD64)$")
set(_arch "x86_64")
elseif(_arch MATCHES "^(aarch64|arm64|ARM64)$")
set(_arch "aarch64")
endif()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
set(ZIG_TARGET "${_arch}-windows-gnu")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(ZIG_TARGET "${_arch}-linux-gnu")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
set(ZIG_TARGET "${_arch}-linux-gnu")
else()
message(FATAL_ERROR
"Cannot derive ZIG_TARGET for ${CMAKE_HOST_SYSTEM_NAME}. "
"Pass -DZIG_TARGET=... manually.")
endif()
message(STATUS "Cross-compiling for ZIG_TARGET: ${ZIG_TARGET}")
endif()
# --- Set up zig cc as the cross compiler ------------------------------------
# GhosttyZigCompiler.cmake must be called before project().
# Downstream projects would copy this file into their tree; here we
# include it directly from the repo.
include(../../dist/cmake/GhosttyZigCompiler.cmake)
ghostty_zig_compiler(ZIG_TARGET "${ZIG_TARGET}")
project(c-vt-cmake-cross LANGUAGES C CXX)
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
FetchContent_MakeAvailable(ghostty)
ghostty_vt_add_target(NAME cross ZIG_TARGET "${ZIG_TARGET}")
add_executable(c_vt_cmake_cross src/main.c)
target_link_libraries(c_vt_cmake_cross PRIVATE ghostty-vt-static-cross)

View File

@ -1,21 +0,0 @@
# c-vt-cmake-cross
Demonstrates using `ghostty_vt_add_target()` to cross-compile
libghostty-vt with static linking. The target OS is chosen automatically:
| Host | Target |
| ------- | --------------- |
| Linux | Windows (MinGW) |
| Windows | Linux (glibc) |
| macOS | Linux (glibc) |
Override with `-DZIG_TARGET=...` if needed.
## Building
```shell-session
cd example/c-vt-cmake-cross
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=../..
cmake --build build
file build/c_vt_cmake_cross
```

View File

@ -1,52 +0,0 @@
#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 some VT-encoded content into the terminal
const char *commands[] = {
"Hello from a \033[1mCMake\033[0m-built program!\r\n",
"Line 2: \033[4munderlined\033[0m text\r\n",
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
};
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]));
}
// Format the terminal contents as plain text
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);
uint8_t *buf = NULL;
size_t len = 0;
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
assert(result == GHOSTTY_SUCCESS);
printf("Plain text (%zu bytes):\n", len);
fwrite(buf, 1, len, stdout);
printf("\n");
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -1,13 +0,0 @@
cmake_minimum_required(VERSION 3.19)
project(c-vt-cmake-static LANGUAGES C)
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
set(GHOSTTY_ZIG_BUILD_FLAGS "-Dsimd=false" CACHE STRING "" FORCE)
FetchContent_MakeAvailable(ghostty)
add_executable(c_vt_cmake_static src/main.c)
target_link_libraries(c_vt_cmake_static PRIVATE ghostty-vt-static)

View File

@ -1,21 +0,0 @@
# c-vt-cmake-static
Demonstrates consuming libghostty-vt as a **static** library from a CMake
project using `FetchContent`. Creates a terminal, writes VT sequences into
it, and formats the screen contents as plain text.
## Building
```shell-session
cd example/c-vt-cmake-static
cmake -B build
cmake --build build
./build/c_vt_cmake_static
```
To build against a local checkout instead of fetching from GitHub:
```shell-session
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=../..
cmake --build build
```

View File

@ -1,52 +0,0 @@
#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 some VT-encoded content into the terminal
const char *commands[] = {
"Hello from a \033[1mCMake\033[0m-built program (static)!\r\n",
"Line 2: \033[4munderlined\033[0m text\r\n",
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
};
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]));
}
// Format the terminal contents as plain text
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);
uint8_t *buf = NULL;
size_t len = 0;
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
assert(result == GHOSTTY_SUCCESS);
printf("Plain text (%zu bytes):\n", len);
fwrite(buf, 1, len, stdout);
printf("\n");
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -1,12 +0,0 @@
cmake_minimum_required(VERSION 3.19)
project(c-vt-cmake LANGUAGES C)
include(FetchContent)
FetchContent_Declare(ghostty
GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
GIT_TAG main
)
FetchContent_MakeAvailable(ghostty)
add_executable(c_vt_cmake src/main.c)
target_link_libraries(c_vt_cmake PRIVATE ghostty-vt)

View File

@ -1,21 +0,0 @@
# c-vt-cmake
Demonstrates consuming libghostty-vt from a CMake project using
`FetchContent`. Creates a terminal, writes VT sequences into it, and
formats the screen contents as plain text.
## Building
```shell-session
cd example/c-vt-cmake
cmake -B build
cmake --build build
./build/c_vt_cmake
```
To build against a local checkout instead of fetching from GitHub:
```shell-session
cmake -B build -DFETCHCONTENT_SOURCE_DIR_GHOSTTY=../..
cmake --build build
```

View File

@ -1,52 +0,0 @@
#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 some VT-encoded content into the terminal
const char *commands[] = {
"Hello from a \033[1mCMake\033[0m-built program!\r\n",
"Line 2: \033[4munderlined\033[0m text\r\n",
"Line 3: \033[31mred\033[0m \033[32mgreen\033[0m \033[34mblue\033[0m\r\n",
};
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]));
}
// Format the terminal contents as plain text
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);
uint8_t *buf = NULL;
size_t len = 0;
result = ghostty_formatter_format_alloc(formatter, NULL, &buf, &len);
assert(result == GHOSTTY_SUCCESS);
printf("Plain text (%zu bytes):\n", len);
fwrite(buf, 1, len, stdout);
printf("\n");
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -1,18 +0,0 @@
# Example: `ghostty-vt` Terminal Colors
This contains a simple example of how to set default terminal colors,
read effective and default color values, and observe how OSC overrides
layer on top of defaults using the `ghostty-vt` C library.
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
```

View File

@ -1,42 +0,0 @@
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_colors",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_colors,
.version = "0.0.0",
.fingerprint = 0xe7ec4247f16d4fce,
.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",
},
}

View File

@ -1,121 +0,0 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [colors-set-defaults]
/// Set up a dark color theme with custom palette entries.
void set_color_theme(GhosttyTerminal terminal) {
// Set default foreground (light gray) and background (dark)
GhosttyColorRgb fg = { .r = 0xDD, .g = 0xDD, .b = 0xDD };
GhosttyColorRgb bg = { .r = 0x1E, .g = 0x1E, .b = 0x2E };
GhosttyColorRgb cursor = { .r = 0xF5, .g = 0xE0, .b = 0xDC };
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_FOREGROUND, &fg);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_BACKGROUND, &bg);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_CURSOR, &cursor);
// Set a custom palette — start from the built-in default and override
// the first 8 entries with a custom dark theme.
GhosttyColorRgb palette[256];
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_PALETTE, palette);
palette[GHOSTTY_COLOR_NAMED_BLACK] = (GhosttyColorRgb){ 0x45, 0x47, 0x5A };
palette[GHOSTTY_COLOR_NAMED_RED] = (GhosttyColorRgb){ 0xF3, 0x8B, 0xA8 };
palette[GHOSTTY_COLOR_NAMED_GREEN] = (GhosttyColorRgb){ 0xA6, 0xE3, 0xA1 };
palette[GHOSTTY_COLOR_NAMED_YELLOW] = (GhosttyColorRgb){ 0xF9, 0xE2, 0xAF };
palette[GHOSTTY_COLOR_NAMED_BLUE] = (GhosttyColorRgb){ 0x89, 0xB4, 0xFA };
palette[GHOSTTY_COLOR_NAMED_MAGENTA] = (GhosttyColorRgb){ 0xF5, 0xC2, 0xE7 };
palette[GHOSTTY_COLOR_NAMED_CYAN] = (GhosttyColorRgb){ 0x94, 0xE2, 0xD5 };
palette[GHOSTTY_COLOR_NAMED_WHITE] = (GhosttyColorRgb){ 0xBA, 0xC2, 0xDE };
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_PALETTE, palette);
}
//! [colors-set-defaults]
//! [colors-read]
/// Print the effective and default values for a color, showing how
/// OSC overrides layer on top of defaults.
void print_color(GhosttyTerminal terminal,
const char* name,
GhosttyTerminalData effective_data,
GhosttyTerminalData default_data) {
GhosttyColorRgb color;
GhosttyResult res = ghostty_terminal_get(terminal, effective_data, &color);
if (res == GHOSTTY_SUCCESS) {
printf(" %-12s effective: #%02X%02X%02X", name, color.r, color.g, color.b);
} else {
printf(" %-12s effective: (not set)", name);
}
res = ghostty_terminal_get(terminal, default_data, &color);
if (res == GHOSTTY_SUCCESS) {
printf(" default: #%02X%02X%02X\n", color.r, color.g, color.b);
} else {
printf(" default: (not set)\n");
}
}
void print_all_colors(GhosttyTerminal terminal, const char* label) {
printf("%s:\n", label);
print_color(terminal, "foreground",
GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND,
GHOSTTY_TERMINAL_DATA_COLOR_FOREGROUND_DEFAULT);
print_color(terminal, "background",
GHOSTTY_TERMINAL_DATA_COLOR_BACKGROUND,
GHOSTTY_TERMINAL_DATA_COLOR_BACKGROUND_DEFAULT);
print_color(terminal, "cursor",
GHOSTTY_TERMINAL_DATA_COLOR_CURSOR,
GHOSTTY_TERMINAL_DATA_COLOR_CURSOR_DEFAULT);
// Show palette index 0 (black) as an example
GhosttyColorRgb palette[256];
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_PALETTE, palette);
printf(" %-12s effective: #%02X%02X%02X", "palette[0]",
palette[0].r, palette[0].g, palette[0].b);
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_COLOR_PALETTE_DEFAULT,
palette);
printf(" default: #%02X%02X%02X\n", palette[0].r, palette[0].g, palette[0].b);
}
//! [colors-read]
//! [colors-main]
int main() {
// Create a terminal
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
if (ghostty_terminal_new(NULL, &terminal, opts) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create terminal\n");
return 1;
}
// Before setting any colors, everything is unset
print_all_colors(terminal, "Before setting defaults");
// Set our color theme defaults
set_color_theme(terminal);
print_all_colors(terminal, "\nAfter setting defaults");
// Simulate an OSC override (e.g. a program running inside the
// terminal changes the foreground via OSC 10)
const char* osc_fg = "\x1B]10;rgb:FF/00/00\x1B\\";
ghostty_terminal_vt_write(terminal, (const uint8_t*)osc_fg,
strlen(osc_fg));
print_all_colors(terminal, "\nAfter OSC foreground override");
// Clear the foreground default — the OSC override is still active
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_COLOR_FOREGROUND, NULL);
print_all_colors(terminal, "\nAfter clearing foreground default");
ghostty_terminal_free(terminal);
return 0;
}
//! [colors-main]

View File

@ -1,18 +0,0 @@
# Example: `ghostty-vt` Terminal Effects
This contains a simple example of how to register and use terminal
effect callbacks (`write_pty`, `bell`, `title_changed`) with the
`ghostty-vt` C library.
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
```

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_effects,
.version = "0.0.0",
.fingerprint = 0xc02634cd65f5b583,
.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",
},
}

View File

@ -1,97 +0,0 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [effects-write-pty]
void on_write_pty(GhosttyTerminal terminal,
void* userdata,
const uint8_t* data,
size_t len) {
(void)terminal;
(void)userdata;
printf(" write_pty (%zu bytes): ", len);
fwrite(data, 1, len, stdout);
printf("\n");
}
//! [effects-write-pty]
//! [effects-bell]
void on_bell(GhosttyTerminal terminal, void* userdata) {
(void)terminal;
int* count = (int*)userdata;
(*count)++;
printf(" bell! (count=%d)\n", *count);
}
//! [effects-bell]
//! [effects-title-changed]
void on_title_changed(GhosttyTerminal terminal, void* userdata) {
(void)userdata;
// Query the cursor position to confirm the terminal processed the
// title change (the title itself is tracked by the embedder via the
// OSC parser or its own state).
uint16_t col = 0;
ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_CURSOR_X, &col);
printf(" title changed (cursor at col %u)\n", col);
}
//! [effects-title-changed]
//! [effects-register]
int main() {
// Create a terminal
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
if (ghostty_terminal_new(NULL, &terminal, opts) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create terminal\n");
return 1;
}
// Set up userdata — a simple bell counter
int bell_count = 0;
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_USERDATA, &bell_count);
// Register effect callbacks
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_WRITE_PTY,
(const void *)on_write_pty);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_BELL,
(const void *)on_bell);
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_TITLE_CHANGED,
(const void *)on_title_changed);
// Feed VT data that triggers effects:
// 1. Bell (BEL = 0x07)
printf("Sending BEL:\n");
const uint8_t bel = 0x07;
ghostty_terminal_vt_write(terminal, &bel, 1);
// 2. Title change (OSC 2 ; <title> ST)
printf("Sending title change:\n");
const char* title_seq = "\x1B]2;Hello Effects\x1B\\";
ghostty_terminal_vt_write(terminal, (const uint8_t*)title_seq,
strlen(title_seq));
// 3. Device status report (DECRQM for wraparound mode ?7)
// triggers write_pty with the response
printf("Sending DECRQM query:\n");
const char* decrqm = "\x1B[?7$p";
ghostty_terminal_vt_write(terminal, (const uint8_t*)decrqm,
strlen(decrqm));
// 4. Another bell to show the counter increments
printf("Sending another BEL:\n");
ghostty_terminal_vt_write(terminal, &bel, 1);
printf("Total bells: %d\n", bell_count);
ghostty_terminal_free(terminal);
return 0;
}
//! [effects-register]

View File

@ -1,17 +0,0 @@
# Example: `ghostty-vt` Encode Focus
This contains a simple example of how to use the `ghostty-vt` focus
encoding API to encode focus gained/lost events into escape sequences.
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
```

View File

@ -1,42 +0,0 @@
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_encode_focus",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_encode_focus,
.version = "0.0.0",
.fingerprint = 0x89f01fd829fcc550,
.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",
},
}

View File

@ -1,20 +0,0 @@
#include <stdio.h>
#include <ghostty/vt.h>
//! [focus-encode]
int main() {
char buf[8];
size_t written = 0;
GhosttyResult result = ghostty_focus_encode(
GHOSTTY_FOCUS_GAINED, buf, sizeof(buf), &written);
if (result == GHOSTTY_SUCCESS) {
printf("Encoded %zu bytes: ", written);
fwrite(buf, 1, written, stdout);
printf("\n");
}
return 0;
}
//! [focus-encode]

View File

@ -1,42 +0,0 @@
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_encode_key",
.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);
}

View File

@ -1,40 +0,0 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [key-encode]
int main() {
// Create encoder
GhosttyKeyEncoder encoder;
GhosttyResult result = ghostty_key_encoder_new(NULL, &encoder);
assert(result == GHOSTTY_SUCCESS);
// Enable Kitty keyboard protocol with all features
ghostty_key_encoder_setopt(encoder, GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS,
&(uint8_t){GHOSTTY_KITTY_KEY_ALL});
// Create and configure key event for Ctrl+C press
GhosttyKeyEvent event;
result = ghostty_key_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_PRESS);
ghostty_key_event_set_key(event, GHOSTTY_KEY_C);
ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);
// Encode the key event
char buf[128];
size_t written = 0;
result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
assert(result == GHOSTTY_SUCCESS);
// Use the encoded sequence (e.g., write to terminal)
fwrite(buf, 1, written, stdout);
// Cleanup
ghostty_key_event_free(event);
ghostty_key_encoder_free(encoder);
return 0;
}
//! [key-encode]

View File

@ -1,23 +0,0 @@
# Example: `ghostty-vt` C Mouse Encoding
This example demonstrates how to use the `ghostty-vt` C library to encode mouse
events into terminal escape sequences.
This example specifically shows how to:
1. Create a mouse encoder with the C API
2. Configure tracking mode and output format (this example uses SGR)
3. Set terminal geometry for pixel-to-cell coordinate mapping
4. Create and configure a mouse event
5. Encode the mouse event into a terminal escape sequence
The example encodes a left button press at pixel position (50, 40) using SGR
format, producing an escape sequence like `\x1b[<0;6;3M`.
## Usage
Run the program:
```shell-session
zig build run
```

View File

@ -1,42 +0,0 @@
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_encode_mouse",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt,
.version = "0.0.0",
.fingerprint = 0x413a8529a6dd3c51,
.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",
},
}

View File

@ -1,52 +0,0 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [mouse-encode]
int main() {
// Create encoder
GhosttyMouseEncoder encoder;
GhosttyResult result = ghostty_mouse_encoder_new(NULL, &encoder);
assert(result == GHOSTTY_SUCCESS);
// Configure SGR format with normal tracking
ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_EVENT,
&(GhosttyMouseTrackingMode){GHOSTTY_MOUSE_TRACKING_NORMAL});
ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_FORMAT,
&(GhosttyMouseFormat){GHOSTTY_MOUSE_FORMAT_SGR});
// Set terminal geometry for coordinate mapping
ghostty_mouse_encoder_setopt(encoder, GHOSTTY_MOUSE_ENCODER_OPT_SIZE,
&(GhosttyMouseEncoderSize){
.size = sizeof(GhosttyMouseEncoderSize),
.screen_width = 800, .screen_height = 600,
.cell_width = 10, .cell_height = 20,
});
// Create and configure a left button press event
GhosttyMouseEvent event;
result = ghostty_mouse_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_mouse_event_set_action(event, GHOSTTY_MOUSE_ACTION_PRESS);
ghostty_mouse_event_set_button(event, GHOSTTY_MOUSE_BUTTON_LEFT);
ghostty_mouse_event_set_position(event,
(GhosttyMousePosition){.x = 50.0f, .y = 40.0f});
// Encode the mouse event
char buf[128];
size_t written = 0;
result = ghostty_mouse_encoder_encode(encoder, event,
buf, sizeof(buf), &written);
assert(result == GHOSTTY_SUCCESS);
// Use the encoded sequence (e.g., write to terminal)
fwrite(buf, 1, written, stdout);
// Cleanup
ghostty_mouse_event_free(event);
ghostty_mouse_encoder_free(encoder);
return 0;
}
//! [mouse-encode]

View File

@ -1,18 +0,0 @@
# 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
```

View File

@ -1,42 +0,0 @@
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);
}

View File

@ -1,24 +0,0 @@
.{
.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",
},
}

View File

@ -1,63 +0,0 @@
#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
ghostty_free(NULL, buf, len);
ghostty_formatter_free(formatter);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -1,19 +0,0 @@
# Example: `ghostty-vt` Tracked Grid References
This contains a simple example of how to use the `ghostty-vt` terminal and
tracked grid reference APIs to keep a long-lived reference to a cell as the
terminal scrolls, detect when that reference loses its meaningful location,
and move the same tracked handle to a new point.
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
```

View File

@ -1,42 +0,0 @@
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_ref_tracked",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_grid_ref_tracked,
.version = "0.0.0",
.fingerprint = 0x64bd14b59e76c294,
.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",
},
}

View File

@ -1,94 +0,0 @@
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [grid-ref-tracked]
static uint32_t codepoint_at_tracked_ref(GhosttyTrackedGridRef tracked) {
GhosttyGridRef snapshot = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyResult result = ghostty_tracked_grid_ref_snapshot(tracked, &snapshot);
assert(result == GHOSTTY_SUCCESS);
GhosttyCell cell;
result = ghostty_grid_ref_cell(&snapshot, &cell);
assert(result == GHOSTTY_SUCCESS);
bool has_text = false;
ghostty_cell_get(cell, GHOSTTY_CELL_DATA_HAS_TEXT, &has_text);
assert(has_text);
uint32_t codepoint = 0;
ghostty_cell_get(cell, GHOSTTY_CELL_DATA_CODEPOINT, &codepoint);
return codepoint;
}
int main() {
GhosttyTerminal terminal;
GhosttyTerminalOptions opts = {
.cols = 8,
.rows = 3,
.max_scrollback = 100,
};
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
assert(result == GHOSTTY_SUCCESS);
const char *text = "alpha\r\n"
"bravo\r\n"
"charlie";
ghostty_terminal_vt_write(
terminal, (const uint8_t *)text, strlen(text));
GhosttyTrackedGridRef tracked = NULL;
GhosttyPoint alpha = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 0, .y = 0 } },
};
result = ghostty_terminal_grid_ref_track(terminal, alpha, &tracked);
assert(result == GHOSTTY_SUCCESS);
// Writing another line scrolls the original "alpha" row into scrollback.
// The tracked ref still follows the same cell.
const char *more = "\r\ndelta";
ghostty_terminal_vt_write(
terminal, (const uint8_t *)more, strlen(more));
assert(ghostty_tracked_grid_ref_has_value(tracked));
printf("tracked codepoint after scroll: %c\n",
(char)codepoint_at_tracked_ref(tracked));
GhosttyPointCoordinate screen = {0};
result = ghostty_tracked_grid_ref_point(
tracked, GHOSTTY_POINT_TAG_SCREEN, &screen);
assert(result == GHOSTTY_SUCCESS);
printf("tracked screen point: %u,%u\n", screen.x, screen.y);
// Resetting the terminal discards the old grid contents. The tracked
// handle remains valid, but no longer has a meaningful location.
ghostty_terminal_reset(terminal);
assert(!ghostty_tracked_grid_ref_has_value(tracked));
GhosttyGridRef discarded = GHOSTTY_INIT_SIZED(GhosttyGridRef);
result = ghostty_tracked_grid_ref_snapshot(tracked, &discarded);
assert(result == GHOSTTY_NO_VALUE);
// The same handle can be moved to a new point after it loses its value.
const char *replacement = "echo";
ghostty_terminal_vt_write(
terminal, (const uint8_t *)replacement, strlen(replacement));
GhosttyPoint echo = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 0, .y = 0 } },
};
result = ghostty_tracked_grid_ref_set(tracked, terminal, echo);
assert(result == GHOSTTY_SUCCESS);
assert(ghostty_tracked_grid_ref_has_value(tracked));
printf("tracked codepoint after reset/set: %c\n",
(char)codepoint_at_tracked_ref(tracked));
ghostty_tracked_grid_ref_free(tracked);
ghostty_terminal_free(terminal);
return 0;
}
//! [grid-ref-tracked]

View File

@ -1,19 +0,0 @@
# 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
```

View File

@ -1,42 +0,0 @@
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);
}

View File

@ -1,24 +0,0 @@
.{
.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",
},
}

View File

@ -1,85 +0,0 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [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]

View File

@ -29,7 +29,7 @@ pub fn build(b: *std.Build) void {
// Exe
const exe = b.addExecutable(.{
.name = "c_vt_effects",
.name = "c_vt_key_encode",
.root_module = exe_mod,
});
b.installArtifact(exe);

View File

@ -0,0 +1,59 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
GhosttyKeyEncoder encoder;
GhosttyResult result = ghostty_key_encoder_new(NULL, &encoder);
assert(result == GHOSTTY_SUCCESS);
// Set kitty flags with all features enabled
ghostty_key_encoder_setopt(encoder, GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS, &(uint8_t){GHOSTTY_KITTY_KEY_ALL});
// Create key event
GhosttyKeyEvent event;
result = ghostty_key_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_RELEASE);
ghostty_key_event_set_key(event, GHOSTTY_KEY_CONTROL_LEFT);
ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);
printf("Encoding event: left ctrl release with all Kitty flags enabled\n");
// Optionally, encode with null buffer to get required size. You can
// skip this step and provide a sufficiently large buffer directly.
// If there isn't enoug hspace, the function will return an out of memory
// error.
size_t required = 0;
result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required);
assert(result == GHOSTTY_OUT_OF_MEMORY);
printf("Required buffer size: %zu bytes\n", required);
// Encode the key event. We don't use our required size above because
// that was just an example; we know 128 bytes is enough.
char buf[128];
size_t written = 0;
result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
assert(result == GHOSTTY_SUCCESS);
printf("Encoded %zu bytes\n", written);
// Print the encoded sequence (hex and string)
printf("Hex: ");
for (size_t i = 0; i < written; i++) printf("%02x ", (unsigned char)buf[i]);
printf("\n");
printf("String: ");
for (size_t i = 0; i < written; i++) {
if (buf[i] == 0x1b) {
printf("\\x1b");
} else {
printf("%c", buf[i]);
}
}
printf("\n");
ghostty_key_event_free(event);
ghostty_key_encoder_free(encoder);
return 0;
}

View File

@ -1,18 +0,0 @@
# Example: `ghostty-vt` Kitty Graphics Protocol
This contains a simple example of how to use the system interface
(`ghostty_sys_set`) to install a PNG decoder callback, then send
a Kitty Graphics Protocol image via `ghostty_terminal_vt_write`.
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
```

View File

@ -1,42 +0,0 @@
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_kitty_graphics",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_kitty_graphics,
.version = "0.0.0",
.fingerprint = 0x432d40ecc8f15589,
.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",
},
}

View File

@ -1,211 +0,0 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
//! [kitty-graphics-decode-png]
/**
* Minimal PNG decoder callback for the sys interface.
*
* A real implementation would use a PNG library (libpng, stb_image, etc.)
* to decode the PNG data. This example uses a hardcoded 1x1 red pixel
* since we know exactly what image we're sending.
*
* WARNING: This is only an example for providing a callback, it DOES NOT
* actually decode the PNG it is passed. It hardcodes a response.
*/
bool decode_png(void* userdata,
const GhosttyAllocator* allocator,
const uint8_t* data,
size_t data_len,
GhosttySysImage* out) {
int* count = (int*)userdata;
(*count)++;
printf(" decode_png called (size=%zu, call #%d)\n", data_len, *count);
/* Allocate RGBA pixel data through the provided allocator. */
const size_t pixel_len = 4; /* 1x1 RGBA */
uint8_t* pixels = ghostty_alloc(allocator, pixel_len);
if (!pixels) return false;
/* Fill with red (R=255, G=0, B=0, A=255). */
pixels[0] = 255;
pixels[1] = 0;
pixels[2] = 0;
pixels[3] = 255;
out->width = 1;
out->height = 1;
out->data = pixels;
out->data_len = pixel_len;
return true;
}
//! [kitty-graphics-decode-png]
//! [kitty-graphics-write-pty]
/**
* write_pty callback to capture terminal responses.
*
* The Kitty graphics protocol sends an APC response back to the pty
* when an image is loaded (unless suppressed with q=2).
*/
void on_write_pty(GhosttyTerminal terminal,
void* userdata,
const uint8_t* data,
size_t len) {
(void)terminal;
(void)userdata;
printf(" response (%zu bytes): ", len);
fwrite(data, 1, len, stdout);
printf("\n");
}
//! [kitty-graphics-write-pty]
//! [kitty-graphics-main]
int main() {
/* Install the PNG decoder via the sys interface. */
int decode_count = 0;
ghostty_sys_set(GHOSTTY_SYS_OPT_USERDATA, &decode_count);
ghostty_sys_set(GHOSTTY_SYS_OPT_DECODE_PNG, (const void*)decode_png);
/* Create a terminal with Kitty graphics enabled. */
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions opts = {
.cols = 80,
.rows = 24,
.max_scrollback = 0,
};
if (ghostty_terminal_new(NULL, &terminal, opts) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create terminal\n");
return 1;
}
/* Set cell pixel dimensions so kitty graphics can compute grid sizes. */
ghostty_terminal_resize(terminal, 80, 24, 8, 16);
/* Set a storage limit to enable Kitty graphics. */
uint64_t storage_limit = 64 * 1024 * 1024; /* 64 MiB */
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_STORAGE_LIMIT,
&storage_limit);
/* Install write_pty to see the protocol response. */
ghostty_terminal_set(terminal, GHOSTTY_TERMINAL_OPT_WRITE_PTY,
(const void*)on_write_pty);
/*
* Send a Kitty graphics command with an inline 1x1 PNG image.
*
* The escape sequence is:
* ESC _G a=T,f=100,q=1; <base64 PNG data> ESC \
*
* Where:
* a=T transmit and display
* f=100 PNG format
* q=1 request a response (q=0 would suppress it)
*/
printf("Sending Kitty graphics PNG image:\n");
const char* kitty_cmd =
"\x1b_Ga=T,f=100,q=1;"
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAA"
"DUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg=="
"\x1b\\";
ghostty_terminal_vt_write(terminal, (const uint8_t*)kitty_cmd,
strlen(kitty_cmd));
printf("PNG decode calls: %d\n", decode_count);
/* Query the kitty graphics storage to verify the image was stored. */
GhosttyKittyGraphics graphics = NULL;
if (ghostty_terminal_get(terminal, GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS,
&graphics) != GHOSTTY_SUCCESS || !graphics) {
fprintf(stderr, "Failed to get kitty graphics storage\n");
return 1;
}
printf("\nKitty graphics storage is available.\n");
/* Iterate placements to find the image ID. */
GhosttyKittyGraphicsPlacementIterator iter = NULL;
if (ghostty_kitty_graphics_placement_iterator_new(NULL, &iter) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to create placement iterator\n");
return 1;
}
if (ghostty_kitty_graphics_get(graphics,
GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR, &iter) != GHOSTTY_SUCCESS) {
fprintf(stderr, "Failed to get placement iterator\n");
return 1;
}
int placement_count = 0;
while (ghostty_kitty_graphics_placement_next(iter)) {
placement_count++;
uint32_t image_id = 0;
uint32_t placement_id = 0;
bool is_virtual = false;
int32_t z = 0;
ghostty_kitty_graphics_placement_get_multi(iter, 4,
(GhosttyKittyGraphicsPlacementData[]){
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL,
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z,
},
(void*[]){ &image_id, &placement_id, &is_virtual, &z },
NULL);
printf(" placement #%d: image_id=%u placement_id=%u virtual=%s z=%d\n",
placement_count, image_id, placement_id,
is_virtual ? "true" : "false", z);
/* Look up the image and print its properties. */
GhosttyKittyGraphicsImage image =
ghostty_kitty_graphics_image(graphics, image_id);
if (!image) {
fprintf(stderr, "Failed to look up image %u\n", image_id);
return 1;
}
uint32_t width = 0, height = 0, number = 0;
GhosttyKittyImageFormat format = 0;
size_t data_len = 0;
ghostty_kitty_graphics_image_get_multi(image, 5,
(GhosttyKittyGraphicsImageData[]){
GHOSTTY_KITTY_IMAGE_DATA_NUMBER,
GHOSTTY_KITTY_IMAGE_DATA_WIDTH,
GHOSTTY_KITTY_IMAGE_DATA_HEIGHT,
GHOSTTY_KITTY_IMAGE_DATA_FORMAT,
GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN,
},
(void*[]){ &number, &width, &height, &format, &data_len },
NULL);
printf(" image: number=%u size=%ux%u format=%d data_len=%zu\n",
number, width, height, format, data_len);
/* Compute the rendered pixel size and grid size. */
uint32_t px_w = 0, px_h = 0, cols = 0, rows = 0;
if (ghostty_kitty_graphics_placement_pixel_size(iter, image, terminal,
&px_w, &px_h) == GHOSTTY_SUCCESS) {
printf(" rendered pixel size: %ux%u\n", px_w, px_h);
}
if (ghostty_kitty_graphics_placement_grid_size(iter, image, terminal,
&cols, &rows) == GHOSTTY_SUCCESS) {
printf(" grid size: %u cols x %u rows\n", cols, rows);
}
}
printf("Total placements: %d\n", placement_count);
ghostty_kitty_graphics_placement_iterator_free(iter);
/* Clean up. */
ghostty_terminal_free(terminal);
/* Clear the sys callbacks. */
ghostty_sys_set(GHOSTTY_SYS_OPT_DECODE_PNG, NULL);
ghostty_sys_set(GHOSTTY_SYS_OPT_USERDATA, NULL);
return 0;
}
//! [kitty-graphics-main]

View File

@ -1,18 +0,0 @@
# Example: `ghostty-vt` Mode Utilities
This contains a simple example of how to use the `ghostty-vt` mode
utilities to pack and unpack terminal mode identifiers and encode
DECRPM responses.
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
```

View File

@ -1,42 +0,0 @@
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_modes",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_modes,
.version = "0.0.0",
.fingerprint = 0x67ce079ebc70a02a,
.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",
},
}

View File

@ -1,45 +0,0 @@
#include <stdio.h>
#include <ghostty/vt.h>
//! [modes-pack-unpack]
void modes_example() {
// Create a mode for DEC mode 25 (cursor visible)
GhosttyMode tag = ghostty_mode_new(25, false);
printf("value=%u ansi=%d packed=0x%04x\n",
ghostty_mode_value(tag),
ghostty_mode_ansi(tag),
tag);
// Create a mode for ANSI mode 4 (insert mode)
GhosttyMode ansi_tag = ghostty_mode_new(4, true);
printf("value=%u ansi=%d packed=0x%04x\n",
ghostty_mode_value(ansi_tag),
ghostty_mode_ansi(ansi_tag),
ansi_tag);
}
//! [modes-pack-unpack]
//! [modes-decrpm]
void decrpm_example() {
char buf[32];
size_t written = 0;
// Encode a report that DEC mode 25 (cursor visible) is set
GhosttyResult result = ghostty_mode_report_encode(
GHOSTTY_MODE_CURSOR_VISIBLE,
GHOSTTY_MODE_REPORT_SET,
buf, sizeof(buf), &written);
if (result == GHOSTTY_SUCCESS) {
printf("Encoded %zu bytes: ", written);
fwrite(buf, 1, written, stdout);
printf("\n"); // prints: ESC[?25;1$y
}
}
//! [modes-decrpm]
int main() {
modes_example();
decrpm_example();
return 0;
}

View File

@ -1,7 +1,7 @@
# Example: `ghostty-vt` Paste Utilities
# Example: `ghostty-vt` Paste Safety Check
This contains a simple example of how to use the `ghostty-vt` paste
utilities to check if paste data is safe and encode it for terminal input.
utilities to check if paste data is safe.
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

View File

@ -2,41 +2,18 @@
#include <string.h>
#include <ghostty/vt.h>
//! [paste-safety]
void safety_example() {
const char* safe_data = "hello world";
const char* unsafe_data = "rm -rf /\n";
if (ghostty_paste_is_safe(safe_data, strlen(safe_data))) {
printf("Safe to paste\n");
}
if (!ghostty_paste_is_safe(unsafe_data, strlen(unsafe_data))) {
printf("Unsafe! Contains newline\n");
}
}
//! [paste-safety]
//! [paste-encode]
void encode_example() {
// The input buffer is modified in place (unsafe bytes are stripped).
char data[] = "hello\nworld";
char buf[64];
size_t written = 0;
GhosttyResult result = ghostty_paste_encode(
data, strlen(data), true, buf, sizeof(buf), &written);
if (result == GHOSTTY_SUCCESS) {
printf("Encoded %zu bytes: ", written);
fwrite(buf, 1, written, stdout);
printf("\n");
}
}
//! [paste-encode]
int main() {
safety_example();
// Test safe paste data
const char *safe_data = "hello world";
if (ghostty_paste_is_safe(safe_data, strlen(safe_data))) {
printf("'%s' is safe to paste\n", safe_data);
}
// Test unsafe paste data with newline
const char *unsafe_newline = "rm -rf /\n";
if (!ghostty_paste_is_safe(unsafe_newline, strlen(unsafe_newline))) {
printf("'%s' is UNSAFE - contains newline\n", unsafe_newline);
}
// Test unsafe paste data with bracketed paste end sequence
const char *unsafe_escape = "evil\x1b[201~code";
@ -50,7 +27,5 @@ int main() {
printf("Empty data is safe\n");
}
encode_example();
return 0;
}

View File

@ -1,19 +0,0 @@
# Example: `ghostty-vt` Render State
This contains an example of how to use the `ghostty-vt` render-state API
to create a render state, update it from terminal content, iterate rows
and cells, read styles and colors, inspect cursor and row-local selection
state, and manage dirty tracking.
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
```

View File

@ -1,42 +0,0 @@
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_render",
.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);
}

View File

@ -1,24 +0,0 @@
.{
.name = .c_vt_render,
.version = "0.0.0",
.fingerprint = 0xb10e18b2fab773c9,
.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",
},
}

View File

@ -1,272 +0,0 @@
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
/// Helper: resolve a style color to an RGB value using the palette.
static GhosttyColorRgb resolve_color(GhosttyStyleColor color,
const GhosttyRenderStateColors* colors,
GhosttyColorRgb fallback) {
switch (color.tag) {
case GHOSTTY_STYLE_COLOR_RGB:
return color.value.rgb;
case GHOSTTY_STYLE_COLOR_PALETTE:
return colors->palette[color.value.palette];
default:
return fallback;
}
}
int main(void) {
GhosttyResult result;
//! [render-state-update]
// Create a terminal and render state, then update the render state
// from the terminal. The render state captures a snapshot of everything
// needed to draw a frame.
GhosttyTerminal terminal = NULL;
GhosttyTerminalOptions terminal_opts = {
.cols = 40,
.rows = 5,
.max_scrollback = 10000,
};
result = ghostty_terminal_new(NULL, &terminal, terminal_opts);
assert(result == GHOSTTY_SUCCESS);
GhosttyRenderState render_state = NULL;
result = ghostty_render_state_new(NULL, &render_state);
assert(result == GHOSTTY_SUCCESS);
// Feed some styled content into the terminal.
const char* content =
"Hello, \033[1;32mworld\033[0m!\r\n" // bold green "world"
"\033[4munderlined\033[0m text\r\n" // underlined text
"\033[38;2;255;128;0morange\033[0m\r\n"; // 24-bit orange fg
ghostty_terminal_vt_write(
terminal, (const uint8_t*)content, strlen(content));
// Select "underlined" on the second row. Render state exposes this
// later as a row-local selected cell range.
GhosttyGridRef selection_start = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyPoint selection_start_pt = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 0, .y = 1 } },
};
result = ghostty_terminal_grid_ref(
terminal, selection_start_pt, &selection_start);
assert(result == GHOSTTY_SUCCESS);
GhosttyGridRef selection_end = GHOSTTY_INIT_SIZED(GhosttyGridRef);
GhosttyPoint selection_end_pt = {
.tag = GHOSTTY_POINT_TAG_ACTIVE,
.value = { .coordinate = { .x = 9, .y = 1 } },
};
result = ghostty_terminal_grid_ref(terminal, selection_end_pt, &selection_end);
assert(result == GHOSTTY_SUCCESS);
GhosttySelection selection = GHOSTTY_INIT_SIZED(GhosttySelection);
selection.start = selection_start;
selection.end = selection_end;
result = ghostty_terminal_set(
terminal, GHOSTTY_TERMINAL_OPT_SELECTION, &selection);
assert(result == GHOSTTY_SUCCESS);
result = ghostty_render_state_update(render_state, terminal);
assert(result == GHOSTTY_SUCCESS);
//! [render-state-update]
//! [render-dirty-check]
// Check the global dirty state to decide how much work the renderer
// needs to do. After rendering, reset it to false.
GhosttyRenderStateDirty dirty;
result = ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_DIRTY, &dirty);
assert(result == GHOSTTY_SUCCESS);
switch (dirty) {
case GHOSTTY_RENDER_STATE_DIRTY_FALSE:
printf("Frame is clean, nothing to draw.\n");
break;
case GHOSTTY_RENDER_STATE_DIRTY_PARTIAL:
printf("Partial redraw needed.\n");
break;
case GHOSTTY_RENDER_STATE_DIRTY_FULL:
printf("Full redraw needed.\n");
break;
}
//! [render-dirty-check]
//! [render-colors]
// Retrieve colors (background, foreground, palette) from the render
// state. These are needed to resolve palette-indexed cell colors.
GhosttyRenderStateColors colors =
GHOSTTY_INIT_SIZED(GhosttyRenderStateColors);
result = ghostty_render_state_colors_get(render_state, &colors);
assert(result == GHOSTTY_SUCCESS);
printf("Background: #%02x%02x%02x\n",
colors.background.r, colors.background.g, colors.background.b);
printf("Foreground: #%02x%02x%02x\n",
colors.foreground.r, colors.foreground.g, colors.foreground.b);
//! [render-colors]
//! [render-cursor]
// Read cursor position and visual style from the render state.
bool cursor_visible = false;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VISIBLE,
&cursor_visible);
bool cursor_in_viewport = false;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_HAS_VALUE,
&cursor_in_viewport);
if (cursor_visible && cursor_in_viewport) {
uint16_t cx, cy;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_X, &cx);
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_Y, &cy);
GhosttyRenderStateCursorVisualStyle style;
ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_CURSOR_VISUAL_STYLE,
&style);
const char* style_name = "unknown";
switch (style) {
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BAR:
style_name = "bar";
break;
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK:
style_name = "block";
break;
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_UNDERLINE:
style_name = "underline";
break;
case GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK_HOLLOW:
style_name = "hollow";
break;
}
printf("Cursor at (%u, %u), style: %s\n", cx, cy, style_name);
}
//! [render-cursor]
//! [render-row-iterate]
// Iterate rows via the row iterator. For each dirty row, iterate its
// cells, read codepoints/graphemes and styles, and emit ANSI-colored
// output as a simple "renderer".
GhosttyRenderStateRowIterator row_iter = NULL;
result = ghostty_render_state_row_iterator_new(NULL, &row_iter);
assert(result == GHOSTTY_SUCCESS);
result = ghostty_render_state_get(
render_state, GHOSTTY_RENDER_STATE_DATA_ROW_ITERATOR, &row_iter);
assert(result == GHOSTTY_SUCCESS);
GhosttyRenderStateRowCells cells = NULL;
result = ghostty_render_state_row_cells_new(NULL, &cells);
assert(result == GHOSTTY_SUCCESS);
int row_index = 0;
while (ghostty_render_state_row_iterator_next(row_iter)) {
// Check per-row dirty state; a real renderer would skip clean rows.
bool row_dirty = false;
ghostty_render_state_row_get(
row_iter, GHOSTTY_RENDER_STATE_ROW_DATA_DIRTY, &row_dirty);
printf("Row %2d [%s]: ", row_index,
row_dirty ? "dirty" : "clean");
// Query the row-local selection range. Rows without a selection return
// GHOSTTY_NO_VALUE; selected rows return inclusive start/end columns.
GhosttyRenderStateRowSelection row_selection =
GHOSTTY_INIT_SIZED(GhosttyRenderStateRowSelection);
result = ghostty_render_state_row_get(
row_iter, GHOSTTY_RENDER_STATE_ROW_DATA_SELECTION, &row_selection);
assert(result == GHOSTTY_SUCCESS || result == GHOSTTY_NO_VALUE);
if (result == GHOSTTY_SUCCESS) {
printf("selection=%u..%u ",
row_selection.start_x, row_selection.end_x);
}
// Get cells for this row (reuses the same cells handle).
result = ghostty_render_state_row_get(
row_iter, GHOSTTY_RENDER_STATE_ROW_DATA_CELLS, &cells);
assert(result == GHOSTTY_SUCCESS);
while (ghostty_render_state_row_cells_next(cells)) {
// Get the grapheme length; 0 means the cell is empty.
uint32_t grapheme_len = 0;
ghostty_render_state_row_cells_get(
cells, GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_LEN,
&grapheme_len);
if (grapheme_len == 0) {
putchar(' ');
continue;
}
// Read the style for this cell. Returns the default style for
// cells that have no explicit styling.
GhosttyStyle style = GHOSTTY_INIT_SIZED(GhosttyStyle);
ghostty_render_state_row_cells_get(
cells, GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_STYLE, &style);
// Resolve foreground color for this cell.
GhosttyColorRgb fg =
resolve_color(style.fg_color, &colors, colors.foreground);
// Emit ANSI true-color escape for the foreground.
printf("\033[38;2;%u;%u;%um", fg.r, fg.g, fg.b);
if (style.bold) printf("\033[1m");
if (style.underline) printf("\033[4m");
// Read grapheme codepoints into a buffer and print them.
// The buffer must be at least grapheme_len elements.
uint32_t codepoints[16];
uint32_t len = grapheme_len < 16 ? grapheme_len : 16;
ghostty_render_state_row_cells_get(
cells, GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_BUF,
codepoints);
for (uint32_t i = 0; i < len; i++) {
// Simple ASCII print; a real renderer would handle UTF-8.
if (codepoints[i] < 128)
putchar((char)codepoints[i]);
else
printf("U+%04X", codepoints[i]);
}
printf("\033[0m"); // Reset style after each cell.
}
printf("\n");
// Clear per-row dirty flag after "rendering" it.
bool clean = false;
ghostty_render_state_row_set(
row_iter, GHOSTTY_RENDER_STATE_ROW_OPTION_DIRTY, &clean);
row_index++;
}
//! [render-row-iterate]
//! [render-dirty-reset]
// After finishing the frame, reset the global dirty state so the next
// update can report changes accurately.
GhosttyRenderStateDirty clean_state = GHOSTTY_RENDER_STATE_DIRTY_FALSE;
result = ghostty_render_state_set(
render_state, GHOSTTY_RENDER_STATE_OPTION_DIRTY, &clean_state);
assert(result == GHOSTTY_SUCCESS);
//! [render-dirty-reset]
// Cleanup
ghostty_render_state_row_cells_free(cells);
ghostty_render_state_row_iterator_free(row_iter);
ghostty_render_state_free(render_state);
ghostty_terminal_free(terminal);
return 0;
}

View File

@ -1,18 +0,0 @@
# Example: `ghostty-vt` Selection Gestures
This contains a simple example of how to use the `ghostty-vt` selection
gesture API from C. It creates synthetic press, drag, release, and deep-press
events and formats the resulting selection snapshots.
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
```

Some files were not shown because too many files have changed in this diff Show More