Merge branch 'main' into terminal/word-selection-adjustment
commit
c23773125a
|
|
@ -1,3 +1,47 @@
|
|||
#--------------------------------------------------------------------
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -19,14 +19,23 @@
|
|||
# discussion by the author. Maintainers can denounce users by commenting
|
||||
# "!denounce" or "!denounce [username]" on a discussion.
|
||||
00-kat
|
||||
007hacky007
|
||||
00jciv00
|
||||
04cb
|
||||
0xdvc
|
||||
-4rh1t3ct0r7
|
||||
aalhendi
|
||||
aaron-ang
|
||||
abdurrahmanski
|
||||
abudvytis
|
||||
adrum
|
||||
agoodkind
|
||||
aindriu80
|
||||
ajiblock
|
||||
akimiojr
|
||||
alaasdk
|
||||
alanmoyano
|
||||
alaviss
|
||||
alexfeijoo44
|
||||
alexjuca
|
||||
alosarjos
|
||||
|
|
@ -35,16 +44,23 @@ andrejdaskalov
|
|||
anhthang
|
||||
anmitalidev
|
||||
anthonyzhoon
|
||||
athaapa
|
||||
atomk
|
||||
b0uks
|
||||
b1nar10
|
||||
balazs-szucs
|
||||
barutsrb
|
||||
bch
|
||||
bennettp123
|
||||
benodiwal
|
||||
bernsno
|
||||
beryesa
|
||||
bitigchi
|
||||
bkircher
|
||||
bleikurr
|
||||
bo2themax
|
||||
brentschroeter
|
||||
brianc442
|
||||
cespare
|
||||
charliie-dev
|
||||
chernetskyi
|
||||
|
|
@ -53,35 +69,50 @@ 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
|
||||
|
|
@ -90,32 +121,50 @@ heddxh heddxh
|
|||
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
|
||||
|
|
@ -124,26 +173,41 @@ markhuot
|
|||
marler8997
|
||||
marrocco-simone
|
||||
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
|
||||
|
|
@ -159,19 +223,30 @@ 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
|
||||
|
|
@ -181,10 +256,16 @@ tweedbeetle
|
|||
uhojin
|
||||
unphased
|
||||
uzaaft
|
||||
vancluever
|
||||
vaughanandrews
|
||||
viruslobster
|
||||
vlsi
|
||||
voidnv
|
||||
wyounas
|
||||
yabbal
|
||||
yamshta
|
||||
ydah
|
||||
-zaviro
|
||||
zenyr
|
||||
zeshi09
|
||||
zubb
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
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.
|
||||
|
|
@ -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@92ae9851ad316786193b1fd3f40c4b51eb5cb101 # v6.6
|
||||
- uses: flatpak/flatpak-github-actions/flatpak-builder@401fe28a8384095fc1531b9d320b292f0ee45adb # v6.7
|
||||
with:
|
||||
bundle: com.mitchellh.ghostty
|
||||
manifest-path: dist/flatpak/com.mitchellh.ghostty.yml
|
||||
|
|
|
|||
|
|
@ -41,16 +41,16 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
path: |
|
||||
/nix
|
||||
/zig
|
||||
- name: Setup Nix
|
||||
uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
|
||||
uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
with:
|
||||
name: ghostty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
|
|
|||
|
|
@ -83,17 +83,17 @@ jobs:
|
|||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
path: |
|
||||
/nix
|
||||
/zig
|
||||
|
||||
- uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
|
||||
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: source-tarball
|
||||
path: |-
|
||||
|
|
@ -137,7 +137,7 @@ jobs:
|
|||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
cache: |
|
||||
xcode
|
||||
|
|
@ -147,13 +147,13 @@ jobs:
|
|||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
with:
|
||||
determinate: true
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- 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.2.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: macos
|
||||
path: |-
|
||||
|
|
@ -353,7 +353,7 @@ jobs:
|
|||
mv appcast_new.xml appcast.xml
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: sparkle
|
||||
path: |-
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ jobs:
|
|||
# Important so that build number generation works
|
||||
fetch-depth: 0
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
path: |
|
||||
/nix
|
||||
- uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
|
||||
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
with:
|
||||
name: ghostty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
|
@ -163,22 +163,22 @@ jobs:
|
|||
github.ref_name == 'main'
|
||||
)
|
||||
)
|
||||
runs-on: namespace-profile-ghostty-md
|
||||
runs-on: namespace-profile-ghostty-sm
|
||||
env:
|
||||
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
|
||||
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
path: |
|
||||
/nix
|
||||
/zig
|
||||
- uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
|
||||
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
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@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
name: 'Ghostty Tip ("Nightly")'
|
||||
prerelease: true
|
||||
|
|
@ -206,6 +206,165 @@ 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- 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: |
|
||||
|
|
@ -234,7 +393,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
cache: |
|
||||
xcode
|
||||
|
|
@ -245,13 +404,13 @@ jobs:
|
|||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
with:
|
||||
determinate: true
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- 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.2.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
|
|
@ -378,7 +537,7 @@ jobs:
|
|||
|
||||
# Update Release
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
name: 'Ghostty Tip ("Nightly")'
|
||||
prerelease: true
|
||||
|
|
@ -456,7 +615,7 @@ jobs:
|
|||
EOF
|
||||
|
||||
- name: Upload Release URLs
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v6.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v6.0
|
||||
with:
|
||||
name: release-urls-${{ inputs.pr || '0' }}
|
||||
path: release-urls.txt
|
||||
|
|
@ -490,7 +649,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
cache: |
|
||||
xcode
|
||||
|
|
@ -501,13 +660,13 @@ jobs:
|
|||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
with:
|
||||
determinate: true
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- 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.2.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
|
|
@ -627,7 +786,7 @@ jobs:
|
|||
|
||||
# Update Release
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
name: 'Ghostty Tip ("Nightly")'
|
||||
prerelease: true
|
||||
|
|
@ -687,7 +846,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
cache: |
|
||||
xcode
|
||||
|
|
@ -698,13 +857,13 @@ jobs:
|
|||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
with:
|
||||
determinate: true
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- 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.2.app
|
||||
run: sudo xcode-select -s /Applications/Xcode_26.3.app
|
||||
|
||||
- name: Xcode Version
|
||||
run: xcodebuild -version
|
||||
|
|
@ -824,7 +983,7 @@ jobs:
|
|||
|
||||
# Update Release
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
name: 'Ghostty Tip ("Nightly")'
|
||||
prerelease: true
|
||||
|
|
|
|||
|
|
@ -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@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
path: |
|
||||
/nix
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -22,17 +22,17 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
||||
uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3
|
||||
with:
|
||||
path: |
|
||||
/nix
|
||||
/zig
|
||||
|
||||
- name: Setup Nix
|
||||
uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1
|
||||
uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
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@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||
with:
|
||||
title: Update iTerm2 colorschemes
|
||||
base: main
|
||||
|
|
|
|||
|
|
@ -8,15 +8,21 @@ jobs:
|
|||
check:
|
||||
runs-on: namespace-profile-ghostty-xsm
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
|
||||
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.VOUCH_APP_ID }}
|
||||
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: mitchellh/vouch/action/check-issue@c6d80ead49839655b61b422700b7a3bc9d0804a9 # v1.4.2
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
sparse-checkout: .github/issue-unvouched-message
|
||||
|
||||
- uses: mitchellh/vouch/action/check-issue@52aec3d64655edf2fdb58f298e02da754a056daf # unreleased main
|
||||
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 }}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ jobs:
|
|||
check:
|
||||
runs-on: namespace-profile-ghostty-xsm
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
|
||||
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.VOUCH_APP_ID }}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
manage:
|
||||
runs-on: namespace-profile-ghostty-xsm
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
|
||||
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.VOUCH_APP_ID }}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
manage:
|
||||
runs-on: namespace-profile-ghostty-xsm
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
|
||||
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.VOUCH_APP_ID }}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
sync:
|
||||
runs-on: namespace-profile-ghostty-xsm
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
|
||||
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.VOUCH_APP_ID }}
|
||||
|
|
|
|||
|
|
@ -26,3 +26,6 @@ website/.next
|
|||
# fuzz corpus files
|
||||
test/fuzz-libghostty/corpus/
|
||||
test/fuzz-libghostty/afl-out/
|
||||
|
||||
# Swift example build outputs
|
||||
example/swift-vt-xcframework/.build/
|
||||
|
|
|
|||
|
|
@ -16,6 +16,15 @@ 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/`
|
||||
|
|
|
|||
215
CMakeLists.txt
215
CMakeLists.txt
|
|
@ -44,8 +44,27 @@
|
|||
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt) # shared
|
||||
# target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt-static) # static
|
||||
#
|
||||
# See dist/cmake/README.md for more details and example/c-vt-cmake/ for a
|
||||
# complete working example.
|
||||
# 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)
|
||||
|
|
@ -54,15 +73,22 @@ project(ghostty-vt VERSION 0.1.0 LANGUAGES C)
|
|||
|
||||
set(GHOSTTY_ZIG_BUILD_FLAGS "" CACHE STRING "Additional flags to pass to zig build")
|
||||
|
||||
# Map CMake build types to Zig optimization levels.
|
||||
# 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")
|
||||
list(APPEND GHOSTTY_ZIG_BUILD_FLAGS "-Doptimize=ReleaseFast")
|
||||
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)
|
||||
|
|
@ -81,16 +107,27 @@ if(APPLE)
|
|||
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()
|
||||
|
||||
set(GHOSTTY_VT_SHARED_LIBRARY "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_REALNAME}")
|
||||
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.
|
||||
set(GHOSTTY_VT_STATIC_REALNAME "${CMAKE_STATIC_LIBRARY_PREFIX}ghostty-vt${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
# 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
|
||||
|
|
@ -99,7 +136,7 @@ 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}"
|
||||
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..."
|
||||
|
|
@ -110,6 +147,11 @@ 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
|
||||
|
|
@ -122,7 +164,11 @@ if(APPLE)
|
|||
set_target_properties(ghostty-vt PROPERTIES
|
||||
IMPORTED_SONAME "@rpath/${GHOSTTY_VT_SONAME}"
|
||||
)
|
||||
elseif(NOT WIN32)
|
||||
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}"
|
||||
)
|
||||
|
|
@ -131,20 +177,28 @@ add_dependencies(ghostty-vt zig_build_lib_vt)
|
|||
|
||||
# Static
|
||||
#
|
||||
# When linking the static library, consumers must also link its transitive
|
||||
# dependencies. By default (with SIMD enabled), these are:
|
||||
# - libc
|
||||
# - libc++ (or libstdc++ on Linux)
|
||||
# - highway
|
||||
# - simdutf
|
||||
# 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.
|
||||
#
|
||||
# Building with -Dsimd=false removes the C++ / highway / simdutf
|
||||
# dependencies, leaving only 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 ------------------------------------------------------------------
|
||||
|
|
@ -152,8 +206,12 @@ add_dependencies(ghostty-vt-static zig_build_lib_vt)
|
|||
include(GNUInstallDirs)
|
||||
|
||||
# Install shared library
|
||||
install(FILES "${GHOSTTY_VT_SHARED_LIBRARY}" TYPE LIB)
|
||||
if(NOT WIN32)
|
||||
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
|
||||
|
|
@ -196,3 +254,124 @@ install(
|
|||
"${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()
|
||||
|
|
|
|||
|
|
@ -162,14 +162,17 @@
|
|||
/src/surface_mouse.zig @ghostty-org/terminal
|
||||
|
||||
# Localization
|
||||
/po/README_TRANSLATORS.md @ghostty-org/localization
|
||||
/po/com.mitchellh.ghostty.pot @ghostty-org/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/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
|
||||
|
|
|
|||
|
|
@ -177,11 +177,6 @@ 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.
|
||||
|
|
|
|||
|
|
@ -67,6 +67,14 @@ 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
145
README.md
|
|
@ -7,6 +7,8 @@
|
|||
<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>
|
||||
|
|
@ -26,20 +28,13 @@ 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.
|
||||
|
||||
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.
|
||||
**`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.
|
||||
|
||||
For more details, see [About Ghostty](https://ghostty.org/docs/about).
|
||||
|
||||
|
|
@ -61,30 +56,37 @@ 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 | 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) | ❌ |
|
||||
| # | 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 | ❌ |
|
||||
|
||||
Additional details for each step in the big roadmap below:
|
||||
|
||||
#### Standards-Compliant Terminal Emulation
|
||||
|
||||
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)
|
||||
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)
|
||||
comparing Ghostty's behavior to xterm and building a set of conformance
|
||||
test cases.
|
||||
|
||||
We believe Ghostty is one of the most compliant terminal emulators available.
|
||||
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.
|
||||
|
||||
Terminal behavior is partially a de jure standard
|
||||
(i.e. [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/))
|
||||
|
|
@ -96,33 +98,30 @@ views as a "standard."
|
|||
|
||||
#### Competitive Performance
|
||||
|
||||
We need better benchmarks to continuously verify this, but Ghostty is
|
||||
generally in the same performance category as the other highest performing
|
||||
terminal emulators.
|
||||
Ghostty is generally in the same performance category as the other highest
|
||||
performing terminal emulators.
|
||||
|
||||
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.
|
||||
"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 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.
|
||||
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.
|
||||
|
||||
> [!NOTE]
|
||||
> Despite being _very fast_, there is a lot of room for improvement here.
|
||||
|
||||
#### Richer Windowing Features
|
||||
#### Rich Windowing Features
|
||||
|
||||
The Mac and Linux (build with GTK) apps support multi-window, tabbing, and
|
||||
splits.
|
||||
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.
|
||||
|
||||
#### Native Platform Experiences
|
||||
|
||||
|
|
@ -133,10 +132,15 @@ 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.
|
||||
|
||||
There are more improvements to be made. The macOS settings window is still
|
||||
a work-in-progress. Similar improvements will follow with Linux.
|
||||
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.
|
||||
|
||||
#### Cross-platform `libghostty` for Embeddable Terminals
|
||||
|
||||
|
|
@ -145,21 +149,40 @@ 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 actually libraries, starting with `libghostty-vt`. The goal of
|
||||
separate 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. 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.
|
||||
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.
|
||||
|
||||
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.
|
||||
`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.
|
||||
|
||||
## Crash Reports
|
||||
|
||||
|
|
|
|||
106
build.zig
106
build.zig
|
|
@ -3,11 +3,17 @@ const assert = std.debug.assert;
|
|||
const builtin = @import("builtin");
|
||||
const buildpkg = @import("src/build/main.zig");
|
||||
|
||||
const appVersion = @import("build.zig.zon").version;
|
||||
const minimumZigVersion = @import("build.zig.zon").minimum_zig_version;
|
||||
/// 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;
|
||||
|
||||
comptime {
|
||||
buildpkg.requireZig(minimumZigVersion);
|
||||
buildpkg.requireZig(minimum_zig_version);
|
||||
}
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
|
|
@ -15,7 +21,24 @@ 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`.
|
||||
|
||||
const config = try buildpkg.Config.init(b, appVersion);
|
||||
// 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 test_filters = b.option(
|
||||
[][]const u8,
|
||||
"test-filter",
|
||||
|
|
@ -106,27 +129,45 @@ pub fn build(b: *std.Build) !void {
|
|||
};
|
||||
libghostty_vt_shared.install(b.getInstallStep());
|
||||
|
||||
// libghostty-vt static lib. We don't build this for wasm since wasm has
|
||||
// no concept of static vs shared and we put the wasm binary up in
|
||||
// our shared handling.
|
||||
if (!config.target.result.cpu.arch.isWasm()) {
|
||||
const libghostty_vt_static = try buildpkg.GhosttyLibVt.initStatic(
|
||||
// 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,
|
||||
);
|
||||
|
||||
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.
|
||||
b.getInstallStep().dependOn(&b.addInstallLibFile(
|
||||
libghostty_vt_static.output,
|
||||
"libghostty-vt.a",
|
||||
).step);
|
||||
}
|
||||
const xcframework = buildpkg.GhosttyLibVt.xcframework(&apple_libs, b);
|
||||
b.getInstallStep().dependOn(xcframework.step);
|
||||
}
|
||||
|
||||
// Helpgen
|
||||
|
|
@ -152,14 +193,20 @@ pub fn build(b: *std.Build) !void {
|
|||
// 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
|
||||
lib_shared.install("libghostty.so");
|
||||
lib_static.install("libghostty.a");
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// macOS only artifacts. These will error if they're initialized for
|
||||
// other targets.
|
||||
if (config.target.result.os.tag.isDarwin() and
|
||||
// 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))
|
||||
{
|
||||
// Ghostty xcframework
|
||||
|
|
@ -216,7 +263,8 @@ 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.target.result.os.tag.isDarwin() and
|
||||
if (!config.emit_lib_vt and
|
||||
config.target.result.os.tag.isDarwin() and
|
||||
(config.emit_xcframework or config.emit_macos_app))
|
||||
{
|
||||
const xcframework_native = try buildpkg.GhosttyXCFramework.init(
|
||||
|
|
@ -287,8 +335,8 @@ pub fn build(b: *std.Build) !void {
|
|||
test_lib_vt_step.dependOn(&mod_vt_c_test_run.step);
|
||||
}
|
||||
|
||||
// Tests
|
||||
{
|
||||
// Tests (skip when building libghostty-vt)
|
||||
if (!config.emit_lib_vt) {
|
||||
// Full unit tests
|
||||
const test_exe = b.addTest(.{
|
||||
.name = "ghostty-test",
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@
|
|||
.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 },
|
||||
|
||||
|
|
@ -117,8 +116,8 @@
|
|||
.apple_sdk = .{ .path = "./pkg/apple-sdk" },
|
||||
.android_ndk = .{ .path = "./pkg/android-ndk" },
|
||||
.iterm2_themes = .{
|
||||
.url = "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz",
|
||||
.hash = "N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF",
|
||||
.url = "https://deps.files.ghostty.org/ghostty-themes-release-20260511-160054-2671288.tgz",
|
||||
.hash = "N-V-__8AAPy1AwDnEoq1ww42uq58nusIeQgR16W4-5SQZFIM",
|
||||
.lazy = true,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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-2b1DBvAIHY5LhItq3+q9L6tJgi7itnnrSAHc7fXWDEg="
|
||||
"hash": "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc="
|
||||
},
|
||||
"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-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF": {
|
||||
"N-V-__8AAPy1AwDnEoq1ww42uq58nusIeQgR16W4-5SQZFIM": {
|
||||
"name": "iterm2_themes",
|
||||
"url": "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz",
|
||||
"hash": "sha256-FCALuGoMgUq2lgnVALKAs5a20uuDXt8Gdt5KeJwKqP0="
|
||||
"url": "https://deps.files.ghostty.org/ghostty-themes-release-20260511-160054-2671288.tgz",
|
||||
"hash": "sha256-R2NJUKxz2LHRiCBi/MAnN3XzMyY4VWlbX0uWCbWefjQ="
|
||||
},
|
||||
"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-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc="
|
||||
"hash": "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg="
|
||||
},
|
||||
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
|
||||
"name": "libxml2",
|
||||
|
|
@ -109,11 +109,6 @@
|
|||
"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",
|
||||
|
|
@ -122,12 +117,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-0KvuD0+L1urjwFF3fhbnxC2JZKqqAVWRxOVlcD9GX5U="
|
||||
"hash": "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg="
|
||||
},
|
||||
"vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS": {
|
||||
"name": "vaxis",
|
||||
"url": "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz",
|
||||
"hash": "sha256-LnIzK8icW1Qexua9SHaeHz+3V8QAbz0a+UC1T5sIjvY="
|
||||
"hash": "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y="
|
||||
},
|
||||
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
|
||||
"name": "wayland",
|
||||
|
|
@ -152,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-afIdou/V7gk3/lXE0J5Ir8T7L5GgHvFnyMJ1rgRnl/c="
|
||||
"hash": "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E="
|
||||
},
|
||||
"zf-0.10.3-OIRy8RuJAACKA3Lohoumrt85nRbHwbpMcUaLES8vxDnh": {
|
||||
"name": "zf",
|
||||
"url": "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz",
|
||||
"hash": "sha256-OwFdkorwTp4mJyvBXrTbtNmp1GnrbSkKDdrmc7d8RWg="
|
||||
"hash": "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY="
|
||||
},
|
||||
"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-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M="
|
||||
"hash": "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4="
|
||||
},
|
||||
"zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK": {
|
||||
"name": "zig_objc",
|
||||
"url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
|
||||
"hash": "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw="
|
||||
"hash": "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM="
|
||||
},
|
||||
"wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe": {
|
||||
"name": "zig_wayland",
|
||||
"url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
|
||||
"hash": "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4="
|
||||
"hash": "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw="
|
||||
},
|
||||
"zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms": {
|
||||
"name": "zigimg",
|
||||
"url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
|
||||
"hash": "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM="
|
||||
"hash": "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A="
|
||||
},
|
||||
"N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
|
||||
"name": "zlib",
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
{
|
||||
lib,
|
||||
linkFarm,
|
||||
fetchzip,
|
||||
fetchurl,
|
||||
fetchgit,
|
||||
runCommandLocal,
|
||||
zig_0_15,
|
||||
zstd,
|
||||
name ? "zig-packages",
|
||||
}: let
|
||||
unpackZigArtifact = {
|
||||
|
|
@ -17,7 +19,7 @@
|
|||
nativeBuildInputs = [zig_0_15];
|
||||
}
|
||||
''
|
||||
hash="$(zig fetch --global-cache-dir "$TMPDIR" ${artifact})"
|
||||
hash="$(cd "$TMPDIR" && zig fetch --global-cache-dir "$TMPDIR" ${artifact})"
|
||||
mv "$TMPDIR/p/$hash" "$out"
|
||||
chmod 755 "$out"
|
||||
'';
|
||||
|
|
@ -26,8 +28,16 @@
|
|||
name,
|
||||
url,
|
||||
hash,
|
||||
unpack,
|
||||
}: let
|
||||
artifact = fetchurl {inherit url hash;};
|
||||
artifact =
|
||||
if unpack
|
||||
then
|
||||
fetchzip {
|
||||
inherit url hash;
|
||||
nativeBuildInputs = [zstd];
|
||||
}
|
||||
else fetchurl {inherit url hash;};
|
||||
in
|
||||
unpackZigArtifact {inherit name artifact;};
|
||||
|
||||
|
|
@ -56,6 +66,7 @@
|
|||
name,
|
||||
url,
|
||||
hash,
|
||||
unpack,
|
||||
}: let
|
||||
parts = lib.splitString "://" url;
|
||||
proto = builtins.elemAt parts 0;
|
||||
|
|
@ -70,11 +81,11 @@
|
|||
url = "https://${path}";
|
||||
};
|
||||
http = fetchZig {
|
||||
inherit name hash;
|
||||
inherit name hash unpack;
|
||||
url = "http://${path}";
|
||||
};
|
||||
https = fetchZig {
|
||||
inherit name hash;
|
||||
inherit name hash unpack;
|
||||
url = "https://${path}";
|
||||
};
|
||||
};
|
||||
|
|
@ -88,6 +99,7 @@ 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;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -96,6 +108,7 @@ in
|
|||
name = "breakpad";
|
||||
url = "https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.tar.gz";
|
||||
hash = "sha256-bMqYlD0amQdmzvYQd8Ca/1k4Bj/heh7+EijlQSttatk=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -104,6 +117,7 @@ in
|
|||
name = "fontconfig";
|
||||
url = "https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz";
|
||||
hash = "sha256-O6LdkhWHGKzsXKrxpxYEO1qgVcJ7CB2RSvPMtA3OilU=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -112,6 +126,7 @@ in
|
|||
name = "freetype";
|
||||
url = "https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz";
|
||||
hash = "sha256-QnIB9dUVFnDQXB9bRb713aHy592XHvVPD+qqf/0quQw=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -120,6 +135,7 @@ in
|
|||
name = "gettext";
|
||||
url = "https://deps.files.ghostty.org/gettext-0.24.tar.gz";
|
||||
hash = "sha256-yRhQPVk9cNr0hE0XWhPYFq+stmfAb7oeydzVACwVGLc=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -128,6 +144,7 @@ in
|
|||
name = "glslang";
|
||||
url = "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz";
|
||||
hash = "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -135,7 +152,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "gobject";
|
||||
url = "https://deps.files.ghostty.org/gobject-2025-11-08-23-1.tar.zst";
|
||||
hash = "sha256-2b1DBvAIHY5LhItq3+q9L6tJgi7itnnrSAHc7fXWDEg=";
|
||||
hash = "sha256-OxS9/XC5aMJj1KhOcFP1ZZN7PI4ADw4f7ocx6V64mOc=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -144,6 +162,7 @@ in
|
|||
name = "gtk4_layer_shell";
|
||||
url = "https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz";
|
||||
hash = "sha256-mChCgSYKXu9bT2OlXxbEv2p4ihAgptsDfssPcfozaYg=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -152,6 +171,7 @@ in
|
|||
name = "harfbuzz";
|
||||
url = "https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz";
|
||||
hash = "sha256-8WNRuv4hRyX+LB1bWfDZPkmQWkskeJn7kNcM/5U6K5s=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -160,6 +180,7 @@ in
|
|||
name = "highway";
|
||||
url = "https://deps.files.ghostty.org/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz";
|
||||
hash = "sha256-h9T4iT704I8iSXNgj/6/lCaKgTgLp5wS6IQZaMgKohI=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -168,14 +189,16 @@ 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-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF";
|
||||
name = "N-V-__8AAPy1AwDnEoq1ww42uq58nusIeQgR16W4-5SQZFIM";
|
||||
path = fetchZigArtifact {
|
||||
name = "iterm2_themes";
|
||||
url = "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz";
|
||||
hash = "sha256-FCALuGoMgUq2lgnVALKAs5a20uuDXt8Gdt5KeJwKqP0=";
|
||||
url = "https://deps.files.ghostty.org/ghostty-themes-release-20260511-160054-2671288.tgz";
|
||||
hash = "sha256-R2NJUKxz2LHRiCBi/MAnN3XzMyY4VWlbX0uWCbWefjQ=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -184,6 +207,7 @@ in
|
|||
name = "jetbrains_mono";
|
||||
url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz";
|
||||
hash = "sha256-xXppHouCrQmLWWPzlZAy5AOPORCHr3cViFulkEYQXMQ=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -192,6 +216,7 @@ in
|
|||
name = "libpng";
|
||||
url = "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz";
|
||||
hash = "sha256-/syVtGzwXo4/yKQUdQ4LparQDYnp/fF16U/wQcrxoDo=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -199,7 +224,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "libxev";
|
||||
url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz";
|
||||
hash = "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc=";
|
||||
hash = "sha256-1B9oJExVyOWRj+Y9d9eHkOBTlOYuEkcwGBUKdlgRhkg=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -208,6 +234,7 @@ in
|
|||
name = "libxml2";
|
||||
url = "https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz";
|
||||
hash = "sha256-bCgFni4+60K1tLFkieORamNGwQladP7jvGXNxdiaYhU=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -216,6 +243,7 @@ in
|
|||
name = "nerd_fonts_symbols_only";
|
||||
url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz";
|
||||
hash = "sha256-EWTRuVbUveJI17LwmYxDzJT1ICQxoVZKeTiVsec7DQQ=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -224,6 +252,7 @@ in
|
|||
name = "oniguruma";
|
||||
url = "https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz";
|
||||
hash = "sha256-ABqhIC54RI9MC/GkjHblVodrNvFtks4yB+zP1h2Z8qA=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -232,6 +261,7 @@ in
|
|||
name = "pixels";
|
||||
url = "https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d83b5801a932dcd44917424c8806.tar.gz";
|
||||
hash = "sha256-Veg7FtCRCCUCvxSb9FfzH0IJLFmCZQ4/+657SIcb8Ro=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -240,6 +270,7 @@ in
|
|||
name = "plasma_wayland_protocols";
|
||||
url = "https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e893e0132fc87bb763969a585dc16ecca33e88334c566.tar.gz";
|
||||
hash = "sha256-XFi6IUrNjmvKNCbcCLAixGqN2Zeymhs+KLrfccIN9EE=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -248,6 +279,7 @@ in
|
|||
name = "sentry";
|
||||
url = "https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz";
|
||||
hash = "sha256-KsZJfMjWGo0xCT5HrduMmyxFsWsHBbszSoNbZCPDGN8=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -256,14 +288,7 @@ in
|
|||
name = "spirv_cross";
|
||||
url = "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz";
|
||||
hash = "sha256-tStvz8Ref6abHwahNiwVVHNETizAmZVVaxVsU7pmV+M=";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH";
|
||||
path = fetchZigArtifact {
|
||||
name = "utfcpp";
|
||||
url = "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz";
|
||||
hash = "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -272,6 +297,7 @@ in
|
|||
name = "uucode";
|
||||
url = "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732";
|
||||
hash = "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -279,7 +305,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "uucode";
|
||||
url = "https://deps.files.ghostty.org/uucode-0.2.0-ZZjBPqZVVABQepOqZHR7vV_NcaN-wats0IB6o-Exj6m9.tar.gz";
|
||||
hash = "sha256-0KvuD0+L1urjwFF3fhbnxC2JZKqqAVWRxOVlcD9GX5U=";
|
||||
hash = "sha256-jLrhrmCXQ1T+LQP1JTBBB3Jn+1hCZfODbC4SdlfNdKg=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -287,7 +314,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "vaxis";
|
||||
url = "https://deps.files.ghostty.org/vaxis-7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz";
|
||||
hash = "sha256-LnIzK8icW1Qexua9SHaeHz+3V8QAbz0a+UC1T5sIjvY=";
|
||||
hash = "sha256-zTyrZrIffM+GJIt973tKDeWHmOCwbn7KLDdQxSiK00Y=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -296,6 +324,7 @@ in
|
|||
name = "wayland";
|
||||
url = "https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.tar.gz";
|
||||
hash = "sha256-6kGR1o5DdnflHzqs3ieCmBAUTpMdOXoyfcYDXiw5xQ0=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -304,6 +333,7 @@ in
|
|||
name = "wayland_protocols";
|
||||
url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz";
|
||||
hash = "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -312,6 +342,7 @@ in
|
|||
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;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -320,6 +351,7 @@ in
|
|||
name = "wuffs";
|
||||
url = "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz";
|
||||
hash = "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -327,7 +359,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "z2d";
|
||||
url = "https://deps.files.ghostty.org/z2d-0.10.0-j5P_Hu-6FgBsZNgwphIqh17jDnj8_yPtD8yzjO6PpHRQ.tar.gz";
|
||||
hash = "sha256-afIdou/V7gk3/lXE0J5Ir8T7L5GgHvFnyMJ1rgRnl/c=";
|
||||
hash = "sha256-qD+XexnAjSanRAwr5ZIaPY1aQhNW5DFVJ4PYLwhIr2E=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -335,7 +368,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "zf";
|
||||
url = "https://deps.files.ghostty.org/zf-3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz";
|
||||
hash = "sha256-OwFdkorwTp4mJyvBXrTbtNmp1GnrbSkKDdrmc7d8RWg=";
|
||||
hash = "sha256-BfAZILill3I/nBf1oWwol77N34Jcpm4hudC+XSeMgZY=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -343,7 +377,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "zig_js";
|
||||
url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz";
|
||||
hash = "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M=";
|
||||
hash = "sha256-r6GdXwrv+jTu0AkTlyN/FuO+N4X+l20gsbS59wrE7V4=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -351,7 +386,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "zig_objc";
|
||||
url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz";
|
||||
hash = "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw=";
|
||||
hash = "sha256-jWFQ5BrV880qqa9KypltWuRLqNSh21rDxt6Jxp0EoMM=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -359,7 +395,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "zig_wayland";
|
||||
url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz";
|
||||
hash = "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4=";
|
||||
hash = "sha256-1wRkixysjdFMyrATxlXdukAc34MwfNj0B6ydYVn+UKw=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -367,7 +404,8 @@ in
|
|||
path = fetchZigArtifact {
|
||||
name = "zigimg";
|
||||
url = "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz";
|
||||
hash = "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM=";
|
||||
hash = "sha256-vkcTloGX+vRw7e6GYJLO9eocYaEOYjXYE0dT7jscZ4A=";
|
||||
unpack = true;
|
||||
};
|
||||
}
|
||||
{
|
||||
|
|
@ -376,6 +414,7 @@ in
|
|||
name = "zlib";
|
||||
url = "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz";
|
||||
hash = "sha256-F+iIY/NgBnKrSRgvIXKBtvxNPHYr3jYZNeQ2qVIU0Fw=";
|
||||
unpack = false;
|
||||
};
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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-20260216-151611-fc73ce3.tgz
|
||||
https://deps.files.ghostty.org/ghostty-themes-release-20260511-160054-2671288.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,7 +20,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
# 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()
|
||||
|
|
@ -57,11 +57,46 @@ add_executable(myapp main.c)
|
|||
target_link_libraries(myapp PRIVATE ghostty-vt::ghostty-vt)
|
||||
```
|
||||
|
||||
## Files
|
||||
## Cross-compilation
|
||||
|
||||
- `ghostty-vt-config.cmake.in` — template for the CMake package config
|
||||
file installed alongside the library, enabling `find_package()` support.
|
||||
For cross-compiling to a different Zig target triple, use
|
||||
`ghostty_vt_add_target()` after `FetchContent_MakeAvailable`:
|
||||
|
||||
## Example
|
||||
```cmake
|
||||
FetchContent_MakeAvailable(ghostty)
|
||||
ghostty_vt_add_target(NAME linux-amd64 ZIG_TARGET x86_64-linux-gnu)
|
||||
|
||||
See `example/c-vt-cmake/` for a complete working example.
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -8,10 +8,17 @@ set(_ghostty_vt_libdir "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_LIBDIR@")
|
|||
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_libdir}/@GHOSTTY_VT_REALNAME@"
|
||||
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
|
||||
|
|
@ -22,7 +29,11 @@ if(NOT TARGET ghostty-vt::ghostty-vt)
|
|||
set_property(TARGET ghostty-vt::ghostty-vt APPEND PROPERTY
|
||||
INTERFACE_LINK_OPTIONS "LINKER:-rpath,${_ghostty_vt_libdir}"
|
||||
)
|
||||
elseif(NOT WIN32)
|
||||
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@"
|
||||
)
|
||||
|
|
@ -42,6 +53,11 @@ if(NOT TARGET ghostty-vt::ghostty-vt-static)
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ dist/
|
|||
node_modules/
|
||||
example.wasm*
|
||||
build/
|
||||
.build/
|
||||
|
|
|
|||
|
|
@ -14,6 +14,35 @@ void query_build_info() {
|
|||
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]
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
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)
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# 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
|
||||
```
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ int main() {
|
|||
fwrite(buf, 1, len, stdout);
|
||||
printf("\n");
|
||||
|
||||
free(buf);
|
||||
ghostty_free(NULL, buf, len);
|
||||
ghostty_formatter_free(formatter);
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ int main() {
|
|||
fwrite(buf, 1, len, stdout);
|
||||
printf("\n");
|
||||
|
||||
free(buf);
|
||||
ghostty_free(NULL, buf, len);
|
||||
ghostty_formatter_free(formatter);
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# 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
|
||||
```
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe_mod.addCSourceFiles(.{
|
||||
.root = b.path("src"),
|
||||
.files = &.{"main.c"},
|
||||
});
|
||||
|
||||
// You'll want to use a lazy dependency here so that ghostty is only
|
||||
// downloaded if you actually need it.
|
||||
if (b.lazyDependency("ghostty", .{
|
||||
// Setting simd to false will force a pure static build that
|
||||
// doesn't even require libc, but it has a significant performance
|
||||
// penalty. If your embedding app requires libc anyway, you should
|
||||
// always keep simd enabled.
|
||||
// .simd = false,
|
||||
})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
// Exe
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#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]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# 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
|
||||
```
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe_mod.addCSourceFiles(.{
|
||||
.root = b.path("src"),
|
||||
.files = &.{"main.c"},
|
||||
});
|
||||
|
||||
// You'll want to use a lazy dependency here so that ghostty is only
|
||||
// downloaded if you actually need it.
|
||||
if (b.lazyDependency("ghostty", .{
|
||||
// Setting simd to false will force a pure static build that
|
||||
// doesn't even require libc, but it has a significant performance
|
||||
// penalty. If your embedding app requires libc anyway, you should
|
||||
// always keep simd enabled.
|
||||
// .simd = false,
|
||||
})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
// Exe
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_effects",
|
||||
.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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#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]
|
||||
|
|
@ -56,7 +56,7 @@ int main() {
|
|||
printf("\n");
|
||||
|
||||
// Clean up
|
||||
free(buf);
|
||||
ghostty_free(NULL, buf, len);
|
||||
ghostty_formatter_free(formatter);
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# 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
|
||||
```
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe_mod.addCSourceFiles(.{
|
||||
.root = b.path("src"),
|
||||
.files = &.{"main.c"},
|
||||
});
|
||||
|
||||
// You'll want to use a lazy dependency here so that ghostty is only
|
||||
// downloaded if you actually need it.
|
||||
if (b.lazyDependency("ghostty", .{
|
||||
// Setting simd to false will force a pure static build that
|
||||
// doesn't even require libc, but it has a significant performance
|
||||
// penalty. If your embedding app requires libc anyway, you should
|
||||
// always keep simd enabled.
|
||||
// .simd = false,
|
||||
})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
// Exe
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_grid_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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#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]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# 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
|
||||
```
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe_mod.addCSourceFiles(.{
|
||||
.root = b.path("src"),
|
||||
.files = &.{"main.c"},
|
||||
});
|
||||
|
||||
// You'll want to use a lazy dependency here so that ghostty is only
|
||||
// downloaded if you actually need it.
|
||||
if (b.lazyDependency("ghostty", .{
|
||||
// Setting simd to false will force a pure static build that
|
||||
// doesn't even require libc, but it has a significant performance
|
||||
// penalty. If your embedding app requires libc anyway, you should
|
||||
// always keep simd enabled.
|
||||
// .simd = false,
|
||||
})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
// Exe
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
#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]
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# Example: `ghostty-vt` Paste Safety Check
|
||||
# Example: `ghostty-vt` Paste Utilities
|
||||
|
||||
This contains a simple example of how to use the `ghostty-vt` paste
|
||||
utilities to check if paste data is safe.
|
||||
utilities to check if paste data is safe and encode it for terminal input.
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <ghostty/vt.h>
|
||||
|
||||
//! [paste-safety]
|
||||
void basic_example() {
|
||||
void safety_example() {
|
||||
const char* safe_data = "hello world";
|
||||
const char* unsafe_data = "rm -rf /\n";
|
||||
|
||||
|
|
@ -17,8 +17,26 @@ void basic_example() {
|
|||
}
|
||||
//! [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() {
|
||||
basic_example();
|
||||
safety_example();
|
||||
|
||||
// Test unsafe paste data with bracketed paste end sequence
|
||||
const char *unsafe_escape = "evil\x1b[201~code";
|
||||
|
|
@ -32,5 +50,7 @@ int main() {
|
|||
printf("Empty data is safe\n");
|
||||
}
|
||||
|
||||
encode_example();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
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 state, and manage dirty
|
||||
tracking.
|
||||
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
|
||||
|
|
|
|||
|
|
@ -46,6 +46,32 @@ int main(void) {
|
|||
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]
|
||||
|
|
@ -154,6 +180,18 @@ int main(void) {
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# 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
|
||||
```
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe_mod.addCSourceFiles(.{
|
||||
.root = b.path("src"),
|
||||
.files = &.{"main.c"},
|
||||
});
|
||||
|
||||
// You'll want to use a lazy dependency here so that ghostty is only
|
||||
// downloaded if you actually need it.
|
||||
if (b.lazyDependency("ghostty", .{
|
||||
// Setting simd to false will force a pure static build that
|
||||
// doesn't even require libc, but it has a significant performance
|
||||
// penalty. If your embedding app requires libc anyway, you should
|
||||
// always keep simd enabled.
|
||||
// .simd = false,
|
||||
})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
// Exe
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_selection_gesture",
|
||||
.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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.name = .c_vt_selection_gesture,
|
||||
.version = "0.0.0",
|
||||
.fingerprint = 0x5a4e72d27b582404,
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ghostty/vt.h>
|
||||
|
||||
//! [selection-gesture-main]
|
||||
static void vt_write(GhosttyTerminal terminal, const char *s) {
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)s, strlen(s));
|
||||
}
|
||||
|
||||
static GhosttyGridRef ref_at(GhosttyTerminal terminal, uint16_t x, uint16_t y) {
|
||||
GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef);
|
||||
GhosttyPoint point = {
|
||||
.tag = GHOSTTY_POINT_TAG_ACTIVE,
|
||||
.value = { .coordinate = { .x = x, .y = y } },
|
||||
};
|
||||
|
||||
GhosttyResult result = ghostty_terminal_grid_ref(terminal, point, &ref);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static void print_selection(
|
||||
GhosttyTerminal terminal,
|
||||
const char *label,
|
||||
const GhosttySelection *selection) {
|
||||
GhosttyTerminalSelectionFormatOptions opts =
|
||||
GHOSTTY_INIT_SIZED(GhosttyTerminalSelectionFormatOptions);
|
||||
opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
|
||||
opts.trim = true;
|
||||
opts.selection = selection;
|
||||
|
||||
uint8_t *buf = NULL;
|
||||
size_t len = 0;
|
||||
GhosttyResult result = ghostty_terminal_selection_format_alloc(
|
||||
terminal, NULL, opts, &buf, &len);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
printf("%s: ", label);
|
||||
fwrite(buf, 1, len, stdout);
|
||||
printf("\n");
|
||||
|
||||
ghostty_free(NULL, buf, len);
|
||||
}
|
||||
|
||||
static GhosttySelectionGestureEvent new_event(
|
||||
GhosttySelectionGestureEventType type) {
|
||||
GhosttySelectionGestureEvent event = NULL;
|
||||
GhosttyResult result = ghostty_selection_gesture_event_new(NULL, &event, type);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
return event;
|
||||
}
|
||||
|
||||
int main() {
|
||||
GhosttyTerminal terminal;
|
||||
GhosttyTerminalOptions opts = {
|
||||
.cols = 20,
|
||||
.rows = 4,
|
||||
.max_scrollback = 100,
|
||||
};
|
||||
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
vt_write(terminal, "hello world\r\nsecond line");
|
||||
|
||||
GhosttySelectionGesture gesture = NULL;
|
||||
result = ghostty_selection_gesture_new(NULL, &gesture);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
GhosttySelectionGestureEvent press =
|
||||
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_PRESS);
|
||||
GhosttySelectionGestureEvent drag =
|
||||
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DRAG);
|
||||
GhosttySelectionGestureEvent release =
|
||||
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_RELEASE);
|
||||
GhosttySelectionGestureEvent deep_press =
|
||||
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DEEP_PRESS);
|
||||
|
||||
GhosttySelectionGestureGeometry geometry = {
|
||||
.columns = 20,
|
||||
.cell_width = 10,
|
||||
.padding_left = 0,
|
||||
.screen_height = 40,
|
||||
};
|
||||
|
||||
// Press in the first cell. A normal single press records the click anchor but
|
||||
// doesn't produce a selection yet, so we discard the optional output.
|
||||
GhosttyGridRef press_ref = ref_at(terminal, 0, 0);
|
||||
result = ghostty_selection_gesture_event_set(
|
||||
press, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &press_ref);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
GhosttySurfacePosition press_pos = { .x = 2, .y = 8 };
|
||||
result = ghostty_selection_gesture_event_set(
|
||||
press, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_POSITION, &press_pos);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
result = ghostty_selection_gesture_event(
|
||||
gesture, terminal, press, NULL);
|
||||
assert(result == GHOSTTY_NO_VALUE);
|
||||
|
||||
// Drag across "hello". The drag event returns a selection snapshot that the
|
||||
// embedder can apply to its UI, copy, or format immediately.
|
||||
GhosttyGridRef drag_ref = ref_at(terminal, 4, 0);
|
||||
result = ghostty_selection_gesture_event_set(
|
||||
drag, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &drag_ref);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
GhosttySurfacePosition drag_pos = { .x = 46, .y = 8 };
|
||||
result = ghostty_selection_gesture_event_set(
|
||||
drag, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_POSITION, &drag_pos);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
result = ghostty_selection_gesture_event_set(
|
||||
drag, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY, &geometry);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
GhosttySelection selection = GHOSTTY_INIT_SIZED(GhosttySelection);
|
||||
result = ghostty_selection_gesture_event(
|
||||
gesture, terminal, drag, &selection);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
print_selection(terminal, "drag", &selection);
|
||||
|
||||
// Release updates gesture state but never produces a selection.
|
||||
result = ghostty_selection_gesture_event_set(
|
||||
release, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &drag_ref);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
result = ghostty_selection_gesture_event(
|
||||
gesture, terminal, release, NULL);
|
||||
assert(result == GHOSTTY_NO_VALUE);
|
||||
|
||||
bool dragged = false;
|
||||
result = ghostty_selection_gesture_get(
|
||||
gesture, terminal, GHOSTTY_SELECTION_GESTURE_DATA_DRAGGED, &dragged);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
printf("dragged: %s\n", dragged ? "true" : "false");
|
||||
|
||||
// Deep press uses the active click anchor to select the surrounding word.
|
||||
ghostty_selection_gesture_reset(gesture, terminal);
|
||||
GhosttyGridRef world_ref = ref_at(terminal, 6, 0);
|
||||
result = ghostty_selection_gesture_event_set(
|
||||
press, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &world_ref);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
result = ghostty_selection_gesture_event(
|
||||
gesture, terminal, press, NULL);
|
||||
assert(result == GHOSTTY_NO_VALUE);
|
||||
|
||||
result = ghostty_selection_gesture_event(
|
||||
gesture, terminal, deep_press, &selection);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
print_selection(terminal, "deep press", &selection);
|
||||
|
||||
ghostty_selection_gesture_event_free(deep_press);
|
||||
ghostty_selection_gesture_event_free(release);
|
||||
ghostty_selection_gesture_event_free(drag);
|
||||
ghostty_selection_gesture_event_free(press);
|
||||
ghostty_selection_gesture_free(gesture, terminal);
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
}
|
||||
//! [selection-gesture-main]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Example: `ghostty-vt` Selection
|
||||
|
||||
This contains a simple example of how to use the `ghostty-vt` terminal,
|
||||
grid reference, selection, and formatter APIs to derive selections such as a
|
||||
word, semantic command line, command output, and all visible content.
|
||||
|
||||
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
|
||||
```
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe_mod.addCSourceFiles(.{
|
||||
.root = b.path("src"),
|
||||
.files = &.{"main.c"},
|
||||
});
|
||||
|
||||
// You'll want to use a lazy dependency here so that ghostty is only
|
||||
// downloaded if you actually need it.
|
||||
if (b.lazyDependency("ghostty", .{
|
||||
// Setting simd to false will force a pure static build that
|
||||
// doesn't even require libc, but it has a significant performance
|
||||
// penalty. If your embedding app requires libc anyway, you should
|
||||
// always keep simd enabled.
|
||||
// .simd = false,
|
||||
})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
// Exe
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_selection",
|
||||
.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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.name = .c_vt_selection,
|
||||
.version = "0.0.0",
|
||||
.fingerprint = 0xb2c2f1a828086fef,
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ghostty/vt.h>
|
||||
|
||||
//! [selection-main]
|
||||
static void vt_write(GhosttyTerminal terminal, const char *s) {
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)s, strlen(s));
|
||||
}
|
||||
|
||||
static GhosttyGridRef ref_at(GhosttyTerminal terminal, uint16_t x, uint16_t y) {
|
||||
GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef);
|
||||
GhosttyPoint point = {
|
||||
.tag = GHOSTTY_POINT_TAG_ACTIVE,
|
||||
.value = { .coordinate = { .x = x, .y = y } },
|
||||
};
|
||||
|
||||
GhosttyResult result = ghostty_terminal_grid_ref(terminal, point, &ref);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static void print_selection(
|
||||
GhosttyTerminal terminal,
|
||||
const char *label,
|
||||
const GhosttySelection *selection) {
|
||||
GhosttyFormatterTerminalOptions opts = GHOSTTY_INIT_SIZED(GhosttyFormatterTerminalOptions);
|
||||
opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
|
||||
opts.trim = true;
|
||||
opts.selection = selection;
|
||||
|
||||
GhosttyFormatter formatter;
|
||||
GhosttyResult result = ghostty_formatter_terminal_new(
|
||||
NULL, &formatter, terminal, 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("%s: ", label);
|
||||
fwrite(buf, 1, len, stdout);
|
||||
printf("\n");
|
||||
|
||||
ghostty_free(NULL, buf, len);
|
||||
ghostty_formatter_free(formatter);
|
||||
}
|
||||
|
||||
int main() {
|
||||
GhosttyTerminal terminal;
|
||||
GhosttyTerminalOptions opts = {
|
||||
.cols = 80,
|
||||
.rows = 8,
|
||||
.max_scrollback = 0,
|
||||
};
|
||||
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
// A realistic shell transcript with OSC 133 semantic prompt markers.
|
||||
// Ghostty uses these markers to distinguish prompt/input from command
|
||||
// output for semantic line and output selections.
|
||||
vt_write(terminal,
|
||||
"\033]133;A\007$ " // Prompt starts: "$ "
|
||||
"\033]133;B\007git status" // Input starts: "git status"
|
||||
"\033]133;C\007\r\n" // Output starts after Enter
|
||||
"On branch main\r\n"
|
||||
"nothing to commit, working tree clean");
|
||||
|
||||
GhosttySelection selection = GHOSTTY_INIT_SIZED(GhosttySelection);
|
||||
|
||||
// Double-click style word selection under the cursor.
|
||||
GhosttyTerminalSelectWordOptions word = GHOSTTY_INIT_SIZED(GhosttyTerminalSelectWordOptions);
|
||||
word.ref = ref_at(terminal, 6, 0); // the "status" in "git status"
|
||||
result = ghostty_terminal_select_word(terminal, &word, &selection);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
print_selection(terminal, "word", &selection);
|
||||
|
||||
//! [selection-word-between]
|
||||
// Double-click-and-drag style selection. Suppose the user double-clicks
|
||||
// "git" and drags to "status". The pointer may pass over whitespace, so
|
||||
// select the nearest word between the original click and current drag point
|
||||
// in both directions, then combine the outer word bounds.
|
||||
GhosttyGridRef click_ref = ref_at(terminal, 2, 0); // the "git" in "git status"
|
||||
GhosttyGridRef drag_ref = ref_at(terminal, 6, 0); // the "status" in "git status"
|
||||
|
||||
GhosttyTerminalSelectWordBetweenOptions start_word_opts =
|
||||
GHOSTTY_INIT_SIZED(GhosttyTerminalSelectWordBetweenOptions);
|
||||
start_word_opts.start = click_ref;
|
||||
start_word_opts.end = drag_ref;
|
||||
|
||||
GhosttySelection start_word = GHOSTTY_INIT_SIZED(GhosttySelection);
|
||||
result = ghostty_terminal_select_word_between(
|
||||
terminal, &start_word_opts, &start_word);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
GhosttyTerminalSelectWordBetweenOptions end_word_opts =
|
||||
GHOSTTY_INIT_SIZED(GhosttyTerminalSelectWordBetweenOptions);
|
||||
end_word_opts.start = drag_ref;
|
||||
end_word_opts.end = click_ref;
|
||||
|
||||
GhosttySelection end_word = GHOSTTY_INIT_SIZED(GhosttySelection);
|
||||
result = ghostty_terminal_select_word_between(
|
||||
terminal, &end_word_opts, &end_word);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
GhosttySelection drag_selection = GHOSTTY_INIT_SIZED(GhosttySelection);
|
||||
drag_selection.start = start_word.start;
|
||||
drag_selection.end = end_word.end;
|
||||
print_selection(terminal, "double-click drag", &drag_selection);
|
||||
//! [selection-word-between]
|
||||
|
||||
// Triple-click style line selection. With semantic prompt boundaries enabled,
|
||||
// this selects only the input area rather than the leading "$ " prompt.
|
||||
GhosttyTerminalSelectLineOptions line = GHOSTTY_INIT_SIZED(GhosttyTerminalSelectLineOptions);
|
||||
line.ref = ref_at(terminal, 2, 0); // the "git status" input area
|
||||
line.semantic_prompt_boundary = true;
|
||||
result = ghostty_terminal_select_line(terminal, &line, &selection);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
print_selection(terminal, "line", &selection);
|
||||
|
||||
// Select exactly the command output for the command under the cursor.
|
||||
result = ghostty_terminal_select_output(
|
||||
terminal, ref_at(terminal, 0, 1), &selection);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
print_selection(terminal, "output", &selection);
|
||||
|
||||
// Select all visible content.
|
||||
result = ghostty_terminal_select_all(terminal, &selection);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
print_selection(terminal, "all", &selection);
|
||||
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
}
|
||||
//! [selection-main]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Example: VT Stream Processing in C
|
||||
|
||||
This contains a simple example of how to use `ghostty_terminal_vt_write`
|
||||
to parse and process VT sequences in C. This is the C equivalent of
|
||||
the `zig-vt-stream` example, ideal for read-only terminal applications
|
||||
such as replay tooling, CI log viewers, and PaaS builder output.
|
||||
|
||||
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
|
||||
```
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe_mod.addCSourceFiles(.{
|
||||
.root = b.path("src"),
|
||||
.files = &.{"main.c"},
|
||||
});
|
||||
|
||||
// You'll want to use a lazy dependency here so that ghostty is only
|
||||
// downloaded if you actually need it.
|
||||
if (b.lazyDependency("ghostty", .{
|
||||
// Setting simd to false will force a pure static build that
|
||||
// doesn't even require libc, but it has a significant performance
|
||||
// penalty. If your embedding app requires libc anyway, you should
|
||||
// always keep simd enabled.
|
||||
// .simd = false,
|
||||
})) |dep| {
|
||||
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||
}
|
||||
|
||||
// Exe
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "c_vt_stream",
|
||||
.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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.name = .c_vt_stream,
|
||||
.version = "0.0.0",
|
||||
.fingerprint = 0xd5bb3fc45e3f4dfc,
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ghostty/vt.h>
|
||||
|
||||
int main(void) {
|
||||
//! [vt-stream-init]
|
||||
// Create a terminal
|
||||
GhosttyTerminal terminal;
|
||||
GhosttyTerminalOptions opts = {
|
||||
.cols = 80,
|
||||
.rows = 24,
|
||||
.max_scrollback = 0,
|
||||
};
|
||||
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
//! [vt-stream-init]
|
||||
|
||||
//! [vt-stream-write]
|
||||
// Feed VT data into the terminal
|
||||
const char *text = "Hello, World!\r\n";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
|
||||
// ANSI color codes: ESC[1;32m = bold green, ESC[0m = reset
|
||||
text = "\x1b[1;32mGreen Text\x1b[0m\r\n";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
|
||||
// Cursor positioning: ESC[1;1H = move to row 1, column 1
|
||||
text = "\x1b[1;1HTop-left corner\r\n";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
|
||||
// Cursor movement: ESC[5B = move down 5 lines
|
||||
text = "\x1b[5B";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
text = "Moved down!\r\n";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
|
||||
// Erase line: ESC[2K = clear entire line
|
||||
text = "\x1b[2K";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
text = "New content\r\n";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
|
||||
// Multiple lines
|
||||
text = "Line A\r\nLine B\r\nLine C\r\n";
|
||||
ghostty_terminal_vt_write(terminal, (const uint8_t *)text, strlen(text));
|
||||
//! [vt-stream-write]
|
||||
|
||||
//! [vt-stream-read]
|
||||
// Get the final terminal state as a plain string using the formatter
|
||||
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);
|
||||
|
||||
fwrite(buf, 1, len, stdout);
|
||||
printf("\n");
|
||||
|
||||
ghostty_free(NULL, buf, len);
|
||||
ghostty_formatter_free(formatter);
|
||||
//! [vt-stream-read]
|
||||
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Example: VT Stream Processing in C++
|
||||
|
||||
This contains a simple example of how to use `ghostty_terminal_vt_write`
|
||||
to parse and process VT sequences in C++. This is a simplified C++ port
|
||||
of the `c-vt-stream` example that verifies libghostty compiles in C++
|
||||
mode.
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> **`libghostty` is a C library.** This example is only here so our CI
|
||||
> verifies that the library can be built in used from C++ files.
|
||||
|
||||
## Usage
|
||||
|
||||
Run the program:
|
||||
|
||||
```shell-session
|
||||
zig build run
|
||||
```
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
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.cpp"},
|
||||
});
|
||||
exe_mod.link_libcpp = true;
|
||||
|
||||
// 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 = "cpp_vt_stream",
|
||||
.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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.{
|
||||
.name = .cpp_vt_stream,
|
||||
.version = "0.0.0",
|
||||
.fingerprint = 0x112f5d044ef8c2ac,
|
||||
.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",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ghostty/vt.h>
|
||||
|
||||
int main() {
|
||||
// Create a terminal
|
||||
GhosttyTerminal terminal;
|
||||
GhosttyTerminalOptions opts = {
|
||||
.cols = 80,
|
||||
.rows = 24,
|
||||
.max_scrollback = 0,
|
||||
};
|
||||
GhosttyResult result = ghostty_terminal_new(nullptr, &terminal, opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
// Feed VT data into the terminal
|
||||
const char *text = "Hello from C++!\r\n";
|
||||
ghostty_terminal_vt_write(terminal, reinterpret_cast<const uint8_t *>(text), std::strlen(text));
|
||||
|
||||
text = "\x1b[1;32mGreen Text\x1b[0m\r\n";
|
||||
ghostty_terminal_vt_write(terminal, reinterpret_cast<const uint8_t *>(text), std::strlen(text));
|
||||
|
||||
text = "\x1b[1;1HTop-left corner\r\n";
|
||||
ghostty_terminal_vt_write(terminal, reinterpret_cast<const uint8_t *>(text), std::strlen(text));
|
||||
|
||||
// Get the final terminal state as a plain string
|
||||
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(nullptr, &formatter, terminal, fmt_opts);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
uint8_t *buf = nullptr;
|
||||
size_t len = 0;
|
||||
result = ghostty_formatter_format_alloc(formatter, nullptr, &buf, &len);
|
||||
assert(result == GHOSTTY_SUCCESS);
|
||||
|
||||
std::fwrite(buf, 1, len, stdout);
|
||||
std::printf("\n");
|
||||
|
||||
ghostty_free(nullptr, buf, len);
|
||||
ghostty_formatter_free(formatter);
|
||||
ghostty_terminal_free(terminal);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// swift-tools-version: 5.9
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "swift-vt-xcframework",
|
||||
platforms: [.macOS(.v13)],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
name: "swift-vt-xcframework",
|
||||
dependencies: ["GhosttyVt"],
|
||||
path: "Sources"
|
||||
),
|
||||
.binaryTarget(
|
||||
name: "GhosttyVt",
|
||||
path: "../../zig-out/lib/ghostty-vt.xcframework"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# swift-vt-xcframework
|
||||
|
||||
Demonstrates consuming libghostty-vt from a Swift Package using the
|
||||
pre-built XCFramework. Creates a terminal, writes VT sequences into it,
|
||||
and formats the screen contents as plain text.
|
||||
|
||||
This example requires the XCFramework to be built first.
|
||||
|
||||
## Building
|
||||
|
||||
First, build the XCFramework from the repository root:
|
||||
|
||||
```shell-session
|
||||
zig build -Demit-lib-vt
|
||||
```
|
||||
|
||||
Then build and run the Swift package:
|
||||
|
||||
```shell-session
|
||||
cd example/swift-vt-xcframework
|
||||
swift build
|
||||
swift run
|
||||
```
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import Foundation
|
||||
import GhosttyVt
|
||||
|
||||
// Create a terminal with a small grid
|
||||
var terminal: GhosttyTerminal?
|
||||
var opts = GhosttyTerminalOptions(
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
max_scrollback: 0
|
||||
)
|
||||
let result = ghostty_terminal_new(nil, &terminal, opts)
|
||||
guard result == GHOSTTY_SUCCESS, let terminal else {
|
||||
fatalError("Failed to create terminal")
|
||||
}
|
||||
|
||||
// Write some VT-encoded content
|
||||
let text = "Hello from \u{1b}[1mSwift\u{1b}[0m via xcframework!\r\n"
|
||||
text.withCString { ptr in
|
||||
ghostty_terminal_vt_write(terminal, ptr, strlen(ptr))
|
||||
}
|
||||
|
||||
// Format the terminal contents as plain text
|
||||
var fmtOpts = GhosttyFormatterTerminalOptions()
|
||||
fmtOpts.size = MemoryLayout<GhosttyFormatterTerminalOptions>.size
|
||||
fmtOpts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN
|
||||
fmtOpts.trim = true
|
||||
|
||||
var formatter: GhosttyFormatter?
|
||||
let fmtResult = ghostty_formatter_terminal_new(nil, &formatter, terminal, fmtOpts)
|
||||
guard fmtResult == GHOSTTY_SUCCESS, let formatter else {
|
||||
fatalError("Failed to create formatter")
|
||||
}
|
||||
|
||||
var buf: UnsafeMutablePointer<UInt8>?
|
||||
var len: Int = 0
|
||||
let allocResult = ghostty_formatter_format_alloc(formatter, nil, &buf, &len)
|
||||
guard allocResult == GHOSTTY_SUCCESS, let buf else {
|
||||
fatalError("Failed to format")
|
||||
}
|
||||
|
||||
print("Plain text (\(len) bytes):")
|
||||
let data = Data(bytes: buf, count: len)
|
||||
print(String(data: data, encoding: .utf8) ?? "<invalid UTF-8>")
|
||||
|
||||
ghostty_free(nil, buf, len)
|
||||
ghostty_formatter_free(formatter)
|
||||
ghostty_terminal_free(terminal)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# WebAssembly VT Terminal Example
|
||||
|
||||
This example demonstrates how to use the Ghostty VT library from WebAssembly
|
||||
to initialize a terminal, write VT-encoded data to it, and format the
|
||||
terminal contents as plain text.
|
||||
|
||||
## Building
|
||||
|
||||
First, build the WebAssembly module:
|
||||
|
||||
```bash
|
||||
zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall
|
||||
```
|
||||
|
||||
This will create `zig-out/bin/ghostty-vt.wasm`.
|
||||
|
||||
## Running
|
||||
|
||||
**Important:** You must serve this via HTTP, not open it as a file directly.
|
||||
Browsers block loading WASM files from `file://` URLs.
|
||||
|
||||
From the **root of the ghostty repository**, serve with a local HTTP server:
|
||||
|
||||
```bash
|
||||
# Using Python (recommended)
|
||||
python3 -m http.server 8000
|
||||
|
||||
# Or using Node.js
|
||||
npx serve .
|
||||
|
||||
# Or using PHP
|
||||
php -S localhost:8000
|
||||
```
|
||||
|
||||
Then open your browser to:
|
||||
|
||||
```
|
||||
http://localhost:8000/example/wasm-vt/
|
||||
```
|
||||
|
|
@ -0,0 +1,342 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Ghostty VT Terminal - WebAssembly Example</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
max-width: 900px;
|
||||
margin: 40px auto;
|
||||
padding: 0 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
}
|
||||
.input-section {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.input-section h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
resize: vertical;
|
||||
}
|
||||
button {
|
||||
background: #0066cc;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
button:hover {
|
||||
background: #0052a3;
|
||||
}
|
||||
button:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.output {
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
font-family: 'Courier New', monospace;
|
||||
white-space: pre-wrap;
|
||||
font-size: 14px;
|
||||
}
|
||||
.error {
|
||||
background: #fee;
|
||||
border-color: #faa;
|
||||
color: #c00;
|
||||
}
|
||||
.status {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.size-controls {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.size-controls label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.size-controls input[type="number"] {
|
||||
width: 60px;
|
||||
padding: 4px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Ghostty VT Terminal - WebAssembly Example</h1>
|
||||
<p>This example demonstrates initializing a terminal, writing VT-encoded data to it, and formatting the output using the Ghostty VT WebAssembly module.</p>
|
||||
|
||||
<div class="status" id="status">Loading WebAssembly module...</div>
|
||||
|
||||
<div class="input-section">
|
||||
<h3>Terminal Size</h3>
|
||||
<div class="size-controls">
|
||||
<label>Cols: <input type="number" id="cols" value="80" min="1" max="500" disabled></label>
|
||||
<label>Rows: <input type="number" id="rows" value="24" min="1" max="500" disabled></label>
|
||||
</div>
|
||||
<h3>VT Input</h3>
|
||||
<textarea id="vtInput" rows="6" disabled>Hello, World!\r\n\x1b[1;32mGreen Bold\x1b[0m and \x1b[4mUnderline\x1b[0m\r\nLine 3: placeholder\r\n\x1b[3;1H\x1b[2KLine 3: Overwritten!</textarea>
|
||||
<p style="font-size: 13px; color: #666; margin-top: 5px;">Use \x1b for ESC, \r\n for CR+LF. Press "Run" to process.</p>
|
||||
<button id="runBtn" disabled>Run</button>
|
||||
</div>
|
||||
|
||||
<div id="output" class="output">Waiting for input...</div>
|
||||
|
||||
<p><strong>Note:</strong> This example must be served via HTTP (not opened directly as a file). See the README for instructions.</p>
|
||||
|
||||
<script>
|
||||
let wasmInstance = null;
|
||||
let wasmMemory = null;
|
||||
let typeLayout = null;
|
||||
|
||||
async function loadWasm() {
|
||||
try {
|
||||
const response = await fetch('../../zig-out/bin/ghostty-vt.wasm');
|
||||
const wasmBytes = await response.arrayBuffer();
|
||||
|
||||
const wasmModule = await WebAssembly.instantiate(wasmBytes, {
|
||||
env: {
|
||||
log: (ptr, len) => {
|
||||
const bytes = new Uint8Array(wasmModule.instance.exports.memory.buffer, ptr, len);
|
||||
const text = new TextDecoder().decode(bytes);
|
||||
console.log('[wasm]', text);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
wasmInstance = wasmModule.instance;
|
||||
wasmMemory = wasmInstance.exports.memory;
|
||||
|
||||
// Load the type layout JSON from the library
|
||||
const jsonPtr = wasmInstance.exports.ghostty_type_json();
|
||||
const jsonStr = new TextDecoder().decode(
|
||||
new Uint8Array(wasmMemory.buffer, jsonPtr, wasmMemory.buffer.byteLength - jsonPtr)
|
||||
).split('\0')[0];
|
||||
typeLayout = JSON.parse(jsonStr);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('Failed to load WASM:', e);
|
||||
if (window.location.protocol === 'file:') {
|
||||
throw new Error('Cannot load WASM from file:// protocol. Please serve via HTTP (see README)');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Look up a field's offset and DataView setter from the type layout JSON.
|
||||
function fieldInfo(structName, fieldName) {
|
||||
const field = typeLayout[structName].fields[fieldName];
|
||||
return field;
|
||||
}
|
||||
|
||||
// Set a field in a DataView using the type layout JSON metadata.
|
||||
function setField(view, structName, fieldName, value) {
|
||||
const field = fieldInfo(structName, fieldName);
|
||||
switch (field.type) {
|
||||
case 'u8': case 'bool': view.setUint8(field.offset, value); break;
|
||||
case 'u16': view.setUint16(field.offset, value, true); break;
|
||||
case 'u32': case 'enum': view.setUint32(field.offset, value, true); break;
|
||||
case 'u64': view.setBigUint64(field.offset, BigInt(value), true); break;
|
||||
default: throw new Error(`Unsupported field type: ${field.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getBuffer() {
|
||||
return wasmMemory.buffer;
|
||||
}
|
||||
|
||||
// Parse escape sequences in the input string (e.g. \x1b, \r, \n)
|
||||
function parseEscapes(str) {
|
||||
return str
|
||||
.replace(/\\x([0-9a-fA-F]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
||||
.replace(/\\r/g, '\r')
|
||||
.replace(/\\n/g, '\n')
|
||||
.replace(/\\t/g, '\t')
|
||||
.replace(/\\\\/g, '\\');
|
||||
}
|
||||
|
||||
// GHOSTTY_FORMATTER_FORMAT_PLAIN = 0
|
||||
const GHOSTTY_FORMATTER_FORMAT_PLAIN = 0;
|
||||
// GHOSTTY_SUCCESS = 0
|
||||
const GHOSTTY_SUCCESS = 0;
|
||||
|
||||
function run() {
|
||||
const outputDiv = document.getElementById('output');
|
||||
|
||||
try {
|
||||
const cols = parseInt(document.getElementById('cols').value, 10);
|
||||
const rows = parseInt(document.getElementById('rows').value, 10);
|
||||
const vtText = parseEscapes(document.getElementById('vtInput').value);
|
||||
|
||||
const TERM_OPTS_SIZE = typeLayout['GhosttyTerminalOptions'].size;
|
||||
const optsPtr = wasmInstance.exports.ghostty_wasm_alloc_u8_array(TERM_OPTS_SIZE);
|
||||
new Uint8Array(getBuffer(), optsPtr, TERM_OPTS_SIZE).fill(0);
|
||||
const optsView = new DataView(getBuffer(), optsPtr, TERM_OPTS_SIZE);
|
||||
setField(optsView, 'GhosttyTerminalOptions', 'cols', cols);
|
||||
setField(optsView, 'GhosttyTerminalOptions', 'rows', rows);
|
||||
setField(optsView, 'GhosttyTerminalOptions', 'max_scrollback', 0);
|
||||
|
||||
// Allocate pointer to receive the terminal handle
|
||||
const termPtrPtr = wasmInstance.exports.ghostty_wasm_alloc_opaque();
|
||||
|
||||
// Create terminal
|
||||
const newResult = wasmInstance.exports.ghostty_terminal_new(0, termPtrPtr, optsPtr);
|
||||
wasmInstance.exports.ghostty_wasm_free_u8_array(optsPtr, TERM_OPTS_SIZE);
|
||||
|
||||
if (newResult !== GHOSTTY_SUCCESS) {
|
||||
throw new Error(`ghostty_terminal_new failed with result ${newResult}`);
|
||||
}
|
||||
|
||||
const termPtr = new DataView(getBuffer()).getUint32(termPtrPtr, true);
|
||||
wasmInstance.exports.ghostty_wasm_free_opaque(termPtrPtr);
|
||||
|
||||
// Write VT data to the terminal
|
||||
const vtBytes = new TextEncoder().encode(vtText);
|
||||
const dataPtr = wasmInstance.exports.ghostty_wasm_alloc_u8_array(vtBytes.length);
|
||||
new Uint8Array(getBuffer()).set(vtBytes, dataPtr);
|
||||
wasmInstance.exports.ghostty_terminal_vt_write(termPtr, dataPtr, vtBytes.length);
|
||||
wasmInstance.exports.ghostty_wasm_free_u8_array(dataPtr, vtBytes.length);
|
||||
|
||||
// Create a plain-text formatter
|
||||
const FMT_OPTS_SIZE = typeLayout['GhosttyFormatterTerminalOptions'].size;
|
||||
const fmtOptsPtr = wasmInstance.exports.ghostty_wasm_alloc_u8_array(FMT_OPTS_SIZE);
|
||||
new Uint8Array(getBuffer(), fmtOptsPtr, FMT_OPTS_SIZE).fill(0);
|
||||
const fmtOptsView = new DataView(getBuffer(), fmtOptsPtr, FMT_OPTS_SIZE);
|
||||
setField(fmtOptsView, 'GhosttyFormatterTerminalOptions', 'size', FMT_OPTS_SIZE);
|
||||
setField(fmtOptsView, 'GhosttyFormatterTerminalOptions', 'emit', GHOSTTY_FORMATTER_FORMAT_PLAIN);
|
||||
setField(fmtOptsView, 'GhosttyFormatterTerminalOptions', 'unwrap', 0);
|
||||
setField(fmtOptsView, 'GhosttyFormatterTerminalOptions', 'trim', 1);
|
||||
|
||||
// Set the nested sized-struct `size` fields for extra and extra.screen
|
||||
const extraOffset = fieldInfo('GhosttyFormatterTerminalOptions', 'extra').offset;
|
||||
const extraSize = typeLayout['GhosttyFormatterTerminalExtra'].size;
|
||||
const extraSizeField = fieldInfo('GhosttyFormatterTerminalExtra', 'size');
|
||||
fmtOptsView.setUint32(extraOffset + extraSizeField.offset, extraSize, true);
|
||||
|
||||
const screenOffset = fieldInfo('GhosttyFormatterTerminalExtra', 'screen').offset;
|
||||
const screenSize = typeLayout['GhosttyFormatterScreenExtra'].size;
|
||||
const screenSizeField = fieldInfo('GhosttyFormatterScreenExtra', 'size');
|
||||
fmtOptsView.setUint32(extraOffset + screenOffset + screenSizeField.offset, screenSize, true);
|
||||
|
||||
const fmtPtrPtr = wasmInstance.exports.ghostty_wasm_alloc_opaque();
|
||||
const fmtResult = wasmInstance.exports.ghostty_formatter_terminal_new(
|
||||
0, fmtPtrPtr, termPtr, fmtOptsPtr
|
||||
);
|
||||
wasmInstance.exports.ghostty_wasm_free_u8_array(fmtOptsPtr, FMT_OPTS_SIZE);
|
||||
|
||||
if (fmtResult !== GHOSTTY_SUCCESS) {
|
||||
wasmInstance.exports.ghostty_terminal_free(termPtr);
|
||||
throw new Error(`ghostty_formatter_terminal_new failed with result ${fmtResult}`);
|
||||
}
|
||||
|
||||
const fmtPtr = new DataView(getBuffer()).getUint32(fmtPtrPtr, true);
|
||||
wasmInstance.exports.ghostty_wasm_free_opaque(fmtPtrPtr);
|
||||
|
||||
// Format with alloc
|
||||
const outPtrPtr = wasmInstance.exports.ghostty_wasm_alloc_opaque();
|
||||
const outLenPtr = wasmInstance.exports.ghostty_wasm_alloc_usize();
|
||||
const formatResult = wasmInstance.exports.ghostty_formatter_format_alloc(
|
||||
fmtPtr, 0, outPtrPtr, outLenPtr
|
||||
);
|
||||
|
||||
if (formatResult !== GHOSTTY_SUCCESS) {
|
||||
wasmInstance.exports.ghostty_formatter_free(fmtPtr);
|
||||
wasmInstance.exports.ghostty_terminal_free(termPtr);
|
||||
throw new Error(`ghostty_formatter_format_alloc failed with result ${formatResult}`);
|
||||
}
|
||||
|
||||
const outPtr = new DataView(getBuffer()).getUint32(outPtrPtr, true);
|
||||
const outLen = new DataView(getBuffer()).getUint32(outLenPtr, true);
|
||||
|
||||
const outBytes = new Uint8Array(getBuffer(), outPtr, outLen);
|
||||
const outText = new TextDecoder().decode(outBytes);
|
||||
|
||||
let output = `Terminal: ${cols}x${rows}\n`;
|
||||
output += `Input: ${vtBytes.length} bytes\n`;
|
||||
output += `Output: ${outLen} bytes\n\n`;
|
||||
output += outText;
|
||||
|
||||
outputDiv.className = 'output';
|
||||
outputDiv.textContent = output;
|
||||
|
||||
// Clean up
|
||||
wasmInstance.exports.ghostty_free(0, outPtr, outLen);
|
||||
wasmInstance.exports.ghostty_wasm_free_opaque(outPtrPtr);
|
||||
wasmInstance.exports.ghostty_wasm_free_usize(outLenPtr);
|
||||
wasmInstance.exports.ghostty_formatter_free(fmtPtr);
|
||||
wasmInstance.exports.ghostty_terminal_free(termPtr);
|
||||
|
||||
} catch (e) {
|
||||
console.error('Error:', e);
|
||||
outputDiv.className = 'output error';
|
||||
outputDiv.textContent = `Error: ${e.message}\n\nStack trace:\n${e.stack}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function init() {
|
||||
const statusDiv = document.getElementById('status');
|
||||
const vtInput = document.getElementById('vtInput');
|
||||
const colsInput = document.getElementById('cols');
|
||||
const rowsInput = document.getElementById('rows');
|
||||
const runBtn = document.getElementById('runBtn');
|
||||
|
||||
try {
|
||||
statusDiv.textContent = 'Loading WebAssembly module...';
|
||||
|
||||
const loaded = await loadWasm();
|
||||
if (!loaded) {
|
||||
throw new Error('Failed to load WebAssembly module');
|
||||
}
|
||||
|
||||
statusDiv.textContent = '';
|
||||
vtInput.disabled = false;
|
||||
colsInput.disabled = false;
|
||||
rowsInput.disabled = false;
|
||||
runBtn.disabled = false;
|
||||
|
||||
runBtn.addEventListener('click', run);
|
||||
|
||||
// Run the default example on load
|
||||
run();
|
||||
return;
|
||||
} catch (e) {
|
||||
statusDiv.textContent = `Error: ${e.message}`;
|
||||
statusDiv.style.color = '#c00';
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
38
flake.lock
38
flake.lock
|
|
@ -88,11 +88,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1773145353,
|
||||
"narHash": "sha256-dE8zx8WA54TRmFFQBvA48x/sXGDTP7YaDmY6nNKMAYw=",
|
||||
"lastModified": 1776789209,
|
||||
"narHash": "sha256-G6B7Q4TXn7MZ1mB+f9rymjsYF5PLWoSvmbxijb/99bw=",
|
||||
"owner": "mitchellh",
|
||||
"repo": "zig-overlay",
|
||||
"rev": "8666155d83bf792956a7c40915508e6d4b2b8716",
|
||||
"rev": "14fe971844e841297ddd2ce9783d6892b467af39",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -101,24 +101,46 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zon2nix": {
|
||||
"zig_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zon2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1768231828,
|
||||
"narHash": "sha256-wL/8Iij4T2OLkhHcc4NieOjf7YeJffaUYbCiCqKv/+0=",
|
||||
"lastModified": 1777234348,
|
||||
"narHash": "sha256-fKw44a4qbUuI5eTG8k0gPbqMV5TOrjYF35PBzsYgd2U=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "2c781c0609ecda600ab98f98cca417bbd981bd53",
|
||||
"revCount": 1677,
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/jcollie/zig-overlay.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/jcollie/zig-overlay.git"
|
||||
}
|
||||
},
|
||||
"zon2nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"zig": "zig_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777314365,
|
||||
"narHash": "sha256-eLxQaD0wc96Neqkln8wHS0rNq/chPODifFkhwrwilEU=",
|
||||
"owner": "jcollie",
|
||||
"repo": "zon2nix",
|
||||
"rev": "c28e93f3ba133d4c1b1d65224e2eebede61fd071",
|
||||
"rev": "a5a1d412ad1ab6305511997bbc92b3a9dd6cb784",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "jcollie",
|
||||
"ref": "main",
|
||||
"repo": "zon2nix",
|
||||
"rev": "c28e93f3ba133d4c1b1d65224e2eebede61fd071",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
47
flake.nix
47
flake.nix
|
|
@ -32,7 +32,7 @@
|
|||
};
|
||||
|
||||
zon2nix = {
|
||||
url = "github:jcollie/zon2nix?rev=c28e93f3ba133d4c1b1d65224e2eebede61fd071";
|
||||
url = "github:jcollie/zon2nix?ref=main";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
|
@ -75,7 +75,10 @@
|
|||
in {
|
||||
devShells = forAllPlatforms (pkgs: {
|
||||
default = pkgs.callPackage ./nix/devShell.nix {
|
||||
zig = zig.packages.${pkgs.stdenv.hostPlatform.system}."0.15.2";
|
||||
zig =
|
||||
if pkgs.stdenv.hostPlatform.isDarwin
|
||||
then zig.packages.${pkgs.stdenv.hostPlatform.system}.brew."0.15.2"
|
||||
else zig.packages.${pkgs.stdenv.hostPlatform.system}."0.15.2";
|
||||
wraptest = pkgs.callPackage ./nix/pkgs/wraptest.nix {};
|
||||
zon2nix = zon2nix;
|
||||
|
||||
|
|
@ -91,18 +94,36 @@
|
|||
});
|
||||
|
||||
packages =
|
||||
forAllPlatforms (pkgs: {
|
||||
# Deps are needed for environmental setup on macOS
|
||||
deps = pkgs.callPackage ./build.zig.zon.nix {};
|
||||
})
|
||||
// forBuildablePlatforms (pkgs: rec {
|
||||
ghostty-debug = pkgs.callPackage ./nix/package.nix (mkPkgArgs "Debug");
|
||||
ghostty-releasesafe = pkgs.callPackage ./nix/package.nix (mkPkgArgs "ReleaseSafe");
|
||||
ghostty-releasefast = pkgs.callPackage ./nix/package.nix (mkPkgArgs "ReleaseFast");
|
||||
builtins.foldl'
|
||||
lib.recursiveUpdate
|
||||
{}
|
||||
[
|
||||
(
|
||||
forAllPlatforms (pkgs: rec {
|
||||
# Deps are needed for environmental setup on macOS
|
||||
deps = pkgs.callPackage ./build.zig.zon.nix {};
|
||||
|
||||
ghostty = ghostty-releasefast;
|
||||
default = ghostty;
|
||||
});
|
||||
libghostty-vt-debug = pkgs.callPackage ./nix/libghostty-vt.nix (mkPkgArgs "Debug");
|
||||
libghostty-vt-releasesafe = pkgs.callPackage ./nix/libghostty-vt.nix (mkPkgArgs "ReleaseSafe");
|
||||
libghostty-vt-releasefast = pkgs.callPackage ./nix/libghostty-vt.nix (mkPkgArgs "ReleaseFast");
|
||||
libghostty-vt-debug-no-simd = pkgs.callPackage ./nix/libghostty-vt.nix ((mkPkgArgs "Debug") // {simd = false;});
|
||||
libghostty-vt-releasesafe-no-simd = pkgs.callPackage ./nix/libghostty-vt.nix ((mkPkgArgs "ReleaseSafe") // {simd = false;});
|
||||
libghostty-vt-releasefast-no-simd = pkgs.callPackage ./nix/libghostty-vt.nix ((mkPkgArgs "ReleaseFast") // {simd = false;});
|
||||
|
||||
libghostty-vt = libghostty-vt-releasefast;
|
||||
})
|
||||
)
|
||||
(
|
||||
forBuildablePlatforms (pkgs: rec {
|
||||
ghostty-debug = pkgs.callPackage ./nix/package.nix (mkPkgArgs "Debug");
|
||||
ghostty-releasesafe = pkgs.callPackage ./nix/package.nix (mkPkgArgs "ReleaseSafe");
|
||||
ghostty-releasefast = pkgs.callPackage ./nix/package.nix (mkPkgArgs "ReleaseFast");
|
||||
|
||||
ghostty = ghostty-releasefast;
|
||||
default = ghostty;
|
||||
})
|
||||
)
|
||||
];
|
||||
|
||||
formatter = forAllPlatforms (pkgs: pkgs.alejandra);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
app-id: com.mitchellh.ghostty-debug
|
||||
runtime: org.gnome.Platform
|
||||
runtime-version: "49"
|
||||
runtime-version: "50"
|
||||
sdk: org.gnome.Sdk
|
||||
default-branch: tip
|
||||
command: ghostty
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
app-id: com.mitchellh.ghostty
|
||||
runtime: org.gnome.Platform
|
||||
runtime-version: "49"
|
||||
runtime-version: "50"
|
||||
sdk: org.gnome.Sdk
|
||||
default-branch: tip
|
||||
command: ghostty
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@
|
|||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/ghostty-themes-release-20260216-151611-fc73ce3.tgz",
|
||||
"dest": "vendor/p/N-V-__8AABVbAwBwDRyZONfx553tvMW8_A2OKUoLzPUSRiLF",
|
||||
"sha256": "14200bb86a0c814ab69609d500b280b396b6d2eb835edf0676de4a789c0aa8fd"
|
||||
"url": "https://deps.files.ghostty.org/ghostty-themes-release-20260511-160054-2671288.tgz",
|
||||
"dest": "vendor/p/N-V-__8AAPy1AwDnEoq1ww42uq58nusIeQgR16W4-5SQZFIM",
|
||||
"sha256": "47634950ac73d8b1d1882062fcc0273775f333263855695b5f4b9609b59e7e34"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
|
|
@ -131,12 +131,6 @@
|
|||
"dest": "vendor/p/N-V-__8AANb6pwD7O1WG6L5nvD_rNMvnSc9Cpg1ijSlTYywv",
|
||||
"sha256": "b52b6fcfc45e7fa69b1f06a1362c155473444e2cc09995556b156c53ba6657e3"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH",
|
||||
"sha256": "ffc668a310e77607d393f3c18b32715f223da1eac4c4d6e0579a11df8e6b59cf"
|
||||
},
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/jacobsandlund/uucode",
|
||||
|
|
|
|||
|
|
@ -15,13 +15,41 @@ extern "C" {
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Macros
|
||||
|
||||
#define GHOSTTY_SUCCESS 0
|
||||
|
||||
// Symbol visibility for shared library builds. On Windows, functions
|
||||
// are exported from the DLL when building and imported when consuming.
|
||||
// On other platforms with GCC/Clang, functions are marked with default
|
||||
// visibility so they remain accessible when the library is built with
|
||||
// -fvisibility=hidden. For static library builds, define GHOSTTY_STATIC
|
||||
// before including this header to make this a no-op.
|
||||
#ifndef GHOSTTY_API
|
||||
#if defined(GHOSTTY_STATIC)
|
||||
#define GHOSTTY_API
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
#ifdef GHOSTTY_BUILD_SHARED
|
||||
#define GHOSTTY_API __declspec(dllexport)
|
||||
#else
|
||||
#define GHOSTTY_API __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define GHOSTTY_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define GHOSTTY_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Types
|
||||
|
||||
|
|
@ -336,7 +364,6 @@ typedef enum {
|
|||
} ghostty_input_trigger_tag_e;
|
||||
|
||||
typedef union {
|
||||
ghostty_input_key_e translated;
|
||||
ghostty_input_key_e physical;
|
||||
uint32_t unicode;
|
||||
// catch_all has no payload
|
||||
|
|
@ -1027,149 +1054,152 @@ typedef union {
|
|||
// apprt.ipc.Action.Key
|
||||
typedef enum {
|
||||
GHOSTTY_IPC_ACTION_NEW_WINDOW,
|
||||
GHOSTTY_IPC_ACTION_TOGGLE_QUICK_TERMINAL,
|
||||
} ghostty_ipc_action_tag_e;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Published API
|
||||
|
||||
int ghostty_init(uintptr_t, char**);
|
||||
void ghostty_cli_try_action(void);
|
||||
ghostty_info_s ghostty_info(void);
|
||||
const char* ghostty_translate(const char*);
|
||||
void ghostty_string_free(ghostty_string_s);
|
||||
GHOSTTY_API int ghostty_init(uintptr_t, char**);
|
||||
GHOSTTY_API void ghostty_cli_try_action(void);
|
||||
GHOSTTY_API ghostty_info_s ghostty_info(void);
|
||||
GHOSTTY_API const char* ghostty_translate(const char*);
|
||||
GHOSTTY_API void ghostty_string_free(ghostty_string_s);
|
||||
|
||||
ghostty_config_t ghostty_config_new();
|
||||
void ghostty_config_free(ghostty_config_t);
|
||||
ghostty_config_t ghostty_config_clone(ghostty_config_t);
|
||||
void ghostty_config_load_cli_args(ghostty_config_t);
|
||||
void ghostty_config_load_file(ghostty_config_t, const char*);
|
||||
void ghostty_config_load_default_files(ghostty_config_t);
|
||||
void ghostty_config_load_recursive_files(ghostty_config_t);
|
||||
void ghostty_config_finalize(ghostty_config_t);
|
||||
bool ghostty_config_get(ghostty_config_t, void*, const char*, uintptr_t);
|
||||
ghostty_input_trigger_s ghostty_config_trigger(ghostty_config_t,
|
||||
const char*,
|
||||
uintptr_t);
|
||||
uint32_t ghostty_config_diagnostics_count(ghostty_config_t);
|
||||
ghostty_diagnostic_s ghostty_config_get_diagnostic(ghostty_config_t, uint32_t);
|
||||
ghostty_string_s ghostty_config_open_path(void);
|
||||
GHOSTTY_API ghostty_config_t ghostty_config_new();
|
||||
GHOSTTY_API void ghostty_config_free(ghostty_config_t);
|
||||
GHOSTTY_API ghostty_config_t ghostty_config_clone(ghostty_config_t);
|
||||
GHOSTTY_API void ghostty_config_load_cli_args(ghostty_config_t);
|
||||
GHOSTTY_API void ghostty_config_load_file(ghostty_config_t, const char*);
|
||||
GHOSTTY_API void ghostty_config_load_default_files(ghostty_config_t);
|
||||
GHOSTTY_API void ghostty_config_load_recursive_files(ghostty_config_t);
|
||||
GHOSTTY_API void ghostty_config_finalize(ghostty_config_t);
|
||||
GHOSTTY_API bool ghostty_config_get(ghostty_config_t, void*, const char*, uintptr_t);
|
||||
GHOSTTY_API ghostty_input_trigger_s ghostty_config_trigger(ghostty_config_t,
|
||||
const char*,
|
||||
uintptr_t);
|
||||
GHOSTTY_API bool ghostty_config_key_is_binding(ghostty_config_t, ghostty_input_key_s);
|
||||
GHOSTTY_API uint32_t ghostty_config_diagnostics_count(ghostty_config_t);
|
||||
GHOSTTY_API ghostty_diagnostic_s ghostty_config_get_diagnostic(ghostty_config_t, uint32_t);
|
||||
GHOSTTY_API ghostty_string_s ghostty_config_open_path(void);
|
||||
|
||||
ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s*,
|
||||
ghostty_config_t);
|
||||
void ghostty_app_free(ghostty_app_t);
|
||||
void ghostty_app_tick(ghostty_app_t);
|
||||
void* ghostty_app_userdata(ghostty_app_t);
|
||||
void ghostty_app_set_focus(ghostty_app_t, bool);
|
||||
bool ghostty_app_key(ghostty_app_t, ghostty_input_key_s);
|
||||
bool ghostty_app_key_is_binding(ghostty_app_t, ghostty_input_key_s);
|
||||
void ghostty_app_keyboard_changed(ghostty_app_t);
|
||||
void ghostty_app_open_config(ghostty_app_t);
|
||||
void ghostty_app_update_config(ghostty_app_t, ghostty_config_t);
|
||||
bool ghostty_app_needs_confirm_quit(ghostty_app_t);
|
||||
bool ghostty_app_has_global_keybinds(ghostty_app_t);
|
||||
void ghostty_app_set_color_scheme(ghostty_app_t, ghostty_color_scheme_e);
|
||||
GHOSTTY_API ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s*,
|
||||
ghostty_config_t);
|
||||
GHOSTTY_API void ghostty_app_free(ghostty_app_t);
|
||||
GHOSTTY_API void ghostty_app_tick(ghostty_app_t);
|
||||
GHOSTTY_API void* ghostty_app_userdata(ghostty_app_t);
|
||||
GHOSTTY_API void ghostty_app_set_focus(ghostty_app_t, bool);
|
||||
GHOSTTY_API bool ghostty_app_key(ghostty_app_t, ghostty_input_key_s);
|
||||
GHOSTTY_API void ghostty_app_keyboard_changed(ghostty_app_t);
|
||||
GHOSTTY_API void ghostty_app_open_config(ghostty_app_t);
|
||||
GHOSTTY_API void ghostty_app_update_config(ghostty_app_t, ghostty_config_t);
|
||||
GHOSTTY_API bool ghostty_app_needs_confirm_quit(ghostty_app_t);
|
||||
GHOSTTY_API bool ghostty_app_has_global_keybinds(ghostty_app_t);
|
||||
GHOSTTY_API void ghostty_app_set_color_scheme(ghostty_app_t, ghostty_color_scheme_e);
|
||||
|
||||
ghostty_surface_config_s ghostty_surface_config_new();
|
||||
GHOSTTY_API ghostty_surface_config_s ghostty_surface_config_new();
|
||||
|
||||
ghostty_surface_t ghostty_surface_new(ghostty_app_t,
|
||||
const ghostty_surface_config_s*);
|
||||
void ghostty_surface_free(ghostty_surface_t);
|
||||
void* ghostty_surface_userdata(ghostty_surface_t);
|
||||
ghostty_app_t ghostty_surface_app(ghostty_surface_t);
|
||||
ghostty_surface_config_s ghostty_surface_inherited_config(ghostty_surface_t, ghostty_surface_context_e);
|
||||
void ghostty_surface_update_config(ghostty_surface_t, ghostty_config_t);
|
||||
bool ghostty_surface_needs_confirm_quit(ghostty_surface_t);
|
||||
bool ghostty_surface_process_exited(ghostty_surface_t);
|
||||
void ghostty_surface_refresh(ghostty_surface_t);
|
||||
void ghostty_surface_draw(ghostty_surface_t);
|
||||
void ghostty_surface_set_content_scale(ghostty_surface_t, double, double);
|
||||
void ghostty_surface_set_focus(ghostty_surface_t, bool);
|
||||
void ghostty_surface_set_occlusion(ghostty_surface_t, bool);
|
||||
void ghostty_surface_set_size(ghostty_surface_t, uint32_t, uint32_t);
|
||||
ghostty_surface_size_s ghostty_surface_size(ghostty_surface_t);
|
||||
void ghostty_surface_set_color_scheme(ghostty_surface_t,
|
||||
ghostty_color_scheme_e);
|
||||
ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t,
|
||||
ghostty_input_mods_e);
|
||||
bool ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
|
||||
bool ghostty_surface_key_is_binding(ghostty_surface_t,
|
||||
ghostty_input_key_s,
|
||||
ghostty_binding_flags_e*);
|
||||
void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
|
||||
void ghostty_surface_preedit(ghostty_surface_t, const char*, uintptr_t);
|
||||
bool ghostty_surface_mouse_captured(ghostty_surface_t);
|
||||
bool ghostty_surface_mouse_button(ghostty_surface_t,
|
||||
ghostty_input_mouse_state_e,
|
||||
ghostty_input_mouse_button_e,
|
||||
ghostty_input_mods_e);
|
||||
void ghostty_surface_mouse_pos(ghostty_surface_t,
|
||||
double,
|
||||
double,
|
||||
ghostty_input_mods_e);
|
||||
void ghostty_surface_mouse_scroll(ghostty_surface_t,
|
||||
double,
|
||||
double,
|
||||
ghostty_input_scroll_mods_t);
|
||||
void ghostty_surface_mouse_pressure(ghostty_surface_t, uint32_t, double);
|
||||
void ghostty_surface_ime_point(ghostty_surface_t, double*, double*, double*, double*);
|
||||
void ghostty_surface_request_close(ghostty_surface_t);
|
||||
void ghostty_surface_split(ghostty_surface_t, ghostty_action_split_direction_e);
|
||||
void ghostty_surface_split_focus(ghostty_surface_t,
|
||||
ghostty_action_goto_split_e);
|
||||
void ghostty_surface_split_resize(ghostty_surface_t,
|
||||
ghostty_action_resize_split_direction_e,
|
||||
uint16_t);
|
||||
void ghostty_surface_split_equalize(ghostty_surface_t);
|
||||
bool ghostty_surface_binding_action(ghostty_surface_t, const char*, uintptr_t);
|
||||
void ghostty_surface_complete_clipboard_request(ghostty_surface_t,
|
||||
const char*,
|
||||
void*,
|
||||
bool);
|
||||
bool ghostty_surface_has_selection(ghostty_surface_t);
|
||||
bool ghostty_surface_read_selection(ghostty_surface_t, ghostty_text_s*);
|
||||
bool ghostty_surface_read_text(ghostty_surface_t,
|
||||
ghostty_selection_s,
|
||||
ghostty_text_s*);
|
||||
void ghostty_surface_free_text(ghostty_surface_t, ghostty_text_s*);
|
||||
GHOSTTY_API ghostty_surface_t ghostty_surface_new(ghostty_app_t,
|
||||
const ghostty_surface_config_s*);
|
||||
GHOSTTY_API void ghostty_surface_free(ghostty_surface_t);
|
||||
GHOSTTY_API void* ghostty_surface_userdata(ghostty_surface_t);
|
||||
GHOSTTY_API ghostty_app_t ghostty_surface_app(ghostty_surface_t);
|
||||
GHOSTTY_API ghostty_surface_config_s ghostty_surface_inherited_config(ghostty_surface_t, ghostty_surface_context_e);
|
||||
GHOSTTY_API void ghostty_surface_update_config(ghostty_surface_t, ghostty_config_t);
|
||||
GHOSTTY_API bool ghostty_surface_needs_confirm_quit(ghostty_surface_t);
|
||||
GHOSTTY_API bool ghostty_surface_process_exited(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_surface_refresh(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_surface_draw(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_surface_set_content_scale(ghostty_surface_t, double, double);
|
||||
GHOSTTY_API void ghostty_surface_set_focus(ghostty_surface_t, bool);
|
||||
GHOSTTY_API void ghostty_surface_set_occlusion(ghostty_surface_t, bool);
|
||||
GHOSTTY_API void ghostty_surface_set_size(ghostty_surface_t, uint32_t, uint32_t);
|
||||
GHOSTTY_API ghostty_surface_size_s ghostty_surface_size(ghostty_surface_t);
|
||||
GHOSTTY_API uint64_t ghostty_surface_foreground_pid(ghostty_surface_t);
|
||||
GHOSTTY_API ghostty_string_s ghostty_surface_tty_name(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_surface_set_color_scheme(ghostty_surface_t,
|
||||
ghostty_color_scheme_e);
|
||||
GHOSTTY_API ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t,
|
||||
ghostty_input_mods_e);
|
||||
GHOSTTY_API bool ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
|
||||
GHOSTTY_API bool ghostty_surface_key_is_binding(ghostty_surface_t,
|
||||
ghostty_input_key_s,
|
||||
ghostty_binding_flags_e*);
|
||||
GHOSTTY_API void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
|
||||
GHOSTTY_API void ghostty_surface_preedit(ghostty_surface_t, const char*, uintptr_t);
|
||||
GHOSTTY_API bool ghostty_surface_mouse_captured(ghostty_surface_t);
|
||||
GHOSTTY_API bool ghostty_surface_mouse_button(ghostty_surface_t,
|
||||
ghostty_input_mouse_state_e,
|
||||
ghostty_input_mouse_button_e,
|
||||
ghostty_input_mods_e);
|
||||
GHOSTTY_API void ghostty_surface_mouse_pos(ghostty_surface_t,
|
||||
double,
|
||||
double,
|
||||
ghostty_input_mods_e);
|
||||
GHOSTTY_API void ghostty_surface_mouse_scroll(ghostty_surface_t,
|
||||
double,
|
||||
double,
|
||||
ghostty_input_scroll_mods_t);
|
||||
GHOSTTY_API void ghostty_surface_mouse_pressure(ghostty_surface_t, uint32_t, double);
|
||||
GHOSTTY_API void ghostty_surface_ime_point(ghostty_surface_t, double*, double*, double*, double*);
|
||||
GHOSTTY_API void ghostty_surface_request_close(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_surface_split(ghostty_surface_t, ghostty_action_split_direction_e);
|
||||
GHOSTTY_API void ghostty_surface_split_focus(ghostty_surface_t,
|
||||
ghostty_action_goto_split_e);
|
||||
GHOSTTY_API void ghostty_surface_split_resize(ghostty_surface_t,
|
||||
ghostty_action_resize_split_direction_e,
|
||||
uint16_t);
|
||||
GHOSTTY_API void ghostty_surface_split_equalize(ghostty_surface_t);
|
||||
GHOSTTY_API bool ghostty_surface_binding_action(ghostty_surface_t, const char*, uintptr_t);
|
||||
GHOSTTY_API void ghostty_surface_complete_clipboard_request(ghostty_surface_t,
|
||||
const char*,
|
||||
void*,
|
||||
bool);
|
||||
GHOSTTY_API bool ghostty_surface_has_selection(ghostty_surface_t);
|
||||
GHOSTTY_API bool ghostty_surface_read_selection(ghostty_surface_t, ghostty_text_s*);
|
||||
GHOSTTY_API bool ghostty_surface_read_text(ghostty_surface_t,
|
||||
ghostty_selection_s,
|
||||
ghostty_text_s*);
|
||||
GHOSTTY_API void ghostty_surface_free_text(ghostty_surface_t, ghostty_text_s*);
|
||||
|
||||
#ifdef __APPLE__
|
||||
void ghostty_surface_set_display_id(ghostty_surface_t, uint32_t);
|
||||
void* ghostty_surface_quicklook_font(ghostty_surface_t);
|
||||
bool ghostty_surface_quicklook_word(ghostty_surface_t, ghostty_text_s*);
|
||||
GHOSTTY_API void ghostty_surface_set_display_id(ghostty_surface_t, uint32_t);
|
||||
GHOSTTY_API void* ghostty_surface_quicklook_font(ghostty_surface_t);
|
||||
GHOSTTY_API bool ghostty_surface_quicklook_word(ghostty_surface_t, ghostty_text_s*);
|
||||
#endif
|
||||
|
||||
ghostty_inspector_t ghostty_surface_inspector(ghostty_surface_t);
|
||||
void ghostty_inspector_free(ghostty_surface_t);
|
||||
void ghostty_inspector_set_focus(ghostty_inspector_t, bool);
|
||||
void ghostty_inspector_set_content_scale(ghostty_inspector_t, double, double);
|
||||
void ghostty_inspector_set_size(ghostty_inspector_t, uint32_t, uint32_t);
|
||||
void ghostty_inspector_mouse_button(ghostty_inspector_t,
|
||||
ghostty_input_mouse_state_e,
|
||||
ghostty_input_mouse_button_e,
|
||||
ghostty_input_mods_e);
|
||||
void ghostty_inspector_mouse_pos(ghostty_inspector_t, double, double);
|
||||
void ghostty_inspector_mouse_scroll(ghostty_inspector_t,
|
||||
double,
|
||||
double,
|
||||
ghostty_input_scroll_mods_t);
|
||||
void ghostty_inspector_key(ghostty_inspector_t,
|
||||
ghostty_input_action_e,
|
||||
ghostty_input_key_e,
|
||||
ghostty_input_mods_e);
|
||||
void ghostty_inspector_text(ghostty_inspector_t, const char*);
|
||||
GHOSTTY_API ghostty_inspector_t ghostty_surface_inspector(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_inspector_free(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_inspector_set_focus(ghostty_inspector_t, bool);
|
||||
GHOSTTY_API void ghostty_inspector_set_content_scale(ghostty_inspector_t, double, double);
|
||||
GHOSTTY_API void ghostty_inspector_set_size(ghostty_inspector_t, uint32_t, uint32_t);
|
||||
GHOSTTY_API void ghostty_inspector_mouse_button(ghostty_inspector_t,
|
||||
ghostty_input_mouse_state_e,
|
||||
ghostty_input_mouse_button_e,
|
||||
ghostty_input_mods_e);
|
||||
GHOSTTY_API void ghostty_inspector_mouse_pos(ghostty_inspector_t, double, double);
|
||||
GHOSTTY_API void ghostty_inspector_mouse_scroll(ghostty_inspector_t,
|
||||
double,
|
||||
double,
|
||||
ghostty_input_scroll_mods_t);
|
||||
GHOSTTY_API void ghostty_inspector_key(ghostty_inspector_t,
|
||||
ghostty_input_action_e,
|
||||
ghostty_input_key_e,
|
||||
ghostty_input_mods_e);
|
||||
GHOSTTY_API void ghostty_inspector_text(ghostty_inspector_t, const char*);
|
||||
|
||||
#ifdef __APPLE__
|
||||
bool ghostty_inspector_metal_init(ghostty_inspector_t, void*);
|
||||
void ghostty_inspector_metal_render(ghostty_inspector_t, void*, void*);
|
||||
bool ghostty_inspector_metal_shutdown(ghostty_inspector_t);
|
||||
GHOSTTY_API bool ghostty_inspector_metal_init(ghostty_inspector_t, void*);
|
||||
GHOSTTY_API void ghostty_inspector_metal_render(ghostty_inspector_t, void*, void*);
|
||||
GHOSTTY_API bool ghostty_inspector_metal_shutdown(ghostty_inspector_t);
|
||||
#endif
|
||||
|
||||
// APIs I'd like to get rid of eventually but are still needed for now.
|
||||
// Don't use these unless you know what you're doing.
|
||||
void ghostty_set_window_background_blur(ghostty_app_t, void*);
|
||||
GHOSTTY_API void ghostty_set_window_background_blur(ghostty_app_t, void*);
|
||||
|
||||
// Benchmark API, if available.
|
||||
bool ghostty_benchmark_cli(const char*, const char*);
|
||||
GHOSTTY_API bool ghostty_benchmark_cli(const char*, const char*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
* - @ref c-vt-sgr/src/main.c - SGR parser example
|
||||
* - @ref c-vt-formatter/src/main.c - Terminal formatter example
|
||||
* - @ref c-vt-grid-traverse/src/main.c - Grid traversal example using grid refs
|
||||
* - @ref c-vt-grid-ref-tracked/src/main.c - Tracked grid ref example
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -98,6 +99,21 @@
|
|||
* grid refs to inspect cell codepoints, row wrap state, and cell styles.
|
||||
*/
|
||||
|
||||
/** @example c-vt-grid-ref-tracked/src/main.c
|
||||
* This example demonstrates how to track a grid ref as the terminal scrolls,
|
||||
* detect when it loses its value, and move it to a new point.
|
||||
*/
|
||||
|
||||
/** @example c-vt-selection-gesture/src/main.c
|
||||
* This example demonstrates how to use synthetic selection gesture events to
|
||||
* derive drag and deep-press selection snapshots.
|
||||
*/
|
||||
|
||||
/** @example c-vt-kitty-graphics/src/main.c
|
||||
* This example demonstrates how to use the system interface to install a
|
||||
* PNG decoder callback and send a Kitty Graphics Protocol image.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_H
|
||||
#define GHOSTTY_VT_H
|
||||
|
||||
|
|
@ -109,19 +125,25 @@ extern "C" {
|
|||
#include <ghostty/vt/allocator.h>
|
||||
#include <ghostty/vt/build_info.h>
|
||||
#include <ghostty/vt/color.h>
|
||||
#include <ghostty/vt/device.h>
|
||||
#include <ghostty/vt/focus.h>
|
||||
#include <ghostty/vt/formatter.h>
|
||||
#include <ghostty/vt/render.h>
|
||||
#include <ghostty/vt/terminal.h>
|
||||
#include <ghostty/vt/grid_ref.h>
|
||||
#include <ghostty/vt/grid_ref_tracked.h>
|
||||
#include <ghostty/vt/osc.h>
|
||||
#include <ghostty/vt/sgr.h>
|
||||
#include <ghostty/vt/style.h>
|
||||
#include <ghostty/vt/sys.h>
|
||||
#include <ghostty/vt/key.h>
|
||||
#include <ghostty/vt/kitty_graphics.h>
|
||||
#include <ghostty/vt/modes.h>
|
||||
#include <ghostty/vt/mouse.h>
|
||||
#include <ghostty/vt/paste.h>
|
||||
#include <ghostty/vt/point.h>
|
||||
#include <ghostty/vt/screen.h>
|
||||
#include <ghostty/vt/selection.h>
|
||||
#include <ghostty/vt/size_report.h>
|
||||
#include <ghostty/vt/wasm.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <ghostty/vt/types.h>
|
||||
|
||||
/** @defgroup allocator Memory Management
|
||||
*
|
||||
|
|
@ -44,6 +45,24 @@
|
|||
* 2. Create a GhosttyAllocator struct with your vtable and context
|
||||
* 3. Pass the allocator to functions that accept one
|
||||
*
|
||||
* ## Alloc/Free Helpers
|
||||
*
|
||||
* ghostty_alloc() and ghostty_free() provide a simple malloc/free-style
|
||||
* interface for allocating and freeing byte buffers through the library's
|
||||
* allocator. These are useful when:
|
||||
*
|
||||
* - You need to allocate a buffer to pass into a libghostty-vt function
|
||||
* (e.g. preparing input data for ghostty_terminal_vt_write()).
|
||||
* - You need to free a buffer returned by a libghostty-vt function
|
||||
* (e.g. the output of ghostty_formatter_format_alloc()).
|
||||
* - You are on a platform where the library's internal allocator differs
|
||||
* from the consumer's C runtime (e.g. Windows, where Zig's libc and
|
||||
* MSVC's CRT maintain separate heaps), so calling the standard C
|
||||
* free() on library-allocated memory would be undefined behavior.
|
||||
*
|
||||
* Always use the same allocator (or NULL) for both the allocation and
|
||||
* the corresponding free.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
|
@ -191,6 +210,46 @@ typedef struct GhosttyAllocator {
|
|||
const GhosttyAllocatorVtable *vtable;
|
||||
} GhosttyAllocator;
|
||||
|
||||
/**
|
||||
* Allocate a buffer of `len` bytes.
|
||||
*
|
||||
* Uses the provided allocator, or the default allocator if NULL is passed.
|
||||
* The returned buffer must be freed with ghostty_free() using the same
|
||||
* allocator.
|
||||
*
|
||||
* @param allocator Pointer to the allocator to use, or NULL for the default
|
||||
* @param len Number of bytes to allocate
|
||||
* @return Pointer to the allocated buffer, or NULL if allocation failed
|
||||
*
|
||||
* @ingroup allocator
|
||||
*/
|
||||
GHOSTTY_API uint8_t* ghostty_alloc(const GhosttyAllocator* allocator, size_t len);
|
||||
|
||||
/**
|
||||
* Free memory that was allocated by a libghostty-vt function.
|
||||
*
|
||||
* Use this to free buffers returned by functions such as
|
||||
* ghostty_formatter_format_alloc(). Pass the same allocator that was
|
||||
* used for the allocation, or NULL if the default allocator was used.
|
||||
*
|
||||
* On platforms where the library's internal allocator differs from the
|
||||
* consumer's C runtime (e.g. Windows, where Zig's libc and MSVC's CRT
|
||||
* maintain separate heaps), calling the standard C free() on memory
|
||||
* allocated by the library causes undefined behavior. This function
|
||||
* guarantees the correct allocator is used regardless of platform.
|
||||
*
|
||||
* It is safe to pass a NULL pointer; the call is a no-op in that case.
|
||||
*
|
||||
* @param allocator Pointer to the allocator that was used to allocate the
|
||||
* memory, or NULL if the default allocator was used
|
||||
* @param ptr Pointer to the memory to free (may be NULL)
|
||||
* @param len Length of the allocation in bytes (must match the original
|
||||
* allocation size)
|
||||
*
|
||||
* @ingroup allocator
|
||||
*/
|
||||
GHOSTTY_API void ghostty_free(const GhosttyAllocator* allocator, uint8_t* ptr, size_t len);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* GHOSTTY_VT_ALLOCATOR_H */
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <ghostty/vt/types.h>
|
||||
|
|
@ -34,11 +35,12 @@ extern "C" {
|
|||
/**
|
||||
* Build optimization mode.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_OPTIMIZE_DEBUG = 0,
|
||||
GHOSTTY_OPTIMIZE_RELEASE_SAFE = 1,
|
||||
GHOSTTY_OPTIMIZE_RELEASE_SMALL = 2,
|
||||
GHOSTTY_OPTIMIZE_RELEASE_FAST = 3,
|
||||
GHOSTTY_OPTIMIZE_MODE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyOptimizeMode;
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +48,7 @@ typedef enum {
|
|||
*
|
||||
* Each variant documents the expected output pointer type.
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Invalid data type. Never results in any data extraction. */
|
||||
GHOSTTY_BUILD_INFO_INVALID = 0,
|
||||
|
||||
|
|
@ -77,6 +79,51 @@ typedef enum {
|
|||
* Output type: GhosttyOptimizeMode *
|
||||
*/
|
||||
GHOSTTY_BUILD_INFO_OPTIMIZE = 4,
|
||||
|
||||
/**
|
||||
* The full version string (e.g. "1.2.3" or "1.2.3-dev+abcdef").
|
||||
*
|
||||
* Output type: GhosttyString *
|
||||
*/
|
||||
GHOSTTY_BUILD_INFO_VERSION_STRING = 5,
|
||||
|
||||
/**
|
||||
* The major version number.
|
||||
*
|
||||
* Output type: size_t *
|
||||
*/
|
||||
GHOSTTY_BUILD_INFO_VERSION_MAJOR = 6,
|
||||
|
||||
/**
|
||||
* The minor version number.
|
||||
*
|
||||
* Output type: size_t *
|
||||
*/
|
||||
GHOSTTY_BUILD_INFO_VERSION_MINOR = 7,
|
||||
|
||||
/**
|
||||
* The patch version number.
|
||||
*
|
||||
* Output type: size_t *
|
||||
*/
|
||||
GHOSTTY_BUILD_INFO_VERSION_PATCH = 8,
|
||||
|
||||
/**
|
||||
* The pre metadata string (e.g. "alpha", "beta", "dev"). Has zero length if
|
||||
* no pre metadata is present.
|
||||
*
|
||||
* Output type: GhosttyString *
|
||||
*/
|
||||
GHOSTTY_BUILD_INFO_VERSION_PRE = 9,
|
||||
|
||||
/**
|
||||
* The build metadata string (e.g. commit hash). Has zero length if
|
||||
* no build metadata is present.
|
||||
*
|
||||
* Output type: GhosttyString *
|
||||
*/
|
||||
GHOSTTY_BUILD_INFO_VERSION_BUILD = 10,
|
||||
GHOSTTY_BUILD_INFO_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyBuildInfo;
|
||||
|
||||
/**
|
||||
|
|
@ -92,7 +139,7 @@ typedef enum {
|
|||
*
|
||||
* @ingroup build_info
|
||||
*/
|
||||
GhosttyResult ghostty_build_info(GhosttyBuildInfo data, void *out);
|
||||
GHOSTTY_API GhosttyResult ghostty_build_info(GhosttyBuildInfo data, void *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#define GHOSTTY_VT_COLOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ghostty/vt/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -84,7 +85,7 @@ typedef uint8_t GhosttyColorPaletteIndex;
|
|||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
void ghostty_color_rgb_get(GhosttyColorRgb color,
|
||||
GHOSTTY_API void ghostty_color_rgb_get(GhosttyColorRgb color,
|
||||
uint8_t* r,
|
||||
uint8_t* g,
|
||||
uint8_t* b);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
* @file device.h
|
||||
*
|
||||
* Device types used by the terminal for device status and device attribute
|
||||
* queries.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_DEVICE_H
|
||||
#define GHOSTTY_VT_DEVICE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* DA1 conformance levels (Pp parameter). */
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT100 1
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT101 1
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT102 6
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT125 12
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT131 7
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT132 4
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT220 62
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT240 62
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT320 63
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT340 63
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT420 64
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT510 65
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT520 65
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT525 65
|
||||
#define GHOSTTY_DA_CONFORMANCE_LEVEL_2 62
|
||||
#define GHOSTTY_DA_CONFORMANCE_LEVEL_3 63
|
||||
#define GHOSTTY_DA_CONFORMANCE_LEVEL_4 64
|
||||
#define GHOSTTY_DA_CONFORMANCE_LEVEL_5 65
|
||||
|
||||
/* DA1 feature codes (Ps parameters). */
|
||||
#define GHOSTTY_DA_FEATURE_COLUMNS_132 1
|
||||
#define GHOSTTY_DA_FEATURE_PRINTER 2
|
||||
#define GHOSTTY_DA_FEATURE_REGIS 3
|
||||
#define GHOSTTY_DA_FEATURE_SIXEL 4
|
||||
#define GHOSTTY_DA_FEATURE_SELECTIVE_ERASE 6
|
||||
#define GHOSTTY_DA_FEATURE_USER_DEFINED_KEYS 8
|
||||
#define GHOSTTY_DA_FEATURE_NATIONAL_REPLACEMENT 9
|
||||
#define GHOSTTY_DA_FEATURE_TECHNICAL_CHARACTERS 15
|
||||
#define GHOSTTY_DA_FEATURE_LOCATOR 16
|
||||
#define GHOSTTY_DA_FEATURE_TERMINAL_STATE 17
|
||||
#define GHOSTTY_DA_FEATURE_WINDOWING 18
|
||||
#define GHOSTTY_DA_FEATURE_HORIZONTAL_SCROLLING 21
|
||||
#define GHOSTTY_DA_FEATURE_ANSI_COLOR 22
|
||||
#define GHOSTTY_DA_FEATURE_RECTANGULAR_EDITING 28
|
||||
#define GHOSTTY_DA_FEATURE_ANSI_TEXT_LOCATOR 29
|
||||
#define GHOSTTY_DA_FEATURE_CLIPBOARD 52
|
||||
|
||||
/* DA2 device type identifiers (Pp parameter). */
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT100 0
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT220 1
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT240 2
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT330 18
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT340 19
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT320 24
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT382 32
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT420 41
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT510 61
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT520 64
|
||||
#define GHOSTTY_DA_DEVICE_TYPE_VT525 65
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Color scheme reported in response to a CSI ? 996 n query.
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_COLOR_SCHEME_LIGHT = 0,
|
||||
GHOSTTY_COLOR_SCHEME_DARK = 1,
|
||||
GHOSTTY_COLOR_SCHEME_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyColorScheme;
|
||||
|
||||
/**
|
||||
* Primary device attributes (DA1) response data.
|
||||
*
|
||||
* Returned as part of GhosttyDeviceAttributes in response to a CSI c query.
|
||||
* The conformance_level is the Pp parameter and features contains the Ps
|
||||
* feature codes.
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
typedef struct {
|
||||
/** Conformance level (Pp parameter). E.g. 62 for VT220. */
|
||||
uint16_t conformance_level;
|
||||
|
||||
/** DA1 feature codes. Only the first num_features entries are valid. */
|
||||
uint16_t features[64];
|
||||
|
||||
/** Number of valid entries in the features array. */
|
||||
size_t num_features;
|
||||
} GhosttyDeviceAttributesPrimary;
|
||||
|
||||
/**
|
||||
* Secondary device attributes (DA2) response data.
|
||||
*
|
||||
* Returned as part of GhosttyDeviceAttributes in response to a CSI > c query.
|
||||
* Response format: CSI > Pp ; Pv ; Pc c
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
typedef struct {
|
||||
/** Terminal type identifier (Pp). E.g. 1 for VT220. */
|
||||
uint16_t device_type;
|
||||
|
||||
/** Firmware/patch version number (Pv). */
|
||||
uint16_t firmware_version;
|
||||
|
||||
/** ROM cartridge registration number (Pc). Always 0 for emulators. */
|
||||
uint16_t rom_cartridge;
|
||||
} GhosttyDeviceAttributesSecondary;
|
||||
|
||||
/**
|
||||
* Tertiary device attributes (DA3) response data.
|
||||
*
|
||||
* Returned as part of GhosttyDeviceAttributes in response to a CSI = c query.
|
||||
* Response format: DCS ! | D...D ST (DECRPTUI).
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
typedef struct {
|
||||
/** Unit ID encoded as 8 uppercase hex digits in the response. */
|
||||
uint32_t unit_id;
|
||||
} GhosttyDeviceAttributesTertiary;
|
||||
|
||||
/**
|
||||
* Device attributes response data for all three DA levels.
|
||||
*
|
||||
* Filled by the device_attributes callback in response to CSI c,
|
||||
* CSI > c, or CSI = c queries. The terminal uses whichever sub-struct
|
||||
* matches the request type.
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
typedef struct {
|
||||
GhosttyDeviceAttributesPrimary primary;
|
||||
GhosttyDeviceAttributesSecondary secondary;
|
||||
GhosttyDeviceAttributesTertiary tertiary;
|
||||
} GhosttyDeviceAttributes;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GHOSTTY_VT_DEVICE_H */
|
||||
|
|
@ -35,11 +35,12 @@ extern "C" {
|
|||
/**
|
||||
* Focus event types for focus reporting mode (mode 1004).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Terminal window gained focus */
|
||||
GHOSTTY_FOCUS_GAINED = 0,
|
||||
/** Terminal window lost focus */
|
||||
GHOSTTY_FOCUS_LOST = 1,
|
||||
GHOSTTY_FOCUS_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyFocusEvent;
|
||||
|
||||
/**
|
||||
|
|
@ -60,7 +61,7 @@ typedef enum {
|
|||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
|
||||
* is too small
|
||||
*/
|
||||
GhosttyResult ghostty_focus_encode(
|
||||
GHOSTTY_API GhosttyResult ghostty_focus_encode(
|
||||
GhosttyFocusEvent event,
|
||||
char* buf,
|
||||
size_t buf_len,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <ghostty/vt/allocator.h>
|
||||
#include <ghostty/vt/selection.h>
|
||||
#include <ghostty/vt/types.h>
|
||||
#include <ghostty/vt/terminal.h>
|
||||
|
||||
|
|
@ -31,22 +32,6 @@ extern "C" {
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Output format.
|
||||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
typedef enum {
|
||||
/** Plain text (no escape sequences). */
|
||||
GHOSTTY_FORMATTER_FORMAT_PLAIN,
|
||||
|
||||
/** VT sequences preserving colors, styles, URLs, etc. */
|
||||
GHOSTTY_FORMATTER_FORMAT_VT,
|
||||
|
||||
/** HTML with inline styles. */
|
||||
GHOSTTY_FORMATTER_FORMAT_HTML,
|
||||
} GhosttyFormatterFormat;
|
||||
|
||||
/**
|
||||
* Extra screen state to include in styled output.
|
||||
*
|
||||
|
|
@ -106,13 +91,6 @@ typedef struct {
|
|||
GhosttyFormatterScreenExtra screen;
|
||||
} GhosttyFormatterTerminalExtra;
|
||||
|
||||
/**
|
||||
* Opaque handle to a formatter instance.
|
||||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
typedef struct GhosttyFormatter* GhosttyFormatter;
|
||||
|
||||
/**
|
||||
* Options for creating a terminal formatter.
|
||||
*
|
||||
|
|
@ -133,6 +111,10 @@ typedef struct {
|
|||
|
||||
/** Extra terminal state to include in styled output. */
|
||||
GhosttyFormatterTerminalExtra extra;
|
||||
|
||||
/** Optional selection to restrict output to a range.
|
||||
* If NULL, the entire screen is formatted. */
|
||||
const GhosttySelection *selection;
|
||||
} GhosttyFormatterTerminalOptions;
|
||||
|
||||
/**
|
||||
|
|
@ -149,7 +131,7 @@ typedef struct {
|
|||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
GhosttyResult ghostty_formatter_terminal_new(
|
||||
GHOSTTY_API GhosttyResult ghostty_formatter_terminal_new(
|
||||
const GhosttyAllocator* allocator,
|
||||
GhosttyFormatter* formatter,
|
||||
GhosttyTerminal terminal,
|
||||
|
|
@ -176,7 +158,7 @@ GhosttyResult ghostty_formatter_terminal_new(
|
|||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
GhosttyResult ghostty_formatter_format_buf(GhosttyFormatter formatter,
|
||||
GHOSTTY_API GhosttyResult ghostty_formatter_format_buf(GhosttyFormatter formatter,
|
||||
uint8_t* buf,
|
||||
size_t buf_len,
|
||||
size_t* out_written);
|
||||
|
|
@ -186,10 +168,9 @@ GhosttyResult ghostty_formatter_format_buf(GhosttyFormatter formatter,
|
|||
*
|
||||
* Each call formats the current terminal state. The buffer is allocated
|
||||
* using the provided allocator (or the default allocator if NULL).
|
||||
* The caller is responsible for freeing the returned buffer. When using
|
||||
* the default allocator (NULL), the buffer can be freed with `free()`.
|
||||
* When using a custom allocator, the buffer must be freed using the
|
||||
* same allocator.
|
||||
* The caller is responsible for freeing the returned buffer with
|
||||
* ghostty_free(), passing the same allocator (or NULL for the default)
|
||||
* that was used for the allocation.
|
||||
*
|
||||
* @param formatter The formatter handle (must not be NULL)
|
||||
* @param allocator Pointer to allocator, or NULL to use the default allocator
|
||||
|
|
@ -200,7 +181,7 @@ GhosttyResult ghostty_formatter_format_buf(GhosttyFormatter formatter,
|
|||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
GhosttyResult ghostty_formatter_format_alloc(GhosttyFormatter formatter,
|
||||
GHOSTTY_API GhosttyResult ghostty_formatter_format_alloc(GhosttyFormatter formatter,
|
||||
const GhosttyAllocator* allocator,
|
||||
uint8_t** out_ptr,
|
||||
size_t* out_len);
|
||||
|
|
@ -215,7 +196,7 @@ GhosttyResult ghostty_formatter_format_alloc(GhosttyFormatter formatter,
|
|||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
void ghostty_formatter_free(GhosttyFormatter formatter);
|
||||
GHOSTTY_API void ghostty_formatter_free(GhosttyFormatter formatter);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
|||
|
|
@ -20,24 +20,79 @@ extern "C" {
|
|||
|
||||
/** @defgroup grid_ref Grid Reference
|
||||
*
|
||||
* A grid reference is a resolved reference to a specific cell position in the
|
||||
* terminal's internal page structure. Obtain a grid reference from
|
||||
* ghostty_terminal_grid_ref(), then extract the cell or row via
|
||||
* ghostty_grid_ref_cell() and ghostty_grid_ref_row().
|
||||
* A grid reference is a reference to a specific cell position in the
|
||||
* terminal. Obtain a grid reference from `ghostty_terminal_grid_ref`
|
||||
* for untracked or `ghostty_terminal_grid_ref_track` for tracked. Untracked
|
||||
* vs tracked is explained next.
|
||||
*
|
||||
* A grid reference is only valid until the next update to the terminal
|
||||
* instance. There is no guarantee that a grid reference will remain
|
||||
* valid after ANY operation, even if a seemingly unrelated part of
|
||||
* the grid is changed, so any information related to the grid reference
|
||||
* should be read and cached immediately after obtaining the grid reference.
|
||||
* Important: The grid reference APIs are not meant to be used as the core of a render
|
||||
* loop. They are not built to sustain the framerates needed for rendering large
|
||||
* screens. Use the render state API for that.
|
||||
*
|
||||
* This API is not meant to be used as the core of render loop. It isn't
|
||||
* built to sustain the framerates needed for rendering large screens.
|
||||
* Use the render state API for that.
|
||||
* ## Untracked vs Tracked References
|
||||
*
|
||||
* ### Untracked Reference
|
||||
*
|
||||
* ## Example
|
||||
* An untracked grid reference is a value type that snapshots a specific
|
||||
* cell. It is only valid until the next update to the terminal instance.
|
||||
* There is no guarantee that it will remain valid after any operation,
|
||||
* even if a seemingly unrelated part of the grid is changed. These are meant
|
||||
* to be read and have their values cached immediately after obtaining it.
|
||||
*
|
||||
* An untracked grid reference has a performance cost in its initial lookup,
|
||||
* but doesn't affect the ongoing performance of the terminal in any way,
|
||||
* since it is a one-time snapshot.
|
||||
*
|
||||
* ### Tracked Reference
|
||||
*
|
||||
* A tracked grid reference follows its cell across normal screen operations.
|
||||
* For example scrolling, scrollback pruning, resize/reflow, and other
|
||||
* terminal mutations update the tracked reference automatically.
|
||||
*
|
||||
* A tracked reference can still lose its original semantic location. This can
|
||||
* happen when the underlying grid is reset, pruned, or otherwise discarded in a
|
||||
* way that cannot be mapped to a meaningful new cell. In that state,
|
||||
* ghostty_tracked_grid_ref_has_value() returns false and
|
||||
* ghostty_tracked_grid_ref_snapshot() / ghostty_tracked_grid_ref_point() return
|
||||
* GHOSTTY_NO_VALUE. The handle remains valid, and callers may move it to a new
|
||||
* point with ghostty_tracked_grid_ref_set().
|
||||
*
|
||||
* To read cell data from a tracked reference, first snapshot it with
|
||||
* ghostty_tracked_grid_ref_snapshot(). The returned `GhosttyGridRef` is again
|
||||
* an untracked reference and follows the same short lifetime rules as any other
|
||||
* untracked grid reference.
|
||||
*
|
||||
* A tracked reference belongs to the terminal screen/page-list that was active
|
||||
* when it was created or last set. Converting it to a point uses that owning
|
||||
* screen/page-list, even if the terminal has since switched between primary and
|
||||
* alternate screens. Calling ghostty_tracked_grid_ref_set() resolves the new
|
||||
* point against the terminal's currently active screen/page-list and may move
|
||||
* the tracked reference between screens.
|
||||
*
|
||||
* Tracked references are owned by the caller and must be freed with
|
||||
* ghostty_tracked_grid_ref_free(). If the terminal that created a tracked
|
||||
* reference is freed first, the handle remains valid only for tracked-grid-ref
|
||||
* APIs: it reports no value and can still be freed.
|
||||
*
|
||||
* Each tracked reference adds bookkeeping to terminal mutations. Use them
|
||||
* sparingly for long-lived anchors such as selections, search state, marks,
|
||||
* or application-side bookmarks.
|
||||
*
|
||||
* ## Lifetime
|
||||
*
|
||||
* An untracked reference is a snapshot. It doesn't need to be freed.
|
||||
* The safety of accessing the value is documented explicitly above: it
|
||||
* is only safe to access any data until the next terminal mutating
|
||||
* operation (including free).
|
||||
*
|
||||
* A tracked reference is allocated and must be freed when it is no
|
||||
* longer needed. A tracked reference may outlive the terminal that created it;
|
||||
* after terminal free, it reports no value and can still be freed.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* @snippet c-vt-grid-traverse/src/main.c grid-ref-traverse
|
||||
* @snippet c-vt-grid-ref-tracked/src/main.c grid-ref-tracked
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
|
@ -66,7 +121,7 @@ typedef struct {
|
|||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GhosttyResult ghostty_grid_ref_cell(const GhosttyGridRef *ref,
|
||||
GHOSTTY_API GhosttyResult ghostty_grid_ref_cell(const GhosttyGridRef *ref,
|
||||
GhosttyCell *out_cell);
|
||||
|
||||
/**
|
||||
|
|
@ -79,7 +134,7 @@ GhosttyResult ghostty_grid_ref_cell(const GhosttyGridRef *ref,
|
|||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GhosttyResult ghostty_grid_ref_row(const GhosttyGridRef *ref,
|
||||
GHOSTTY_API GhosttyResult ghostty_grid_ref_row(const GhosttyGridRef *ref,
|
||||
GhosttyRow *out_row);
|
||||
|
||||
/**
|
||||
|
|
@ -104,11 +159,37 @@ GhosttyResult ghostty_grid_ref_row(const GhosttyGridRef *ref,
|
|||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GhosttyResult ghostty_grid_ref_graphemes(const GhosttyGridRef *ref,
|
||||
GHOSTTY_API GhosttyResult ghostty_grid_ref_graphemes(const GhosttyGridRef *ref,
|
||||
uint32_t *buf,
|
||||
size_t buf_len,
|
||||
size_t *out_len);
|
||||
|
||||
/**
|
||||
* Get the hyperlink URI for the cell at the grid reference's position.
|
||||
*
|
||||
* Writes the URI bytes into the provided buffer. If the cell has no
|
||||
* hyperlink, out_len is set to 0 and GHOSTTY_SUCCESS is returned.
|
||||
*
|
||||
* If the buffer is too small (or NULL), the function returns
|
||||
* GHOSTTY_OUT_OF_SPACE and writes the required number of bytes to
|
||||
* out_len. The caller can then retry with a sufficiently sized buffer.
|
||||
*
|
||||
* @param ref Pointer to the grid reference
|
||||
* @param buf Output buffer for the URI bytes (may be NULL)
|
||||
* @param buf_len Size of the output buffer in bytes
|
||||
* @param[out] out_len On success, the number of bytes written. On
|
||||
* GHOSTTY_OUT_OF_SPACE, the required buffer size in bytes.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the ref's
|
||||
* node is NULL, GHOSTTY_OUT_OF_SPACE if the buffer is too small
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_grid_ref_hyperlink_uri(
|
||||
const GhosttyGridRef *ref,
|
||||
uint8_t *buf,
|
||||
size_t buf_len,
|
||||
size_t *out_len);
|
||||
|
||||
/**
|
||||
* Get the style of the cell at the grid reference's position.
|
||||
*
|
||||
|
|
@ -119,7 +200,7 @@ GhosttyResult ghostty_grid_ref_graphemes(const GhosttyGridRef *ref,
|
|||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GhosttyResult ghostty_grid_ref_style(const GhosttyGridRef *ref,
|
||||
GHOSTTY_API GhosttyResult ghostty_grid_ref_style(const GhosttyGridRef *ref,
|
||||
GhosttyStyle *out_style);
|
||||
|
||||
/** @} */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
* @file grid_ref_tracked.h
|
||||
*
|
||||
* Tracked terminal grid references.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_GRID_REF_TRACKED_H
|
||||
#define GHOSTTY_VT_GRID_REF_TRACKED_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <ghostty/vt/types.h>
|
||||
#include <ghostty/vt/grid_ref.h>
|
||||
#include <ghostty/vt/point.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Tracked grid references are owned grid references that move with the
|
||||
* terminal. See @ref grid_ref for the full overview of tracked and untracked
|
||||
* grid reference behavior.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
|
||||
/**
|
||||
* Free a tracked grid reference.
|
||||
*
|
||||
* Passing NULL is allowed and has no effect. A tracked reference may be freed
|
||||
* after the terminal that created it is freed.
|
||||
*
|
||||
* @param ref Tracked grid reference to free.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API void ghostty_tracked_grid_ref_free(GhosttyTrackedGridRef ref);
|
||||
|
||||
/**
|
||||
* Return whether a tracked grid reference currently has a meaningful value.
|
||||
*
|
||||
* If the terminal that created the tracked reference has been freed, this
|
||||
* returns false.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @return true if the reference currently has a meaningful value.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API bool ghostty_tracked_grid_ref_has_value(
|
||||
GhosttyTrackedGridRef ref);
|
||||
|
||||
/**
|
||||
* Convert a tracked grid reference to a point in the requested coordinate
|
||||
* space.
|
||||
*
|
||||
* This is the tracked equivalent of ghostty_terminal_point_from_grid_ref().
|
||||
* Unlike snapshotting, this does not expose an intermediate untracked
|
||||
* GhosttyGridRef.
|
||||
*
|
||||
* A tracked reference is resolved against the terminal screen/page-list that
|
||||
* currently owns the reference. If the terminal has switched between primary
|
||||
* and alternate screens since the reference was created or last set, this may
|
||||
* be different from the terminal's currently active screen.
|
||||
*
|
||||
* If the tracked reference no longer has a meaningful value, this returns
|
||||
* GHOSTTY_NO_VALUE. GHOSTTY_NO_VALUE is also returned when the reference cannot
|
||||
* be represented in the requested coordinate space, including after the
|
||||
* terminal that created the tracked reference has been freed.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @param tag Coordinate space to convert into.
|
||||
* @param[out] out_point On success, receives the coordinate. May be NULL.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if ref is invalid,
|
||||
* or GHOSTTY_NO_VALUE if there is no representable value.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_tracked_grid_ref_point(
|
||||
GhosttyTrackedGridRef ref,
|
||||
GhosttyPointTag tag,
|
||||
GhosttyPointCoordinate *out_point);
|
||||
|
||||
/**
|
||||
* Move an existing tracked grid reference to a new terminal point.
|
||||
*
|
||||
* On success, the tracked reference begins tracking the new point and any prior
|
||||
* "no value" state is cleared. On GHOSTTY_OUT_OF_MEMORY, the original tracked
|
||||
* reference is left unchanged.
|
||||
*
|
||||
* The terminal must be the same terminal that created the tracked reference.
|
||||
* The point is resolved against the terminal screen/page-list that is active at
|
||||
* the time this function is called. If the terminal has switched between
|
||||
* primary and alternate screens, this may move the tracked reference from one
|
||||
* screen/page-list to the other.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @param terminal Terminal instance that owns the reference.
|
||||
* @param point New point to track.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if ref, terminal,
|
||||
* or point is invalid, or GHOSTTY_OUT_OF_MEMORY if allocation fails.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_tracked_grid_ref_set(
|
||||
GhosttyTrackedGridRef ref,
|
||||
GhosttyTerminal terminal,
|
||||
GhosttyPoint point);
|
||||
|
||||
/**
|
||||
* Snapshot a tracked grid reference into a regular GhosttyGridRef.
|
||||
*
|
||||
* The returned GhosttyGridRef is an untracked snapshot and has the same
|
||||
* lifetime rules as ghostty_terminal_grid_ref(): it is only valid until the
|
||||
* next terminal update. Snapshot immediately before calling
|
||||
* ghostty_grid_ref_cell(), ghostty_grid_ref_row(),
|
||||
* ghostty_grid_ref_graphemes(), ghostty_grid_ref_hyperlink_uri(), or
|
||||
* ghostty_grid_ref_style().
|
||||
*
|
||||
* If the tracked reference no longer has a meaningful value, this returns
|
||||
* GHOSTTY_NO_VALUE. This includes references whose owning terminal has been
|
||||
* freed.
|
||||
*
|
||||
* @param ref Tracked grid reference.
|
||||
* @param[out] out_ref On success, receives an untracked snapshot. May be NULL.
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if ref is invalid,
|
||||
* or GHOSTTY_NO_VALUE if the tracked location was discarded.
|
||||
*
|
||||
* @ingroup grid_ref
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_tracked_grid_ref_snapshot(
|
||||
GhosttyTrackedGridRef ref,
|
||||
GhosttyGridRef *out_ref);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GHOSTTY_VT_GRID_REF_TRACKED_H */
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
typedef struct GhosttyKeyEncoder *GhosttyKeyEncoder;
|
||||
typedef struct GhosttyKeyEncoderImpl *GhosttyKeyEncoder;
|
||||
|
||||
/**
|
||||
* Kitty keyboard protocol flags.
|
||||
|
|
@ -64,7 +64,7 @@ typedef uint8_t GhosttyKittyKeyFlags;
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Option key is not treated as alt */
|
||||
GHOSTTY_OPTION_AS_ALT_FALSE = 0,
|
||||
/** Option key is treated as alt */
|
||||
|
|
@ -73,6 +73,7 @@ typedef enum {
|
|||
GHOSTTY_OPTION_AS_ALT_LEFT = 2,
|
||||
/** Only right option key is treated as alt */
|
||||
GHOSTTY_OPTION_AS_ALT_RIGHT = 3,
|
||||
GHOSTTY_OPTION_AS_ALT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyOptionAsAlt;
|
||||
|
||||
/**
|
||||
|
|
@ -83,27 +84,36 @@ typedef enum {
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Terminal DEC mode 1: cursor key application mode (value: bool) */
|
||||
GHOSTTY_KEY_ENCODER_OPT_CURSOR_KEY_APPLICATION = 0,
|
||||
|
||||
|
||||
/** Terminal DEC mode 66: keypad key application mode (value: bool) */
|
||||
GHOSTTY_KEY_ENCODER_OPT_KEYPAD_KEY_APPLICATION = 1,
|
||||
|
||||
|
||||
/** Terminal DEC mode 1035: ignore keypad with numlock (value: bool) */
|
||||
GHOSTTY_KEY_ENCODER_OPT_IGNORE_KEYPAD_WITH_NUMLOCK = 2,
|
||||
|
||||
|
||||
/** Terminal DEC mode 1036: alt sends escape prefix (value: bool) */
|
||||
GHOSTTY_KEY_ENCODER_OPT_ALT_ESC_PREFIX = 3,
|
||||
|
||||
|
||||
/** xterm modifyOtherKeys mode 2 (value: bool) */
|
||||
GHOSTTY_KEY_ENCODER_OPT_MODIFY_OTHER_KEYS_STATE_2 = 4,
|
||||
|
||||
|
||||
/** Kitty keyboard protocol flags (value: GhosttyKittyKeyFlags bitmask) */
|
||||
GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS = 5,
|
||||
|
||||
|
||||
/** macOS option-as-alt setting (value: GhosttyOptionAsAlt) */
|
||||
GHOSTTY_KEY_ENCODER_OPT_MACOS_OPTION_AS_ALT = 6,
|
||||
|
||||
/** Backarrow key mode (value: bool)
|
||||
* See https://vt100.net/dec/ek-vt3xx-tp-002.pdf page 170
|
||||
* If `false` (the default), `backspace` emits 0x7f
|
||||
* If `true`, `backspace` emits 0x08
|
||||
*/
|
||||
GHOSTTY_KEY_ENCODER_OPT_BACKARROW_KEY_MODE = 7,
|
||||
|
||||
GHOSTTY_KEY_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKeyEncoderOption;
|
||||
|
||||
/**
|
||||
|
|
@ -119,7 +129,7 @@ typedef enum {
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
GhosttyResult ghostty_key_encoder_new(const GhosttyAllocator *allocator, GhosttyKeyEncoder *encoder);
|
||||
GHOSTTY_API GhosttyResult ghostty_key_encoder_new(const GhosttyAllocator *allocator, GhosttyKeyEncoder *encoder);
|
||||
|
||||
/**
|
||||
* Free a key encoder instance.
|
||||
|
|
@ -131,7 +141,7 @@ GhosttyResult ghostty_key_encoder_new(const GhosttyAllocator *allocator, Ghostty
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_encoder_free(GhosttyKeyEncoder encoder);
|
||||
GHOSTTY_API void ghostty_key_encoder_free(GhosttyKeyEncoder encoder);
|
||||
|
||||
/**
|
||||
* Set an option on the key encoder.
|
||||
|
|
@ -154,7 +164,7 @@ void ghostty_key_encoder_free(GhosttyKeyEncoder encoder);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_encoder_setopt(GhosttyKeyEncoder encoder, GhosttyKeyEncoderOption option, const void *value);
|
||||
GHOSTTY_API void ghostty_key_encoder_setopt(GhosttyKeyEncoder encoder, GhosttyKeyEncoderOption option, const void *value);
|
||||
|
||||
/**
|
||||
* Set encoder options from a terminal's current state.
|
||||
|
|
@ -173,7 +183,7 @@ void ghostty_key_encoder_setopt(GhosttyKeyEncoder encoder, GhosttyKeyEncoderOpti
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, GhosttyTerminal terminal);
|
||||
GHOSTTY_API void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, GhosttyTerminal terminal);
|
||||
|
||||
/**
|
||||
* Encode a key event into a terminal escape sequence.
|
||||
|
|
@ -203,17 +213,17 @@ void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, Ghostty
|
|||
* size_t required = 0;
|
||||
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required);
|
||||
* assert(result == GHOSTTY_OUT_OF_SPACE);
|
||||
*
|
||||
*
|
||||
* // Allocate buffer of required size
|
||||
* char *buf = malloc(required);
|
||||
*
|
||||
*
|
||||
* // Encode with properly sized buffer
|
||||
* size_t written = 0;
|
||||
* result = ghostty_key_encoder_encode(encoder, event, buf, required, &written);
|
||||
* assert(result == GHOSTTY_SUCCESS);
|
||||
*
|
||||
*
|
||||
* // Use the encoded sequence...
|
||||
*
|
||||
*
|
||||
* free(buf);
|
||||
* @endcode
|
||||
*
|
||||
|
|
@ -224,7 +234,7 @@ void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, Ghostty
|
|||
* char buf[128];
|
||||
* size_t written = 0;
|
||||
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
|
||||
*
|
||||
*
|
||||
* if (result == GHOSTTY_SUCCESS) {
|
||||
* // Write the encoded sequence to the terminal
|
||||
* write(pty_fd, buf, written);
|
||||
|
|
@ -240,6 +250,6 @@ void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, Ghostty
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
GhosttyResult ghostty_key_encoder_encode(GhosttyKeyEncoder encoder, GhosttyKeyEvent event, char *out_buf, size_t out_buf_size, size_t *out_len);
|
||||
GHOSTTY_API GhosttyResult ghostty_key_encoder_encode(GhosttyKeyEncoder encoder, GhosttyKeyEvent event, char *out_buf, size_t out_buf_size, size_t *out_len);
|
||||
|
||||
#endif /* GHOSTTY_VT_KEY_ENCODER_H */
|
||||
|
|
|
|||
|
|
@ -21,20 +21,21 @@
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
typedef struct GhosttyKeyEvent *GhosttyKeyEvent;
|
||||
typedef struct GhosttyKeyEventImpl *GhosttyKeyEvent;
|
||||
|
||||
/**
|
||||
* Keyboard input event types.
|
||||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Key was released */
|
||||
GHOSTTY_KEY_ACTION_RELEASE = 0,
|
||||
/** Key was pressed */
|
||||
GHOSTTY_KEY_ACTION_PRESS = 1,
|
||||
/** Key is being repeated (held down) */
|
||||
GHOSTTY_KEY_ACTION_REPEAT = 2,
|
||||
GHOSTTY_KEY_ACTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKeyAction;
|
||||
|
||||
/**
|
||||
|
|
@ -103,7 +104,7 @@ typedef uint16_t GhosttyMods;
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_KEY_UNIDENTIFIED = 0,
|
||||
|
||||
// Writing System Keys (W3C § 3.1.1)
|
||||
|
|
@ -296,6 +297,7 @@ typedef enum {
|
|||
GHOSTTY_KEY_COPY,
|
||||
GHOSTTY_KEY_CUT,
|
||||
GHOSTTY_KEY_PASTE,
|
||||
GHOSTTY_KEY_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKey;
|
||||
|
||||
/**
|
||||
|
|
@ -310,7 +312,7 @@ typedef enum {
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
GhosttyResult ghostty_key_event_new(const GhosttyAllocator *allocator, GhosttyKeyEvent *event);
|
||||
GHOSTTY_API GhosttyResult ghostty_key_event_new(const GhosttyAllocator *allocator, GhosttyKeyEvent *event);
|
||||
|
||||
/**
|
||||
* Free a key event instance.
|
||||
|
|
@ -322,7 +324,7 @@ GhosttyResult ghostty_key_event_new(const GhosttyAllocator *allocator, GhosttyKe
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_free(GhosttyKeyEvent event);
|
||||
GHOSTTY_API void ghostty_key_event_free(GhosttyKeyEvent event);
|
||||
|
||||
/**
|
||||
* Set the key action (press, release, repeat).
|
||||
|
|
@ -332,7 +334,7 @@ void ghostty_key_event_free(GhosttyKeyEvent event);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_set_action(GhosttyKeyEvent event, GhosttyKeyAction action);
|
||||
GHOSTTY_API void ghostty_key_event_set_action(GhosttyKeyEvent event, GhosttyKeyAction action);
|
||||
|
||||
/**
|
||||
* Get the key action (press, release, repeat).
|
||||
|
|
@ -342,7 +344,7 @@ void ghostty_key_event_set_action(GhosttyKeyEvent event, GhosttyKeyAction action
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
GhosttyKeyAction ghostty_key_event_get_action(GhosttyKeyEvent event);
|
||||
GHOSTTY_API GhosttyKeyAction ghostty_key_event_get_action(GhosttyKeyEvent event);
|
||||
|
||||
/**
|
||||
* Set the physical key code.
|
||||
|
|
@ -352,7 +354,7 @@ GhosttyKeyAction ghostty_key_event_get_action(GhosttyKeyEvent event);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_set_key(GhosttyKeyEvent event, GhosttyKey key);
|
||||
GHOSTTY_API void ghostty_key_event_set_key(GhosttyKeyEvent event, GhosttyKey key);
|
||||
|
||||
/**
|
||||
* Get the physical key code.
|
||||
|
|
@ -362,7 +364,7 @@ void ghostty_key_event_set_key(GhosttyKeyEvent event, GhosttyKey key);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
GhosttyKey ghostty_key_event_get_key(GhosttyKeyEvent event);
|
||||
GHOSTTY_API GhosttyKey ghostty_key_event_get_key(GhosttyKeyEvent event);
|
||||
|
||||
/**
|
||||
* Set the modifier keys bitmask.
|
||||
|
|
@ -372,7 +374,7 @@ GhosttyKey ghostty_key_event_get_key(GhosttyKeyEvent event);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_set_mods(GhosttyKeyEvent event, GhosttyMods mods);
|
||||
GHOSTTY_API void ghostty_key_event_set_mods(GhosttyKeyEvent event, GhosttyMods mods);
|
||||
|
||||
/**
|
||||
* Get the modifier keys bitmask.
|
||||
|
|
@ -382,7 +384,7 @@ void ghostty_key_event_set_mods(GhosttyKeyEvent event, GhosttyMods mods);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
GhosttyMods ghostty_key_event_get_mods(GhosttyKeyEvent event);
|
||||
GHOSTTY_API GhosttyMods ghostty_key_event_get_mods(GhosttyKeyEvent event);
|
||||
|
||||
/**
|
||||
* Set the consumed modifiers bitmask.
|
||||
|
|
@ -392,7 +394,7 @@ GhosttyMods ghostty_key_event_get_mods(GhosttyKeyEvent event);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_set_consumed_mods(GhosttyKeyEvent event, GhosttyMods consumed_mods);
|
||||
GHOSTTY_API void ghostty_key_event_set_consumed_mods(GhosttyKeyEvent event, GhosttyMods consumed_mods);
|
||||
|
||||
/**
|
||||
* Get the consumed modifiers bitmask.
|
||||
|
|
@ -402,7 +404,7 @@ void ghostty_key_event_set_consumed_mods(GhosttyKeyEvent event, GhosttyMods cons
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
GhosttyMods ghostty_key_event_get_consumed_mods(GhosttyKeyEvent event);
|
||||
GHOSTTY_API GhosttyMods ghostty_key_event_get_consumed_mods(GhosttyKeyEvent event);
|
||||
|
||||
/**
|
||||
* Set whether the key event is part of a composition sequence.
|
||||
|
|
@ -412,7 +414,7 @@ GhosttyMods ghostty_key_event_get_consumed_mods(GhosttyKeyEvent event);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_set_composing(GhosttyKeyEvent event, bool composing);
|
||||
GHOSTTY_API void ghostty_key_event_set_composing(GhosttyKeyEvent event, bool composing);
|
||||
|
||||
/**
|
||||
* Get whether the key event is part of a composition sequence.
|
||||
|
|
@ -422,10 +424,16 @@ void ghostty_key_event_set_composing(GhosttyKeyEvent event, bool composing);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
bool ghostty_key_event_get_composing(GhosttyKeyEvent event);
|
||||
GHOSTTY_API bool ghostty_key_event_get_composing(GhosttyKeyEvent event);
|
||||
|
||||
/**
|
||||
* Set the UTF-8 text generated by the key event.
|
||||
* Set the UTF-8 text generated by the key for the current keyboard layout.
|
||||
*
|
||||
* Must contain the unmodified character before any Ctrl/Meta transformations.
|
||||
* The encoder derives modifier sequences from the logical key and mods
|
||||
* bitmask, not from this text. Do not pass C0 control characters
|
||||
* (U+0000-U+001F, U+007F) or platform function key codes (e.g. macOS PUA
|
||||
* U+F700-U+F8FF); pass NULL instead and let the encoder use the logical key.
|
||||
*
|
||||
* The key event does NOT take ownership of the text pointer. The caller
|
||||
* must ensure the string remains valid for the lifetime needed by the event.
|
||||
|
|
@ -436,7 +444,7 @@ bool ghostty_key_event_get_composing(GhosttyKeyEvent event);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_set_utf8(GhosttyKeyEvent event, const char *utf8, size_t len);
|
||||
GHOSTTY_API void ghostty_key_event_set_utf8(GhosttyKeyEvent event, const char *utf8, size_t len);
|
||||
|
||||
/**
|
||||
* Get the UTF-8 text generated by the key event.
|
||||
|
|
@ -449,7 +457,7 @@ void ghostty_key_event_set_utf8(GhosttyKeyEvent event, const char *utf8, size_t
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
const char *ghostty_key_event_get_utf8(GhosttyKeyEvent event, size_t *len);
|
||||
GHOSTTY_API const char *ghostty_key_event_get_utf8(GhosttyKeyEvent event, size_t *len);
|
||||
|
||||
/**
|
||||
* Set the unshifted Unicode codepoint.
|
||||
|
|
@ -459,7 +467,7 @@ const char *ghostty_key_event_get_utf8(GhosttyKeyEvent event, size_t *len);
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
void ghostty_key_event_set_unshifted_codepoint(GhosttyKeyEvent event, uint32_t codepoint);
|
||||
GHOSTTY_API void ghostty_key_event_set_unshifted_codepoint(GhosttyKeyEvent event, uint32_t codepoint);
|
||||
|
||||
/**
|
||||
* Get the unshifted Unicode codepoint.
|
||||
|
|
@ -469,6 +477,6 @@ void ghostty_key_event_set_unshifted_codepoint(GhosttyKeyEvent event, uint32_t c
|
|||
*
|
||||
* @ingroup key
|
||||
*/
|
||||
uint32_t ghostty_key_event_get_unshifted_codepoint(GhosttyKeyEvent event);
|
||||
GHOSTTY_API uint32_t ghostty_key_event_get_unshifted_codepoint(GhosttyKeyEvent event);
|
||||
|
||||
#endif /* GHOSTTY_VT_KEY_EVENT_H */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,775 @@
|
|||
/**
|
||||
* @file kitty_graphics.h
|
||||
*
|
||||
* Kitty graphics protocol
|
||||
*
|
||||
* See @ref kitty_graphics for a full usage guide.
|
||||
*/
|
||||
|
||||
#ifndef GHOSTTY_VT_KITTY_GRAPHICS_H
|
||||
#define GHOSTTY_VT_KITTY_GRAPHICS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <ghostty/vt/allocator.h>
|
||||
#include <ghostty/vt/selection.h>
|
||||
#include <ghostty/vt/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup kitty_graphics Kitty Graphics
|
||||
*
|
||||
* API for inspecting images and placements stored via the
|
||||
* [Kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/).
|
||||
*
|
||||
* The central object is @ref GhosttyKittyGraphics, an opaque handle to
|
||||
* the image storage associated with a terminal's active screen. From it
|
||||
* you can iterate over placements and look up individual images.
|
||||
*
|
||||
* ## Obtaining a KittyGraphics Handle
|
||||
*
|
||||
* A @ref GhosttyKittyGraphics handle is obtained from a terminal via
|
||||
* ghostty_terminal_get() with @ref GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS.
|
||||
* The handle is borrowed from the terminal and remains valid until the
|
||||
* next mutating terminal call (e.g. ghostty_terminal_vt_write() or
|
||||
* ghostty_terminal_reset()).
|
||||
*
|
||||
* Before images can be stored, Kitty graphics must be enabled on the
|
||||
* terminal by setting a non-zero storage limit with
|
||||
* @ref GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_STORAGE_LIMIT, and a PNG
|
||||
* decoder callback must be installed via ghostty_sys_set() with
|
||||
* @ref GHOSTTY_SYS_OPT_DECODE_PNG.
|
||||
*
|
||||
* @snippet c-vt-kitty-graphics/src/main.c kitty-graphics-decode-png
|
||||
*
|
||||
* ## Iterating Placements
|
||||
*
|
||||
* Placements are inspected through a @ref GhosttyKittyGraphicsPlacementIterator.
|
||||
* The typical workflow is:
|
||||
*
|
||||
* 1. Create an iterator with ghostty_kitty_graphics_placement_iterator_new().
|
||||
* 2. Populate it from the storage with ghostty_kitty_graphics_get() using
|
||||
* @ref GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR.
|
||||
* 3. Optionally filter by z-layer with
|
||||
* ghostty_kitty_graphics_placement_iterator_set().
|
||||
* 4. Advance with ghostty_kitty_graphics_placement_next() and read
|
||||
* per-placement data with ghostty_kitty_graphics_placement_get().
|
||||
* 5. For each placement, look up its image with
|
||||
* ghostty_kitty_graphics_image() to access pixel data and dimensions.
|
||||
* 6. Free the iterator with ghostty_kitty_graphics_placement_iterator_free().
|
||||
*
|
||||
* ## Looking Up Images
|
||||
*
|
||||
* Given an image ID (obtained from a placement via
|
||||
* @ref GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID), call
|
||||
* ghostty_kitty_graphics_image() to get a @ref GhosttyKittyGraphicsImage
|
||||
* handle. From this handle, ghostty_kitty_graphics_image_get() provides
|
||||
* the image dimensions, pixel format, compression, and a borrowed pointer
|
||||
* to the raw pixel data.
|
||||
*
|
||||
* ## Rendering Helpers
|
||||
*
|
||||
* Several functions assist with rendering a placement:
|
||||
*
|
||||
* - ghostty_kitty_graphics_placement_pixel_size() — rendered pixel
|
||||
* dimensions accounting for source rect and aspect ratio.
|
||||
* - ghostty_kitty_graphics_placement_grid_size() — number of grid
|
||||
* columns and rows the placement occupies.
|
||||
* - ghostty_kitty_graphics_placement_viewport_pos() — viewport-relative
|
||||
* grid position (may be negative for partially scrolled placements).
|
||||
* - ghostty_kitty_graphics_placement_source_rect() — resolved source
|
||||
* rectangle in pixels, clamped to image bounds.
|
||||
* - ghostty_kitty_graphics_placement_rect() — bounding rectangle as a
|
||||
* @ref GhosttySelection.
|
||||
*
|
||||
* ## Lifetime and Thread Safety
|
||||
*
|
||||
* All handles borrowed from the terminal (GhosttyKittyGraphics,
|
||||
* GhosttyKittyGraphicsImage) are invalidated by any mutating terminal
|
||||
* call. The placement iterator is independently owned and must be freed
|
||||
* by the caller, but the data it yields is only valid while the
|
||||
* underlying terminal is not mutated.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* The following example creates a terminal, sends a Kitty graphics
|
||||
* image, then iterates placements and prints image metadata:
|
||||
*
|
||||
* @snippet c-vt-kitty-graphics/src/main.c kitty-graphics-main
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Queryable data kinds for ghostty_kitty_graphics_get().
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Invalid / sentinel value. */
|
||||
GHOSTTY_KITTY_GRAPHICS_DATA_INVALID = 0,
|
||||
|
||||
/**
|
||||
* Populate a pre-allocated placement iterator with placement data from
|
||||
* the storage. Iterator data is only valid as long as the underlying
|
||||
* terminal is not mutated.
|
||||
*
|
||||
* Output type: GhosttyKittyGraphicsPlacementIterator *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR = 1,
|
||||
GHOSTTY_KITTY_GRAPHICS_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyGraphicsData;
|
||||
|
||||
/**
|
||||
* Queryable data kinds for ghostty_kitty_graphics_placement_get().
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Invalid / sentinel value. */
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INVALID = 0,
|
||||
|
||||
/**
|
||||
* The image ID this placement belongs to.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID = 1,
|
||||
|
||||
/**
|
||||
* The placement ID.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID = 2,
|
||||
|
||||
/**
|
||||
* Whether this is a virtual placement (unicode placeholder).
|
||||
*
|
||||
* Output type: bool *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL = 3,
|
||||
|
||||
/**
|
||||
* Pixel offset from the left edge of the cell.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_X_OFFSET = 4,
|
||||
|
||||
/**
|
||||
* Pixel offset from the top edge of the cell.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Y_OFFSET = 5,
|
||||
|
||||
/**
|
||||
* Source rectangle x origin in pixels.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_X = 6,
|
||||
|
||||
/**
|
||||
* Source rectangle y origin in pixels.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_Y = 7,
|
||||
|
||||
/**
|
||||
* Source rectangle width in pixels (0 = full image width).
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_WIDTH = 8,
|
||||
|
||||
/**
|
||||
* Source rectangle height in pixels (0 = full image height).
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_SOURCE_HEIGHT = 9,
|
||||
|
||||
/**
|
||||
* Number of columns this placement occupies.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_COLUMNS = 10,
|
||||
|
||||
/**
|
||||
* Number of rows this placement occupies.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_ROWS = 11,
|
||||
|
||||
/**
|
||||
* Z-index for this placement.
|
||||
*
|
||||
* Output type: int32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z = 12,
|
||||
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyGraphicsPlacementData;
|
||||
|
||||
/**
|
||||
* Z-layer classification for kitty graphics placements.
|
||||
*
|
||||
* Based on the kitty protocol z-index conventions:
|
||||
* - BELOW_BG: z < INT32_MIN/2 (drawn below cell background)
|
||||
* - BELOW_TEXT: INT32_MIN/2 <= z < 0 (above background, below text)
|
||||
* - ABOVE_TEXT: z >= 0 (above text)
|
||||
* - ALL: no filtering (current behavior)
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_KITTY_PLACEMENT_LAYER_ALL = 0,
|
||||
GHOSTTY_KITTY_PLACEMENT_LAYER_BELOW_BG = 1,
|
||||
GHOSTTY_KITTY_PLACEMENT_LAYER_BELOW_TEXT = 2,
|
||||
GHOSTTY_KITTY_PLACEMENT_LAYER_ABOVE_TEXT = 3,
|
||||
GHOSTTY_KITTY_PLACEMENT_LAYER_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyPlacementLayer;
|
||||
|
||||
/**
|
||||
* Settable options for ghostty_kitty_graphics_placement_iterator_set().
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/**
|
||||
* Set the z-layer filter for the iterator.
|
||||
*
|
||||
* Input type: GhosttyKittyPlacementLayer *
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_LAYER = 0,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyGraphicsPlacementIteratorOption;
|
||||
|
||||
/**
|
||||
* Pixel format of a Kitty graphics image.
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_KITTY_IMAGE_FORMAT_RGB = 0,
|
||||
GHOSTTY_KITTY_IMAGE_FORMAT_RGBA = 1,
|
||||
GHOSTTY_KITTY_IMAGE_FORMAT_PNG = 2,
|
||||
GHOSTTY_KITTY_IMAGE_FORMAT_GRAY_ALPHA = 3,
|
||||
GHOSTTY_KITTY_IMAGE_FORMAT_GRAY = 4,
|
||||
GHOSTTY_KITTY_IMAGE_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyImageFormat;
|
||||
|
||||
/**
|
||||
* Compression of a Kitty graphics image.
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_KITTY_IMAGE_COMPRESSION_NONE = 0,
|
||||
GHOSTTY_KITTY_IMAGE_COMPRESSION_ZLIB_DEFLATE = 1,
|
||||
GHOSTTY_KITTY_IMAGE_COMPRESSION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyImageCompression;
|
||||
|
||||
/**
|
||||
* Queryable data kinds for ghostty_kitty_graphics_image_get().
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Invalid / sentinel value. */
|
||||
GHOSTTY_KITTY_IMAGE_DATA_INVALID = 0,
|
||||
|
||||
/**
|
||||
* The image ID.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_ID = 1,
|
||||
|
||||
/**
|
||||
* The image number.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_NUMBER = 2,
|
||||
|
||||
/**
|
||||
* Image width in pixels.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_WIDTH = 3,
|
||||
|
||||
/**
|
||||
* Image height in pixels.
|
||||
*
|
||||
* Output type: uint32_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_HEIGHT = 4,
|
||||
|
||||
/**
|
||||
* Pixel format of the image.
|
||||
*
|
||||
* Output type: GhosttyKittyImageFormat *
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_FORMAT = 5,
|
||||
|
||||
/**
|
||||
* Compression of the image.
|
||||
*
|
||||
* Output type: GhosttyKittyImageCompression *
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_COMPRESSION = 6,
|
||||
|
||||
/**
|
||||
* Borrowed pointer to the raw pixel data. Valid as long as the
|
||||
* underlying terminal is not mutated.
|
||||
*
|
||||
* Output type: const uint8_t **
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_DATA_PTR = 7,
|
||||
|
||||
/**
|
||||
* Length of the raw pixel data in bytes.
|
||||
*
|
||||
* Output type: size_t *
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN = 8,
|
||||
|
||||
GHOSTTY_KITTY_IMAGE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyGraphicsImageData;
|
||||
|
||||
/**
|
||||
* Combined rendering geometry for a placement in a single sized struct.
|
||||
*
|
||||
* Combines the results of ghostty_kitty_graphics_placement_pixel_size(),
|
||||
* ghostty_kitty_graphics_placement_grid_size(),
|
||||
* ghostty_kitty_graphics_placement_viewport_pos(), and
|
||||
* ghostty_kitty_graphics_placement_source_rect() into one call. This is
|
||||
* an optimization over calling those four functions individually,
|
||||
* particularly useful in environments with high per-call overhead such
|
||||
* as FFI or Cgo.
|
||||
*
|
||||
* This struct uses the sized-struct ABI pattern. Initialize with
|
||||
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementRenderInfo) before calling
|
||||
* ghostty_kitty_graphics_placement_render_info().
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef struct {
|
||||
/** Size of this struct in bytes. Must be set to sizeof(GhosttyKittyGraphicsPlacementRenderInfo). */
|
||||
size_t size;
|
||||
/** Rendered width in pixels. */
|
||||
uint32_t pixel_width;
|
||||
/** Rendered height in pixels. */
|
||||
uint32_t pixel_height;
|
||||
/** Number of grid columns the placement occupies. */
|
||||
uint32_t grid_cols;
|
||||
/** Number of grid rows the placement occupies. */
|
||||
uint32_t grid_rows;
|
||||
/** Viewport-relative column (may be negative for partially visible placements). */
|
||||
int32_t viewport_col;
|
||||
/** Viewport-relative row (may be negative for partially visible placements). */
|
||||
int32_t viewport_row;
|
||||
/** False when the placement is fully off-screen or virtual. */
|
||||
bool viewport_visible;
|
||||
/** Resolved source rectangle x origin in pixels. */
|
||||
uint32_t source_x;
|
||||
/** Resolved source rectangle y origin in pixels. */
|
||||
uint32_t source_y;
|
||||
/** Resolved source rectangle width in pixels. */
|
||||
uint32_t source_width;
|
||||
/** Resolved source rectangle height in pixels. */
|
||||
uint32_t source_height;
|
||||
} GhosttyKittyGraphicsPlacementRenderInfo;
|
||||
|
||||
/**
|
||||
* Get data from a kitty graphics storage instance.
|
||||
*
|
||||
* The output pointer must be of the appropriate type for the requested
|
||||
* data kind.
|
||||
*
|
||||
* Returns GHOSTTY_NO_VALUE when Kitty graphics are disabled at build time.
|
||||
*
|
||||
* @param graphics The kitty graphics handle
|
||||
* @param data The type of data to extract
|
||||
* @param[out] out Pointer to store the extracted data
|
||||
* @return GHOSTTY_SUCCESS on success
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_get(
|
||||
GhosttyKittyGraphics graphics,
|
||||
GhosttyKittyGraphicsData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Look up a Kitty graphics image by its image ID.
|
||||
*
|
||||
* Returns NULL if no image with the given ID exists or if Kitty graphics
|
||||
* are disabled at build time.
|
||||
*
|
||||
* @param graphics The kitty graphics handle
|
||||
* @param image_id The image ID to look up
|
||||
* @return An opaque image handle, or NULL if not found
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyKittyGraphicsImage ghostty_kitty_graphics_image(
|
||||
GhosttyKittyGraphics graphics,
|
||||
uint32_t image_id);
|
||||
|
||||
/**
|
||||
* Get data from a Kitty graphics image.
|
||||
*
|
||||
* The output pointer must be of the appropriate type for the requested
|
||||
* data kind.
|
||||
*
|
||||
* @param image The image handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param data The data kind to query
|
||||
* @param[out] out Pointer to receive the queried value
|
||||
* @return GHOSTTY_SUCCESS on success
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get(
|
||||
GhosttyKittyGraphicsImage image,
|
||||
GhosttyKittyGraphicsImageData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from a Kitty graphics image in a single call.
|
||||
*
|
||||
* This is an optimization over calling ghostty_kitty_graphics_image_get()
|
||||
* repeatedly, particularly useful in environments with high per-call
|
||||
* overhead such as FFI or Cgo.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
* The type of each values[i] pointer must match the output type
|
||||
* documented for keys[i].
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param image The image handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get_multi(
|
||||
GhosttyKittyGraphicsImage image,
|
||||
size_t count,
|
||||
const GhosttyKittyGraphicsImageData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Create a new placement iterator instance.
|
||||
*
|
||||
* All fields except the allocator are left undefined until populated
|
||||
* via ghostty_kitty_graphics_get() with
|
||||
* GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR.
|
||||
*
|
||||
* @param allocator Pointer to allocator, or NULL to use the default allocator
|
||||
* @param[out] out_iterator On success, receives the created iterator handle
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY on allocation
|
||||
* failure
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_iterator_new(
|
||||
const GhosttyAllocator* allocator,
|
||||
GhosttyKittyGraphicsPlacementIterator* out_iterator);
|
||||
|
||||
/**
|
||||
* Free a placement iterator.
|
||||
*
|
||||
* @param iterator The iterator handle to free (may be NULL)
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API void ghostty_kitty_graphics_placement_iterator_free(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator);
|
||||
|
||||
/**
|
||||
* Set an option on a placement iterator.
|
||||
*
|
||||
* Use GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_LAYER with a
|
||||
* GhosttyKittyPlacementLayer value to filter placements by z-layer.
|
||||
* The filter is applied during iteration: ghostty_kitty_graphics_placement_next()
|
||||
* will skip placements that do not match the configured layer.
|
||||
*
|
||||
* The default layer is GHOSTTY_KITTY_PLACEMENT_LAYER_ALL (no filtering).
|
||||
*
|
||||
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param option The option to set
|
||||
* @param value Pointer to the value (type depends on option; NULL returns
|
||||
* GHOSTTY_INVALID_VALUE)
|
||||
* @return GHOSTTY_SUCCESS on success
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_iterator_set(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsPlacementIteratorOption option,
|
||||
const void* value);
|
||||
|
||||
/**
|
||||
* Advance the placement iterator to the next placement.
|
||||
*
|
||||
* If a layer filter has been set via
|
||||
* ghostty_kitty_graphics_placement_iterator_set(), only placements
|
||||
* matching that layer are returned.
|
||||
*
|
||||
* @param iterator The iterator handle (may be NULL)
|
||||
* @return true if advanced to the next placement, false if at the end
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API bool ghostty_kitty_graphics_placement_next(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator);
|
||||
|
||||
/**
|
||||
* Get data from the current placement in a placement iterator.
|
||||
*
|
||||
* Call ghostty_kitty_graphics_placement_next() at least once before
|
||||
* calling this function.
|
||||
*
|
||||
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param data The data kind to query
|
||||
* @param[out] out Pointer to receive the queried value
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if the
|
||||
* iterator is NULL or not positioned on a placement
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsPlacementData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from the current placement in a single call.
|
||||
*
|
||||
* This is an optimization over calling ghostty_kitty_graphics_placement_get()
|
||||
* repeatedly, particularly useful in environments with high per-call
|
||||
* overhead such as FFI or Cgo.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
* The type of each values[i] pointer must match the output type
|
||||
* documented for keys[i].
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get_multi(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
size_t count,
|
||||
const GhosttyKittyGraphicsPlacementData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Compute the grid rectangle occupied by the current placement.
|
||||
*
|
||||
* Uses the placement's pin, the image dimensions, and the terminal's
|
||||
* cell/pixel geometry to calculate the bounding rectangle. Virtual
|
||||
* placements (unicode placeholders) return GHOSTTY_NO_VALUE.
|
||||
*
|
||||
* @param terminal The terminal handle
|
||||
* @param image The image handle for this placement's image
|
||||
* @param iterator The placement iterator positioned on a placement
|
||||
* @param[out] out_selection On success, receives the bounding rectangle
|
||||
* as a selection with rectangle=true
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any handle
|
||||
* is NULL or the iterator is not positioned, GHOSTTY_NO_VALUE for
|
||||
* virtual placements or when Kitty graphics are disabled
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_rect(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsImage image,
|
||||
GhosttyTerminal terminal,
|
||||
GhosttySelection* out_selection);
|
||||
|
||||
/**
|
||||
* Compute the rendered pixel size of the current placement.
|
||||
*
|
||||
* Takes into account the placement's source rectangle, specified
|
||||
* columns/rows, and aspect ratio to calculate the final rendered
|
||||
* pixel dimensions.
|
||||
*
|
||||
* @param iterator The placement iterator positioned on a placement
|
||||
* @param image The image handle for this placement's image
|
||||
* @param terminal The terminal handle
|
||||
* @param[out] out_width On success, receives the width in pixels
|
||||
* @param[out] out_height On success, receives the height in pixels
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any handle
|
||||
* is NULL or the iterator is not positioned, GHOSTTY_NO_VALUE when
|
||||
* Kitty graphics are disabled
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_pixel_size(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsImage image,
|
||||
GhosttyTerminal terminal,
|
||||
uint32_t* out_width,
|
||||
uint32_t* out_height);
|
||||
|
||||
/**
|
||||
* Compute the grid cell size of the current placement.
|
||||
*
|
||||
* Returns the number of columns and rows that the placement occupies
|
||||
* in the terminal grid. If the placement specifies explicit columns
|
||||
* and rows, those are returned directly; otherwise they are calculated
|
||||
* from the pixel size and cell dimensions.
|
||||
*
|
||||
* @param iterator The placement iterator positioned on a placement
|
||||
* @param image The image handle for this placement's image
|
||||
* @param terminal The terminal handle
|
||||
* @param[out] out_cols On success, receives the number of columns
|
||||
* @param[out] out_rows On success, receives the number of rows
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any handle
|
||||
* is NULL or the iterator is not positioned, GHOSTTY_NO_VALUE when
|
||||
* Kitty graphics are disabled
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_grid_size(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsImage image,
|
||||
GhosttyTerminal terminal,
|
||||
uint32_t* out_cols,
|
||||
uint32_t* out_rows);
|
||||
|
||||
/**
|
||||
* Get the viewport-relative grid position of the current placement.
|
||||
*
|
||||
* Converts the placement's internal pin to viewport-relative column and
|
||||
* row coordinates. The returned coordinates represent the top-left
|
||||
* corner of the placement in the viewport's grid coordinate space.
|
||||
*
|
||||
* The row value can be negative when the placement's origin has
|
||||
* scrolled above the top of the viewport. For example, a 4-row
|
||||
* image that has scrolled up by 2 rows returns row=-2, meaning
|
||||
* its top 2 rows are above the visible area but its bottom 2 rows
|
||||
* are still on screen. Embedders should use these coordinates
|
||||
* directly when computing the destination rectangle for rendering;
|
||||
* the embedder is responsible for clipping the portion of the image
|
||||
* that falls outside the viewport.
|
||||
*
|
||||
* Returns GHOSTTY_SUCCESS for any placement that is at least
|
||||
* partially visible in the viewport. Returns GHOSTTY_NO_VALUE when
|
||||
* the placement is completely outside the viewport (its bottom edge
|
||||
* is above the viewport or its top edge is at or below the last
|
||||
* viewport row), or when the placement is a virtual (unicode
|
||||
* placeholder) placement.
|
||||
*
|
||||
* @param iterator The placement iterator positioned on a placement
|
||||
* @param image The image handle for this placement's image
|
||||
* @param terminal The terminal handle
|
||||
* @param[out] out_col On success, receives the viewport-relative column
|
||||
* @param[out] out_row On success, receives the viewport-relative row
|
||||
* (may be negative for partially visible placements)
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if fully
|
||||
* off-screen or virtual, GHOSTTY_INVALID_VALUE if any handle
|
||||
* is NULL or the iterator is not positioned
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_viewport_pos(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsImage image,
|
||||
GhosttyTerminal terminal,
|
||||
int32_t* out_col,
|
||||
int32_t* out_row);
|
||||
|
||||
/**
|
||||
* Get the resolved source rectangle for the current placement.
|
||||
*
|
||||
* Applies kitty protocol semantics: a width or height of 0 in the
|
||||
* placement means "use the full image dimension", and the resulting
|
||||
* rectangle is clamped to the actual image bounds. The returned
|
||||
* values are in pixels and are ready to use for texture sampling.
|
||||
*
|
||||
* @param iterator The placement iterator positioned on a placement
|
||||
* @param image The image handle for this placement's image
|
||||
* @param[out] out_x Source rect x origin in pixels
|
||||
* @param[out] out_y Source rect y origin in pixels
|
||||
* @param[out] out_width Source rect width in pixels
|
||||
* @param[out] out_height Source rect height in pixels
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any
|
||||
* handle is NULL or the iterator is not positioned
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_source_rect(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsImage image,
|
||||
uint32_t* out_x,
|
||||
uint32_t* out_y,
|
||||
uint32_t* out_width,
|
||||
uint32_t* out_height);
|
||||
|
||||
/**
|
||||
* Get all rendering geometry for a placement in a single call.
|
||||
*
|
||||
* Combines pixel size, grid size, viewport position, and source
|
||||
* rectangle into one struct. Initialize with
|
||||
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementRenderInfo).
|
||||
*
|
||||
* When viewport_visible is false, the placement is fully off-screen
|
||||
* or is a virtual placement; viewport_col and viewport_row may
|
||||
* contain meaningless values in that case.
|
||||
*
|
||||
* @param iterator The iterator positioned on a placement
|
||||
* @param image The image handle for this placement's image
|
||||
* @param terminal The terminal handle
|
||||
* @param[out] out_info Pointer to receive the rendering geometry
|
||||
* @return GHOSTTY_SUCCESS on success
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_render_info(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsImage image,
|
||||
GhosttyTerminal terminal,
|
||||
GhosttyKittyGraphicsPlacementRenderInfo* out_info);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GHOSTTY_VT_KITTY_GRAPHICS_H */
|
||||
|
|
@ -70,6 +70,7 @@ extern "C" {
|
|||
#define GHOSTTY_MODE_REVERSE_WRAP (ghostty_mode_new(45, false)) /**< Reverse wrap */
|
||||
#define GHOSTTY_MODE_ALT_SCREEN_LEGACY (ghostty_mode_new(47, false)) /**< Alternate screen (legacy) */
|
||||
#define GHOSTTY_MODE_KEYPAD_KEYS (ghostty_mode_new(66, false)) /**< Application keypad */
|
||||
#define GHOSTTY_MODE_BACKARROW_KEY_MODE (ghostty_mode_new(67, false)) /**< Backarrow key mode (DECBKM) */
|
||||
#define GHOSTTY_MODE_LEFT_RIGHT_MARGIN (ghostty_mode_new(69, false)) /**< Left/right margin mode */
|
||||
#define GHOSTTY_MODE_NORMAL_MOUSE (ghostty_mode_new(1000, false)) /**< Normal mouse tracking */
|
||||
#define GHOSTTY_MODE_BUTTON_MOUSE (ghostty_mode_new(1002, false)) /**< Button-event mouse tracking */
|
||||
|
|
@ -146,7 +147,7 @@ static inline bool ghostty_mode_ansi(GhosttyMode mode) {
|
|||
* These correspond to the Ps2 parameter in a DECRPM response
|
||||
* sequence (CSI ? Ps1 ; Ps2 $ y).
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Mode is not recognized */
|
||||
GHOSTTY_MODE_REPORT_NOT_RECOGNIZED = 0,
|
||||
/** Mode is set (enabled) */
|
||||
|
|
@ -157,6 +158,7 @@ typedef enum {
|
|||
GHOSTTY_MODE_REPORT_PERMANENTLY_SET = 3,
|
||||
/** Mode is permanently reset */
|
||||
GHOSTTY_MODE_REPORT_PERMANENTLY_RESET = 4,
|
||||
GHOSTTY_MODE_REPORT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyModeReportState;
|
||||
|
||||
/**
|
||||
|
|
@ -180,7 +182,7 @@ typedef enum {
|
|||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if the buffer
|
||||
* is too small
|
||||
*/
|
||||
GhosttyResult ghostty_mode_report_encode(
|
||||
GHOSTTY_API GhosttyResult ghostty_mode_report_encode(
|
||||
GhosttyMode mode,
|
||||
GhosttyModeReportState state,
|
||||
char* buf,
|
||||
|
|
|
|||
|
|
@ -23,14 +23,14 @@
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
typedef struct GhosttyMouseEncoder *GhosttyMouseEncoder;
|
||||
typedef struct GhosttyMouseEncoderImpl *GhosttyMouseEncoder;
|
||||
|
||||
/**
|
||||
* Mouse tracking mode.
|
||||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Mouse reporting disabled. */
|
||||
GHOSTTY_MOUSE_TRACKING_NONE = 0,
|
||||
|
||||
|
|
@ -45,6 +45,7 @@ typedef enum {
|
|||
|
||||
/** Any-event tracking mode. */
|
||||
GHOSTTY_MOUSE_TRACKING_ANY = 4,
|
||||
GHOSTTY_MOUSE_TRACKING_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyMouseTrackingMode;
|
||||
|
||||
/**
|
||||
|
|
@ -52,12 +53,13 @@ typedef enum {
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_MOUSE_FORMAT_X10 = 0,
|
||||
GHOSTTY_MOUSE_FORMAT_UTF8 = 1,
|
||||
GHOSTTY_MOUSE_FORMAT_SGR = 2,
|
||||
GHOSTTY_MOUSE_FORMAT_URXVT = 3,
|
||||
GHOSTTY_MOUSE_FORMAT_SGR_PIXELS = 4,
|
||||
GHOSTTY_MOUSE_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyMouseFormat;
|
||||
|
||||
/**
|
||||
|
|
@ -105,7 +107,7 @@ typedef struct {
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Mouse tracking mode (value: GhosttyMouseTrackingMode). */
|
||||
GHOSTTY_MOUSE_ENCODER_OPT_EVENT = 0,
|
||||
|
||||
|
|
@ -120,6 +122,7 @@ typedef enum {
|
|||
|
||||
/** Whether to enable motion deduplication by last cell (value: bool). */
|
||||
GHOSTTY_MOUSE_ENCODER_OPT_TRACK_LAST_CELL = 4,
|
||||
GHOSTTY_MOUSE_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyMouseEncoderOption;
|
||||
|
||||
/**
|
||||
|
|
@ -131,7 +134,7 @@ typedef enum {
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
GhosttyResult ghostty_mouse_encoder_new(const GhosttyAllocator *allocator,
|
||||
GHOSTTY_API GhosttyResult ghostty_mouse_encoder_new(const GhosttyAllocator *allocator,
|
||||
GhosttyMouseEncoder *encoder);
|
||||
|
||||
/**
|
||||
|
|
@ -141,7 +144,7 @@ GhosttyResult ghostty_mouse_encoder_new(const GhosttyAllocator *allocator,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_encoder_free(GhosttyMouseEncoder encoder);
|
||||
GHOSTTY_API void ghostty_mouse_encoder_free(GhosttyMouseEncoder encoder);
|
||||
|
||||
/**
|
||||
* Set an option on the mouse encoder.
|
||||
|
|
@ -154,7 +157,7 @@ void ghostty_mouse_encoder_free(GhosttyMouseEncoder encoder);
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_encoder_setopt(GhosttyMouseEncoder encoder,
|
||||
GHOSTTY_API void ghostty_mouse_encoder_setopt(GhosttyMouseEncoder encoder,
|
||||
GhosttyMouseEncoderOption option,
|
||||
const void *value);
|
||||
|
||||
|
|
@ -169,7 +172,7 @@ void ghostty_mouse_encoder_setopt(GhosttyMouseEncoder encoder,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_encoder_setopt_from_terminal(GhosttyMouseEncoder encoder,
|
||||
GHOSTTY_API void ghostty_mouse_encoder_setopt_from_terminal(GhosttyMouseEncoder encoder,
|
||||
GhosttyTerminal terminal);
|
||||
|
||||
/**
|
||||
|
|
@ -181,7 +184,7 @@ void ghostty_mouse_encoder_setopt_from_terminal(GhosttyMouseEncoder encoder,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_encoder_reset(GhosttyMouseEncoder encoder);
|
||||
GHOSTTY_API void ghostty_mouse_encoder_reset(GhosttyMouseEncoder encoder);
|
||||
|
||||
/**
|
||||
* Encode a mouse event into a terminal escape sequence.
|
||||
|
|
@ -202,7 +205,7 @@ void ghostty_mouse_encoder_reset(GhosttyMouseEncoder encoder);
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
GhosttyResult ghostty_mouse_encoder_encode(GhosttyMouseEncoder encoder,
|
||||
GHOSTTY_API GhosttyResult ghostty_mouse_encoder_encode(GhosttyMouseEncoder encoder,
|
||||
GhosttyMouseEvent event,
|
||||
char *out_buf,
|
||||
size_t out_buf_size,
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
typedef struct GhosttyMouseEvent *GhosttyMouseEvent;
|
||||
typedef struct GhosttyMouseEventImpl *GhosttyMouseEvent;
|
||||
|
||||
/**
|
||||
* Mouse event action type.
|
||||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
/** Mouse button was pressed. */
|
||||
GHOSTTY_MOUSE_ACTION_PRESS = 0,
|
||||
|
||||
|
|
@ -36,6 +36,7 @@ typedef enum {
|
|||
|
||||
/** Mouse moved. */
|
||||
GHOSTTY_MOUSE_ACTION_MOTION = 2,
|
||||
GHOSTTY_MOUSE_ACTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyMouseAction;
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +44,7 @@ typedef enum {
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum GHOSTTY_ENUM_TYPED {
|
||||
GHOSTTY_MOUSE_BUTTON_UNKNOWN = 0,
|
||||
GHOSTTY_MOUSE_BUTTON_LEFT = 1,
|
||||
GHOSTTY_MOUSE_BUTTON_RIGHT = 2,
|
||||
|
|
@ -56,6 +57,7 @@ typedef enum {
|
|||
GHOSTTY_MOUSE_BUTTON_NINE = 9,
|
||||
GHOSTTY_MOUSE_BUTTON_TEN = 10,
|
||||
GHOSTTY_MOUSE_BUTTON_ELEVEN = 11,
|
||||
GHOSTTY_MOUSE_BUTTON_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyMouseButton;
|
||||
|
||||
/**
|
||||
|
|
@ -77,7 +79,7 @@ typedef struct {
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
GhosttyResult ghostty_mouse_event_new(const GhosttyAllocator *allocator,
|
||||
GHOSTTY_API GhosttyResult ghostty_mouse_event_new(const GhosttyAllocator *allocator,
|
||||
GhosttyMouseEvent *event);
|
||||
|
||||
/**
|
||||
|
|
@ -87,7 +89,7 @@ GhosttyResult ghostty_mouse_event_new(const GhosttyAllocator *allocator,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_event_free(GhosttyMouseEvent event);
|
||||
GHOSTTY_API void ghostty_mouse_event_free(GhosttyMouseEvent event);
|
||||
|
||||
/**
|
||||
* Set the event action.
|
||||
|
|
@ -97,7 +99,7 @@ void ghostty_mouse_event_free(GhosttyMouseEvent event);
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_event_set_action(GhosttyMouseEvent event,
|
||||
GHOSTTY_API void ghostty_mouse_event_set_action(GhosttyMouseEvent event,
|
||||
GhosttyMouseAction action);
|
||||
|
||||
/**
|
||||
|
|
@ -108,7 +110,7 @@ void ghostty_mouse_event_set_action(GhosttyMouseEvent event,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
GhosttyMouseAction ghostty_mouse_event_get_action(GhosttyMouseEvent event);
|
||||
GHOSTTY_API GhosttyMouseAction ghostty_mouse_event_get_action(GhosttyMouseEvent event);
|
||||
|
||||
/**
|
||||
* Set the event button.
|
||||
|
|
@ -122,7 +124,7 @@ GhosttyMouseAction ghostty_mouse_event_get_action(GhosttyMouseEvent event);
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_event_set_button(GhosttyMouseEvent event,
|
||||
GHOSTTY_API void ghostty_mouse_event_set_button(GhosttyMouseEvent event,
|
||||
GhosttyMouseButton button);
|
||||
|
||||
/**
|
||||
|
|
@ -134,7 +136,7 @@ void ghostty_mouse_event_set_button(GhosttyMouseEvent event,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_event_clear_button(GhosttyMouseEvent event);
|
||||
GHOSTTY_API void ghostty_mouse_event_clear_button(GhosttyMouseEvent event);
|
||||
|
||||
/**
|
||||
* Get the event button.
|
||||
|
|
@ -145,7 +147,7 @@ void ghostty_mouse_event_clear_button(GhosttyMouseEvent event);
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
bool ghostty_mouse_event_get_button(GhosttyMouseEvent event,
|
||||
GHOSTTY_API bool ghostty_mouse_event_get_button(GhosttyMouseEvent event,
|
||||
GhosttyMouseButton *out_button);
|
||||
|
||||
/**
|
||||
|
|
@ -156,7 +158,7 @@ bool ghostty_mouse_event_get_button(GhosttyMouseEvent event,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_event_set_mods(GhosttyMouseEvent event,
|
||||
GHOSTTY_API void ghostty_mouse_event_set_mods(GhosttyMouseEvent event,
|
||||
GhosttyMods mods);
|
||||
|
||||
/**
|
||||
|
|
@ -167,7 +169,7 @@ void ghostty_mouse_event_set_mods(GhosttyMouseEvent event,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
GhosttyMods ghostty_mouse_event_get_mods(GhosttyMouseEvent event);
|
||||
GHOSTTY_API GhosttyMods ghostty_mouse_event_get_mods(GhosttyMouseEvent event);
|
||||
|
||||
/**
|
||||
* Set the event position in surface-space pixels.
|
||||
|
|
@ -177,7 +179,7 @@ GhosttyMods ghostty_mouse_event_get_mods(GhosttyMouseEvent event);
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
void ghostty_mouse_event_set_position(GhosttyMouseEvent event,
|
||||
GHOSTTY_API void ghostty_mouse_event_set_position(GhosttyMouseEvent event,
|
||||
GhosttyMousePosition position);
|
||||
|
||||
/**
|
||||
|
|
@ -188,6 +190,6 @@ void ghostty_mouse_event_set_position(GhosttyMouseEvent event,
|
|||
*
|
||||
* @ingroup mouse
|
||||
*/
|
||||
GhosttyMousePosition ghostty_mouse_event_get_position(GhosttyMouseEvent event);
|
||||
GHOSTTY_API GhosttyMousePosition ghostty_mouse_event_get_position(GhosttyMouseEvent event);
|
||||
|
||||
#endif /* GHOSTTY_VT_MOUSE_EVENT_H */
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue