Merge remote-tracking branch 'upstream/main' into jacob/uucode
commit
4f2d80b08f
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- name: Setup Nix
|
- name: Setup Nix
|
||||||
uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ jobs:
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
# Important so that build number generation works
|
# Important so that build number generation works
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -168,7 +168,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ jobs:
|
||||||
- build-examples
|
- build-examples
|
||||||
- build-flatpak
|
- build-flatpak
|
||||||
- build-freebsd
|
- build-freebsd
|
||||||
|
- build-libghostty-vt
|
||||||
- build-linux
|
- build-linux
|
||||||
- build-linux-libghostty
|
- build-linux-libghostty
|
||||||
- build-nix
|
- build-nix
|
||||||
|
|
@ -79,7 +80,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -94,7 +95,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
dir: [zig-vt]
|
dir: [c-vt, zig-vt]
|
||||||
name: Example ${{ matrix.dir }}
|
name: Example ${{ matrix.dir }}
|
||||||
runs-on: namespace-profile-ghostty-sm
|
runs-on: namespace-profile-ghostty-sm
|
||||||
needs: test
|
needs: test
|
||||||
|
|
@ -113,7 +114,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -146,7 +147,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -180,7 +181,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -194,6 +195,48 @@ jobs:
|
||||||
zig build \
|
zig build \
|
||||||
-Dsnap
|
-Dsnap
|
||||||
|
|
||||||
|
build-libghostty-vt:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
[
|
||||||
|
aarch64-macos,
|
||||||
|
x86_64-macos,
|
||||||
|
aarch64-linux,
|
||||||
|
x86_64-linux,
|
||||||
|
x86_64-windows,
|
||||||
|
]
|
||||||
|
runs-on: namespace-profile-ghostty-sm
|
||||||
|
needs: test
|
||||||
|
env:
|
||||||
|
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
|
||||||
|
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
|
- name: Setup Cache
|
||||||
|
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/nix
|
||||||
|
/zig
|
||||||
|
|
||||||
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
|
with:
|
||||||
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
with:
|
||||||
|
name: ghostty
|
||||||
|
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
nix develop -c zig build lib-vt \
|
||||||
|
-Dtarget=${{ matrix.target }} \
|
||||||
|
-Dsimd=false
|
||||||
|
|
||||||
build-linux:
|
build-linux:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
@ -216,7 +259,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -245,7 +288,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -278,7 +321,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -324,7 +367,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -536,7 +579,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -578,7 +621,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -626,7 +669,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -661,7 +704,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -725,7 +768,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -752,7 +795,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -780,7 +823,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -807,7 +850,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -834,7 +877,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -861,7 +904,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -888,7 +931,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -922,7 +965,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -949,7 +992,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -986,7 +1029,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
@ -1074,7 +1117,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
# Install Nix and use that to run our tests so our environment matches exactly.
|
# Install Nix and use that to run our tests so our environment matches exactly.
|
||||||
- uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ jobs:
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
- name: Setup Nix
|
- name: Setup Nix
|
||||||
uses: cachix/install-nix-action@a809471b5c7c913aa67bec8f459a11a0decc3fce # v31.6.2
|
uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,7 @@
|
||||||
/po/he_IL.UTF-8.po @ghostty-org/he_IL
|
/po/he_IL.UTF-8.po @ghostty-org/he_IL
|
||||||
/po/it_IT.UTF-8.po @ghostty-org/it_IT
|
/po/it_IT.UTF-8.po @ghostty-org/it_IT
|
||||||
/po/zh_TW.UTF-8.po @ghostty-org/zh_TW
|
/po/zh_TW.UTF-8.po @ghostty-org/zh_TW
|
||||||
|
/po/hr_HR.UTF-8.po @ghostty-org/hr_HR
|
||||||
|
|
||||||
# Packaging - Snap
|
# Packaging - Snap
|
||||||
/snap/ @ghostty-org/snap
|
/snap/ @ghostty-org/snap
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Doxyfile 1.13.2
|
||||||
|
|
||||||
|
DOXYFILE_ENCODING = UTF-8
|
||||||
|
PROJECT_NAME = "libghostty"
|
||||||
|
INPUT = include/ghostty/vt.h
|
||||||
|
INPUT_ENCODING = UTF-8
|
||||||
|
RECURSIVE = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# HTML Output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
HTML_OUTPUT = zig-out/share/ghostty/doc/libghostty
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Man Output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
GENERATE_MAN = YES
|
||||||
|
MAN_OUTPUT = zig-out/share/man
|
||||||
|
MAN_EXTENSION = .3
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Other Output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
GENERATE_LATEX = NO
|
||||||
11
build.zig
11
build.zig
|
|
@ -31,6 +31,7 @@ pub fn build(b: *std.Build) !void {
|
||||||
|
|
||||||
// All our steps which we'll hook up later. The steps are shown
|
// All our steps which we'll hook up later. The steps are shown
|
||||||
// up here just so that they are more self-documenting.
|
// up here just so that they are more self-documenting.
|
||||||
|
const libvt_step = b.step("lib-vt", "Build libghostty-vt");
|
||||||
const run_step = b.step("run", "Run the app");
|
const run_step = b.step("run", "Run the app");
|
||||||
const run_valgrind_step = b.step(
|
const run_valgrind_step = b.step(
|
||||||
"run-valgrind",
|
"run-valgrind",
|
||||||
|
|
@ -86,7 +87,7 @@ pub fn build(b: *std.Build) !void {
|
||||||
check_step.dependOn(dist.install_step);
|
check_step.dependOn(dist.install_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
// libghostty
|
// libghostty (internal, big)
|
||||||
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
|
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
|
||||||
b,
|
b,
|
||||||
&deps,
|
&deps,
|
||||||
|
|
@ -96,6 +97,14 @@ pub fn build(b: *std.Build) !void {
|
||||||
&deps,
|
&deps,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// libghostty-vt
|
||||||
|
const libghostty_vt_shared = try buildpkg.GhosttyLibVt.initShared(
|
||||||
|
b,
|
||||||
|
&mod,
|
||||||
|
);
|
||||||
|
libghostty_vt_shared.install(libvt_step);
|
||||||
|
libghostty_vt_shared.install(b.getInstallStep());
|
||||||
|
|
||||||
// Helpgen
|
// Helpgen
|
||||||
if (config.emit_helpgen) deps.help_strings.install();
|
if (config.emit_helpgen) deps.help_strings.install();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Example: `ghostty-vt` C Program
|
||||||
|
|
||||||
|
This contains a simple example of how to use the `ghostty-vt` C library
|
||||||
|
with a C program.
|
||||||
|
|
||||||
|
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",
|
||||||
|
.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,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.fingerprint = 0x413a8529b1255f9a,
|
||||||
|
.minimum_zig_version = "0.14.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,11 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ghostty/vt.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
GhosttyOscParser parser;
|
||||||
|
if (ghostty_osc_new(NULL, &parser) != GHOSTTY_SUCCESS) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ghostty_osc_free(parser);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
/**
|
||||||
|
* @file vt.h
|
||||||
|
*
|
||||||
|
* libghostty-vt - Virtual terminal sequence parsing library
|
||||||
|
*
|
||||||
|
* This library provides functionality for parsing and handling terminal
|
||||||
|
* escape sequences as well as maintaining terminal state such as styles,
|
||||||
|
* cursor position, screen, scrollback, and more.
|
||||||
|
*
|
||||||
|
* WARNING: This is an incomplete, work-in-progress API. It is not yet
|
||||||
|
* stable and is definitely going to change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GHOSTTY_VT_H
|
||||||
|
#define GHOSTTY_VT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque handle to an OSC parser instance.
|
||||||
|
*
|
||||||
|
* This handle represents an OSC (Operating System Command) parser that can
|
||||||
|
* be used to parse the contents of OSC sequences. This isn't a full VT
|
||||||
|
* parser; it is only the OSC parser component. This is useful if you have
|
||||||
|
* a parser already and want to only extract and handle OSC sequences.
|
||||||
|
*/
|
||||||
|
typedef struct GhosttyOscParser *GhosttyOscParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result codes for libghostty-vt operations.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/** Operation completed successfully */
|
||||||
|
GHOSTTY_SUCCESS = 0,
|
||||||
|
/** Operation failed due to failed allocation */
|
||||||
|
GHOSTTY_OUT_OF_MEMORY = -1,
|
||||||
|
} GhosttyResult;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// Allocator Interface
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function table for custom memory allocator operations.
|
||||||
|
*
|
||||||
|
* This vtable defines the interface for a custom memory allocator. All
|
||||||
|
* function pointers must be valid and non-NULL.
|
||||||
|
*
|
||||||
|
* If you're not going to use a custom allocator, you can ignore all of
|
||||||
|
* this. All functions that take an allocator pointer allow NULL to use a
|
||||||
|
* default allocator.
|
||||||
|
*
|
||||||
|
* The interface is based on the Zig allocator interface. I'll say up front
|
||||||
|
* that it is easy to look at this interface and think "wow, this is really
|
||||||
|
* overcomplicated". The reason for this complexity is well thought out by
|
||||||
|
* the Zig folks, and it enables a diverse set of allocation strategies
|
||||||
|
* as shown by the Zig ecosystem. As a consolation, please note that many
|
||||||
|
* of the arguments are only needed for advanced use cases and can be
|
||||||
|
* safely ignored in simple implementations. For example, if you look at
|
||||||
|
* the Zig implementation of the libc allocator in `lib/std/heap.zig`
|
||||||
|
* (search for CAllocator), you'll see it is very simple.
|
||||||
|
*
|
||||||
|
* We chose to align with the Zig allocator interface because:
|
||||||
|
*
|
||||||
|
* 1. It is a proven interface that serves a wide variety of use cases
|
||||||
|
* in the real world via the Zig ecosystem. It's shown to work.
|
||||||
|
*
|
||||||
|
* 2. Our core implementation itself is Zig, and this lets us very
|
||||||
|
* cheaply and easily convert between C and Zig allocators.
|
||||||
|
*
|
||||||
|
* NOTE(mitchellh): In the future, we can have default implementations of
|
||||||
|
* resize/remap and allow those to be null.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Return a pointer to `len` bytes with specified `alignment`, or return
|
||||||
|
* `NULL` indicating the allocation failed.
|
||||||
|
*
|
||||||
|
* @param ctx The allocator context
|
||||||
|
* @param len Number of bytes to allocate
|
||||||
|
* @param alignment Required alignment for the allocation. Guaranteed to
|
||||||
|
* be a power of two between 1 and 16 inclusive.
|
||||||
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
||||||
|
* @return Pointer to allocated memory, or NULL if allocation failed
|
||||||
|
*/
|
||||||
|
void* (*alloc)(void *ctx, size_t len, uint8_t alignment, uintptr_t ret_addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to expand or shrink memory in place.
|
||||||
|
*
|
||||||
|
* `memory_len` must equal the length requested from the most recent
|
||||||
|
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
|
||||||
|
* equal the same value that was passed as the `alignment` parameter to
|
||||||
|
* the original `alloc` call.
|
||||||
|
*
|
||||||
|
* `new_len` must be greater than zero.
|
||||||
|
*
|
||||||
|
* @param ctx The allocator context
|
||||||
|
* @param memory Pointer to the memory block to resize
|
||||||
|
* @param memory_len Current size of the memory block
|
||||||
|
* @param alignment Alignment (must match original allocation)
|
||||||
|
* @param new_len New requested size
|
||||||
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
||||||
|
* @return true if resize was successful in-place, false if relocation would be required
|
||||||
|
*/
|
||||||
|
bool (*resize)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to expand or shrink memory, allowing relocation.
|
||||||
|
*
|
||||||
|
* `memory_len` must equal the length requested from the most recent
|
||||||
|
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
|
||||||
|
* equal the same value that was passed as the `alignment` parameter to
|
||||||
|
* the original `alloc` call.
|
||||||
|
*
|
||||||
|
* A non-`NULL` return value indicates the resize was successful. The
|
||||||
|
* allocation may have same address, or may have been relocated. In either
|
||||||
|
* case, the allocation now has size of `new_len`. A `NULL` return value
|
||||||
|
* indicates that the resize would be equivalent to allocating new memory,
|
||||||
|
* copying the bytes from the old memory, and then freeing the old memory.
|
||||||
|
* In such case, it is more efficient for the caller to perform the copy.
|
||||||
|
*
|
||||||
|
* `new_len` must be greater than zero.
|
||||||
|
*
|
||||||
|
* @param ctx The allocator context
|
||||||
|
* @param memory Pointer to the memory block to remap
|
||||||
|
* @param memory_len Current size of the memory block
|
||||||
|
* @param alignment Alignment (must match original allocation)
|
||||||
|
* @param new_len New requested size
|
||||||
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
||||||
|
* @return Pointer to resized memory (may be relocated), or NULL if manual copy is needed
|
||||||
|
*/
|
||||||
|
void* (*remap)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free and invalidate a region of memory.
|
||||||
|
*
|
||||||
|
* `memory_len` must equal the length requested from the most recent
|
||||||
|
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
|
||||||
|
* equal the same value that was passed as the `alignment` parameter to
|
||||||
|
* the original `alloc` call.
|
||||||
|
*
|
||||||
|
* @param ctx The allocator context
|
||||||
|
* @param memory Pointer to the memory block to free
|
||||||
|
* @param memory_len Size of the memory block
|
||||||
|
* @param alignment Alignment (must match original allocation)
|
||||||
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
||||||
|
*/
|
||||||
|
void (*free)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, uintptr_t ret_addr);
|
||||||
|
} GhosttyAllocatorVtable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom memory allocator.
|
||||||
|
*
|
||||||
|
* For functions that take an allocator pointer, a NULL pointer indicates
|
||||||
|
* that the default allocator should be used. The default allocator will
|
||||||
|
* be libc malloc/free if we're linking to libc. If libc isn't linked,
|
||||||
|
* a custom allocator is used (currently Zig's SMP allocator).
|
||||||
|
*
|
||||||
|
* Usage example:
|
||||||
|
* @code
|
||||||
|
* GhosttyAllocator allocator = {
|
||||||
|
* .vtable = &my_allocator_vtable,
|
||||||
|
* .ctx = my_allocator_state
|
||||||
|
* };
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Opaque context pointer passed to all vtable functions.
|
||||||
|
* This allows the allocator implementation to maintain state
|
||||||
|
* or reference external resources needed for memory management.
|
||||||
|
*/
|
||||||
|
void *ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to the allocator's vtable containing function pointers
|
||||||
|
* for memory operations (alloc, resize, remap, free).
|
||||||
|
*/
|
||||||
|
const GhosttyAllocatorVtable *vtable;
|
||||||
|
} GhosttyAllocator;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
// Functions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new OSC parser instance.
|
||||||
|
*
|
||||||
|
* Creates a new OSC (Operating System Command) parser using the provided
|
||||||
|
* allocator. The parser must be freed using ghostty_vt_osc_free() when
|
||||||
|
* no longer needed.
|
||||||
|
*
|
||||||
|
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
|
||||||
|
* @param parser Pointer to store the created parser handle
|
||||||
|
* @return GHOSTTY_SUCCESS on success, or an error code on failure
|
||||||
|
*/
|
||||||
|
GhosttyResult ghostty_osc_new(const GhosttyAllocator *allocator, GhosttyOscParser *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free an OSC parser instance.
|
||||||
|
*
|
||||||
|
* Releases all resources associated with the OSC parser. After this call,
|
||||||
|
* the parser handle becomes invalid and must not be used.
|
||||||
|
*
|
||||||
|
* @param parser The parser handle to free (may be NULL)
|
||||||
|
*/
|
||||||
|
void ghostty_osc_free(GhosttyOscParser parser);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GHOSTTY_VT_H */
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
lib,
|
lib,
|
||||||
stdenv,
|
stdenv,
|
||||||
bashInteractive,
|
bashInteractive,
|
||||||
|
doxygen,
|
||||||
nushell,
|
nushell,
|
||||||
appstream,
|
appstream,
|
||||||
flatpak-builder,
|
flatpak-builder,
|
||||||
|
|
@ -89,6 +90,7 @@ in
|
||||||
packages =
|
packages =
|
||||||
[
|
[
|
||||||
# For builds
|
# For builds
|
||||||
|
doxygen
|
||||||
jq
|
jq
|
||||||
llvmPackages_latest.llvm
|
llvmPackages_latest.llvm
|
||||||
minisign
|
minisign
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,321 @@
|
||||||
|
# Croatian translations for com.mitchellh.ghostty package
|
||||||
|
# Hrvatski prijevod za paket com.mitchellh.ghostty.
|
||||||
|
# Copyright (C) 2025 "Mitchell Hashimoto, Ghostty contributors"
|
||||||
|
# This file is distributed under the same license as the com.mitchellh.ghostty package.
|
||||||
|
# Filip <filipm7@protonmail.com>, 2025.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
|
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
|
||||||
|
"PO-Revision-Date: 2025-09-16 17:47+0200\n"
|
||||||
|
"Last-Translator: Filip7 <filipm7@protonmail.com>\n"
|
||||||
|
"Language-Team: Croatian <lokalizacija@linux.hr>\n"
|
||||||
|
"Language: hr\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||||
|
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:5
|
||||||
|
msgid "Change Terminal Title"
|
||||||
|
msgstr "Promijeni naslov terminala"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:6
|
||||||
|
msgid "Leave blank to restore the default title."
|
||||||
|
msgstr "Ostavi prazno za povratak zadanog naslova."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:44
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr "Otkaži"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:10
|
||||||
|
msgid "OK"
|
||||||
|
msgstr "OK"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
|
||||||
|
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
|
||||||
|
msgid "Configuration Errors"
|
||||||
|
msgstr "Greške u postavkama"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
|
||||||
|
msgid ""
|
||||||
|
"One or more configuration errors were found. Please review the errors below, "
|
||||||
|
"and either reload your configuration or ignore these errors."
|
||||||
|
msgstr ""
|
||||||
|
"Pronađene su jedna ili više grešaka u postavkama. Pregledaj niže navedene greške"
|
||||||
|
"te ponovno učitaj postavke ili zanemari ove greške."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
|
||||||
|
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
|
||||||
|
msgid "Ignore"
|
||||||
|
msgstr "Zanemari"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
|
||||||
|
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
|
||||||
|
msgid "Reload Configuration"
|
||||||
|
msgstr "Ponovno učitaj postavke"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
|
||||||
|
msgid "Split Up"
|
||||||
|
msgstr "Podijeli gore"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
|
||||||
|
msgid "Split Down"
|
||||||
|
msgstr "Podijeli dolje"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:16
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
|
||||||
|
msgid "Split Left"
|
||||||
|
msgstr "Podijeli lijevo"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:21
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
|
||||||
|
msgid "Split Right"
|
||||||
|
msgstr "Podijeli desno"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
|
||||||
|
msgid "Execute a command…"
|
||||||
|
msgstr "Izvrši naredbu…"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
|
||||||
|
msgid "Copy"
|
||||||
|
msgstr "Kopiraj"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
|
||||||
|
msgid "Paste"
|
||||||
|
msgstr "Zalijepi"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:18
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:73
|
||||||
|
msgid "Clear"
|
||||||
|
msgstr "Očisti"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:23
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:78
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr "Resetiraj"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:30
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:42
|
||||||
|
msgid "Split"
|
||||||
|
msgstr "Podijeli"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:33
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:45
|
||||||
|
msgid "Change Title…"
|
||||||
|
msgstr "Promijeni naslov…"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:59
|
||||||
|
msgid "Tab"
|
||||||
|
msgstr "Kartica"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
|
||||||
|
#: src/apprt/gtk/Window.zig:265
|
||||||
|
msgid "New Tab"
|
||||||
|
msgstr "Nova kartica"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:67
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:35
|
||||||
|
msgid "Close Tab"
|
||||||
|
msgstr "Zatvori karticu"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:73
|
||||||
|
msgid "Window"
|
||||||
|
msgstr "Prozor"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:76
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:18
|
||||||
|
msgid "New Window"
|
||||||
|
msgstr "Novi prozor"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:81
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:23
|
||||||
|
msgid "Close Window"
|
||||||
|
msgstr "Zatvori prozor"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:89
|
||||||
|
msgid "Config"
|
||||||
|
msgstr "Postavke"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
|
||||||
|
msgid "Open Configuration"
|
||||||
|
msgstr "Otvori postavke"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
|
||||||
|
msgid "Command Palette"
|
||||||
|
msgstr "Paleta naredbi"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
|
||||||
|
msgid "Terminal Inspector"
|
||||||
|
msgstr "Inspektor terminala"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
|
||||||
|
#: src/apprt/gtk/Window.zig:1038
|
||||||
|
msgid "About Ghostty"
|
||||||
|
msgstr "O Ghosttyju"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Izađi"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
|
||||||
|
msgid "Authorize Clipboard Access"
|
||||||
|
msgstr "Dopusti pristup međuspremniku"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
|
||||||
|
msgid ""
|
||||||
|
"An application is attempting to read from the clipboard. The current "
|
||||||
|
"clipboard contents are shown below."
|
||||||
|
msgstr ""
|
||||||
|
"Program pokušava pročitati vrijednost međuspremnika. Trenutna"
|
||||||
|
"vrijednost međuspremnika je prikazana niže."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
|
||||||
|
msgid "Deny"
|
||||||
|
msgstr "Odbij"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
|
||||||
|
msgid "Allow"
|
||||||
|
msgstr "Dopusti"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
|
||||||
|
msgid "Remember choice for this split"
|
||||||
|
msgstr "Zapamti izbor za ovu podjelu"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
|
||||||
|
msgid "Reload configuration to show this prompt again"
|
||||||
|
msgstr "Ponovno učitaj postavke za prikaz ovog upita"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
|
||||||
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
|
||||||
|
msgid ""
|
||||||
|
"An application is attempting to write to the clipboard. The current "
|
||||||
|
"clipboard contents are shown below."
|
||||||
|
msgstr ""
|
||||||
|
"Aplikacija pokušava pisati u međuspremnik. Trenutačna vrijednost "
|
||||||
|
"međuspremnika prikazana je niže."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
|
||||||
|
msgid "Warning: Potentially Unsafe Paste"
|
||||||
|
msgstr "Upozorenje: Potencijalno opasno lijepljenje"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
|
||||||
|
msgid ""
|
||||||
|
"Pasting this text into the terminal may be dangerous as it looks like some "
|
||||||
|
"commands may be executed."
|
||||||
|
msgstr ""
|
||||||
|
"Lijepljenje ovog teksta u terminal može biti opasno jer se čini da "
|
||||||
|
"neke naredbe mogu biti izvršene."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2531
|
||||||
|
msgid "Close"
|
||||||
|
msgstr "Zatvori"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:87
|
||||||
|
msgid "Quit Ghostty?"
|
||||||
|
msgstr "Zatvori Ghostty?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:88
|
||||||
|
msgid "Close Window?"
|
||||||
|
msgstr "Zatvori prozor?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:89
|
||||||
|
msgid "Close Tab?"
|
||||||
|
msgstr "Zatvori karticu?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:90
|
||||||
|
msgid "Close Split?"
|
||||||
|
msgstr "Zatvori podjelu?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:96
|
||||||
|
msgid "All terminal sessions will be terminated."
|
||||||
|
msgstr "Sve sesije terminala će biti prekinute."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:97
|
||||||
|
msgid "All terminal sessions in this window will be terminated."
|
||||||
|
msgstr "Sve sesije terminala u ovom prozoru će biti prekinute."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:98
|
||||||
|
msgid "All terminal sessions in this tab will be terminated."
|
||||||
|
msgstr "Sve sesije terminala u ovoj kartici će biti prekinute."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:99
|
||||||
|
msgid "The currently running process in this split will be terminated."
|
||||||
|
msgstr "Pokrenuti procesi u ovom odjeljku će biti prekinuti."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:1266
|
||||||
|
msgid "Copied to clipboard"
|
||||||
|
msgstr "Kopirano u međuspremnik"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:1268
|
||||||
|
msgid "Cleared clipboard"
|
||||||
|
msgstr "Očišćen međuspremnik"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2525
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr "Naredba je uspjela"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2527
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr "Naredba nije uspjela"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:216
|
||||||
|
msgid "Main Menu"
|
||||||
|
msgstr "Glavni izbornik"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:239
|
||||||
|
msgid "View Open Tabs"
|
||||||
|
msgstr "Pregledaj otvorene kartice"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:266
|
||||||
|
msgid "New Split"
|
||||||
|
msgstr "Nova podjela"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:329
|
||||||
|
msgid ""
|
||||||
|
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
|
||||||
|
msgstr ""
|
||||||
|
"⚠️ Pokrenuta je debug verzija Ghosttyja! Performanse će biti smanjene."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:775
|
||||||
|
msgid "Reloaded the configuration"
|
||||||
|
msgstr "Ponovno učitane postavke"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:1019
|
||||||
|
msgid "Ghostty Developers"
|
||||||
|
msgstr "Razvijatelji Ghosttyja"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/inspector.zig:144
|
||||||
|
msgid "Ghostty: Terminal Inspector"
|
||||||
|
msgstr "Ghostty: inspektor terminala"
|
||||||
|
|
@ -809,6 +809,10 @@ pub const Application = extern struct {
|
||||||
|
|
||||||
const writer = buf.writer(alloc);
|
const writer = buf.writer(alloc);
|
||||||
|
|
||||||
|
// Load standard css first as it can override some of the user configured styling.
|
||||||
|
try loadRuntimeCss414(config, &writer);
|
||||||
|
try loadRuntimeCss416(config, &writer);
|
||||||
|
|
||||||
const unfocused_fill: CoreConfig.Color = config.@"unfocused-split-fill" orelse config.background;
|
const unfocused_fill: CoreConfig.Color = config.@"unfocused-split-fill" orelse config.background;
|
||||||
|
|
||||||
try writer.print(
|
try writer.print(
|
||||||
|
|
@ -847,9 +851,6 @@ pub const Application = extern struct {
|
||||||
, .{ .font_family = font_family });
|
, .{ .font_family = font_family });
|
||||||
}
|
}
|
||||||
|
|
||||||
try loadRuntimeCss414(config, &writer);
|
|
||||||
try loadRuntimeCss416(config, &writer);
|
|
||||||
|
|
||||||
// ensure that we have a sentinel
|
// ensure that we have a sentinel
|
||||||
try writer.writeByte(0);
|
try writer.writeByte(0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
const GhosttyLibVt = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const RunStep = std.Build.Step.Run;
|
||||||
|
const Config = @import("Config.zig");
|
||||||
|
const GhosttyZig = @import("GhosttyZig.zig");
|
||||||
|
const SharedDeps = @import("SharedDeps.zig");
|
||||||
|
const LibtoolStep = @import("LibtoolStep.zig");
|
||||||
|
const LipoStep = @import("LipoStep.zig");
|
||||||
|
|
||||||
|
/// The step that generates the file.
|
||||||
|
step: *std.Build.Step,
|
||||||
|
|
||||||
|
/// The artifact result
|
||||||
|
artifact: *std.Build.Step.InstallArtifact,
|
||||||
|
|
||||||
|
/// The final library file
|
||||||
|
output: std.Build.LazyPath,
|
||||||
|
dsym: ?std.Build.LazyPath,
|
||||||
|
pkg_config: std.Build.LazyPath,
|
||||||
|
|
||||||
|
pub fn initShared(
|
||||||
|
b: *std.Build,
|
||||||
|
zig: *const GhosttyZig,
|
||||||
|
) !GhosttyLibVt {
|
||||||
|
const target = zig.vt.resolved_target.?;
|
||||||
|
const lib = b.addSharedLibrary(.{
|
||||||
|
.name = "ghostty-vt",
|
||||||
|
.root_module = zig.vt,
|
||||||
|
});
|
||||||
|
lib.installHeader(
|
||||||
|
b.path("include/ghostty/vt.h"),
|
||||||
|
"ghostty/vt.h",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get our debug symbols
|
||||||
|
const dsymutil: ?std.Build.LazyPath = dsymutil: {
|
||||||
|
if (!target.result.os.tag.isDarwin()) {
|
||||||
|
break :dsymutil null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dsymutil = RunStep.create(b, "dsymutil");
|
||||||
|
dsymutil.addArgs(&.{"dsymutil"});
|
||||||
|
dsymutil.addFileArg(lib.getEmittedBin());
|
||||||
|
dsymutil.addArgs(&.{"-o"});
|
||||||
|
const output = dsymutil.addOutputFileArg("libghostty-vt.dSYM");
|
||||||
|
break :dsymutil output;
|
||||||
|
};
|
||||||
|
|
||||||
|
// pkg-config
|
||||||
|
const pc: std.Build.LazyPath = pc: {
|
||||||
|
const wf = b.addWriteFiles();
|
||||||
|
break :pc wf.add("libghostty-vt.pc", b.fmt(
|
||||||
|
\\prefix={s}
|
||||||
|
\\includedir=${{prefix}}/include
|
||||||
|
\\libdir=${{prefix}}/lib
|
||||||
|
\\
|
||||||
|
\\Name: libghostty-vt
|
||||||
|
\\URL: https://github.com/ghostty-org/ghostty
|
||||||
|
\\Description: Ghostty VT library
|
||||||
|
\\Version: 0.1.0
|
||||||
|
\\Cflags: -I${{includedir}}
|
||||||
|
\\Libs: -L${{libdir}} -lghostty-vt
|
||||||
|
, .{b.install_prefix}));
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.step = &lib.step,
|
||||||
|
.artifact = b.addInstallArtifact(lib, .{}),
|
||||||
|
.output = lib.getEmittedBin(),
|
||||||
|
.dsym = dsymutil,
|
||||||
|
.pkg_config = pc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install(
|
||||||
|
self: *const GhosttyLibVt,
|
||||||
|
step: *std.Build.Step,
|
||||||
|
) void {
|
||||||
|
const b = step.owner;
|
||||||
|
step.dependOn(&self.artifact.step);
|
||||||
|
step.dependOn(&b.addInstallFileWithDir(
|
||||||
|
self.pkg_config,
|
||||||
|
.prefix,
|
||||||
|
"share/pkgconfig/libghostty-vt.pc",
|
||||||
|
).step);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
const SharedDeps = @This();
|
const SharedDeps = @This();
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const Config = @import("Config.zig");
|
const Config = @import("Config.zig");
|
||||||
const HelpStrings = @import("HelpStrings.zig");
|
const HelpStrings = @import("HelpStrings.zig");
|
||||||
const MetallibStep = @import("MetallibStep.zig");
|
const MetallibStep = @import("MetallibStep.zig");
|
||||||
|
|
@ -114,6 +116,19 @@ pub fn add(
|
||||||
var static_libs = LazyPathList.init(b.allocator);
|
var static_libs = LazyPathList.init(b.allocator);
|
||||||
errdefer static_libs.deinit();
|
errdefer static_libs.deinit();
|
||||||
|
|
||||||
|
// WARNING: This is a hack!
|
||||||
|
// If we're cross-compiling to Darwin then we don't add any deps.
|
||||||
|
// We don't support cross-compiling to Darwin but due to the way
|
||||||
|
// lazy dependencies work with Zig, we call this function. So we just
|
||||||
|
// bail. The build will fail but the build would've failed anyways.
|
||||||
|
// And this lets other non-platform-specific targets like `lib-vt`
|
||||||
|
// cross-compile properly.
|
||||||
|
if (!builtin.target.os.tag.isDarwin() and
|
||||||
|
self.config.target.result.os.tag.isDarwin())
|
||||||
|
{
|
||||||
|
return static_libs;
|
||||||
|
}
|
||||||
|
|
||||||
// Every exe gets build options populated
|
// Every exe gets build options populated
|
||||||
step.root_module.addOptions("build_options", self.options);
|
step.root_module.addOptions("build_options", self.options);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ pub const GhosttyDocs = @import("GhosttyDocs.zig");
|
||||||
pub const GhosttyExe = @import("GhosttyExe.zig");
|
pub const GhosttyExe = @import("GhosttyExe.zig");
|
||||||
pub const GhosttyFrameData = @import("GhosttyFrameData.zig");
|
pub const GhosttyFrameData = @import("GhosttyFrameData.zig");
|
||||||
pub const GhosttyLib = @import("GhosttyLib.zig");
|
pub const GhosttyLib = @import("GhosttyLib.zig");
|
||||||
|
pub const GhosttyLibVt = @import("GhosttyLibVt.zig");
|
||||||
pub const GhosttyResources = @import("GhosttyResources.zig");
|
pub const GhosttyResources = @import("GhosttyResources.zig");
|
||||||
pub const GhosttyI18n = @import("GhosttyI18n.zig");
|
pub const GhosttyI18n = @import("GhosttyI18n.zig");
|
||||||
pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig");
|
pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,424 @@
|
||||||
|
//! Iterator to split a string into fields by commas, taking into account
|
||||||
|
//! quotes and escapes.
|
||||||
|
//!
|
||||||
|
//! Supports the same escapes as in Zig literal strings.
|
||||||
|
//!
|
||||||
|
//! Quotes must begin and end with a double quote (`"`). It is an error to not
|
||||||
|
//! end a quote that was begun. To include a double quote inside a quote (or to
|
||||||
|
//! not have a double quote start a quoted section) escape it with a backslash.
|
||||||
|
//!
|
||||||
|
//! Single quotes (`'`) are not special, they do not begin a quoted block.
|
||||||
|
//!
|
||||||
|
//! Zig multiline string literals are NOT supported.
|
||||||
|
//!
|
||||||
|
//! Quotes and escapes are not stripped or decoded, that must be handled as a
|
||||||
|
//! separate step!
|
||||||
|
const CommaSplitter = @This();
|
||||||
|
|
||||||
|
pub const Error = error{
|
||||||
|
UnclosedQuote,
|
||||||
|
UnfinishedEscape,
|
||||||
|
IllegalEscape,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// the string that we are splitting
|
||||||
|
str: []const u8,
|
||||||
|
/// how much of the string has been consumed so far
|
||||||
|
index: usize,
|
||||||
|
|
||||||
|
/// initialize a splitter with the given string
|
||||||
|
pub fn init(str: []const u8) CommaSplitter {
|
||||||
|
return .{
|
||||||
|
.str = str,
|
||||||
|
.index = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the next field, null if no more fields
|
||||||
|
pub fn next(self: *CommaSplitter) Error!?[]const u8 {
|
||||||
|
if (self.index >= self.str.len) return null;
|
||||||
|
|
||||||
|
// where the current field starts
|
||||||
|
const start = self.index;
|
||||||
|
// state of state machine
|
||||||
|
const State = enum {
|
||||||
|
normal,
|
||||||
|
quoted,
|
||||||
|
escape,
|
||||||
|
hexescape,
|
||||||
|
unicodeescape,
|
||||||
|
};
|
||||||
|
// keep track of the state to return to when done processing an escape
|
||||||
|
// sequence.
|
||||||
|
var last: State = .normal;
|
||||||
|
// used to count number of digits seen in a hex escape
|
||||||
|
var hexescape_digits: usize = 0;
|
||||||
|
// sub-state of parsing hex escapes
|
||||||
|
var unicodeescape_state: enum {
|
||||||
|
start,
|
||||||
|
digits,
|
||||||
|
} = .start;
|
||||||
|
// number of digits in a unicode escape seen so far
|
||||||
|
var unicodeescape_digits: usize = 0;
|
||||||
|
// accumulator for value of unicode escape
|
||||||
|
var unicodeescape_value: usize = 0;
|
||||||
|
|
||||||
|
loop: switch (State.normal) {
|
||||||
|
.normal => {
|
||||||
|
if (self.index >= self.str.len) return self.str[start..];
|
||||||
|
switch (self.str[self.index]) {
|
||||||
|
',' => {
|
||||||
|
self.index += 1;
|
||||||
|
return self.str[start .. self.index - 1];
|
||||||
|
},
|
||||||
|
'"' => {
|
||||||
|
self.index += 1;
|
||||||
|
continue :loop .quoted;
|
||||||
|
},
|
||||||
|
'\\' => {
|
||||||
|
self.index += 1;
|
||||||
|
last = .normal;
|
||||||
|
continue :loop .escape;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
self.index += 1;
|
||||||
|
continue :loop .normal;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.quoted => {
|
||||||
|
if (self.index >= self.str.len) return error.UnclosedQuote;
|
||||||
|
switch (self.str[self.index]) {
|
||||||
|
'"' => {
|
||||||
|
self.index += 1;
|
||||||
|
continue :loop .normal;
|
||||||
|
},
|
||||||
|
'\\' => {
|
||||||
|
self.index += 1;
|
||||||
|
last = .quoted;
|
||||||
|
continue :loop .escape;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
self.index += 1;
|
||||||
|
continue :loop .quoted;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.escape => {
|
||||||
|
if (self.index >= self.str.len) return error.UnfinishedEscape;
|
||||||
|
switch (self.str[self.index]) {
|
||||||
|
'n', 'r', 't', '\\', '\'', '"' => {
|
||||||
|
self.index += 1;
|
||||||
|
continue :loop last;
|
||||||
|
},
|
||||||
|
'x' => {
|
||||||
|
self.index += 1;
|
||||||
|
hexescape_digits = 0;
|
||||||
|
continue :loop .hexescape;
|
||||||
|
},
|
||||||
|
'u' => {
|
||||||
|
self.index += 1;
|
||||||
|
unicodeescape_state = .start;
|
||||||
|
unicodeescape_digits = 0;
|
||||||
|
unicodeescape_value = 0;
|
||||||
|
continue :loop .unicodeescape;
|
||||||
|
},
|
||||||
|
else => return error.IllegalEscape,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.hexescape => {
|
||||||
|
if (self.index >= self.str.len) return error.UnfinishedEscape;
|
||||||
|
switch (self.str[self.index]) {
|
||||||
|
'0'...'9', 'a'...'f', 'A'...'F' => {
|
||||||
|
self.index += 1;
|
||||||
|
hexescape_digits += 1;
|
||||||
|
if (hexescape_digits == 2) continue :loop last;
|
||||||
|
continue :loop .hexescape;
|
||||||
|
},
|
||||||
|
else => return error.IllegalEscape,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.unicodeescape => {
|
||||||
|
if (self.index >= self.str.len) return error.UnfinishedEscape;
|
||||||
|
switch (unicodeescape_state) {
|
||||||
|
.start => {
|
||||||
|
switch (self.str[self.index]) {
|
||||||
|
'{' => {
|
||||||
|
self.index += 1;
|
||||||
|
unicodeescape_value = 0;
|
||||||
|
unicodeescape_state = .digits;
|
||||||
|
continue :loop .unicodeescape;
|
||||||
|
},
|
||||||
|
else => return error.IllegalEscape,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.digits => {
|
||||||
|
switch (self.str[self.index]) {
|
||||||
|
'}' => {
|
||||||
|
self.index += 1;
|
||||||
|
if (unicodeescape_digits == 0) return error.IllegalEscape;
|
||||||
|
continue :loop last;
|
||||||
|
},
|
||||||
|
'0'...'9' => |d| {
|
||||||
|
self.index += 1;
|
||||||
|
unicodeescape_digits += 1;
|
||||||
|
unicodeescape_value <<= 4;
|
||||||
|
unicodeescape_value += d - '0';
|
||||||
|
},
|
||||||
|
'a'...'f' => |d| {
|
||||||
|
self.index += 1;
|
||||||
|
unicodeescape_digits += 1;
|
||||||
|
unicodeescape_value <<= 4;
|
||||||
|
unicodeescape_value += d - 'a';
|
||||||
|
},
|
||||||
|
'A'...'F' => |d| {
|
||||||
|
self.index += 1;
|
||||||
|
unicodeescape_digits += 1;
|
||||||
|
unicodeescape_value <<= 4;
|
||||||
|
unicodeescape_value += d - 'A';
|
||||||
|
},
|
||||||
|
else => return error.IllegalEscape,
|
||||||
|
}
|
||||||
|
if (unicodeescape_value > 0x10ffff) return error.IllegalEscape;
|
||||||
|
continue :loop .unicodeescape;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return any remaining string data, whether it has a comma or not.
|
||||||
|
pub fn rest(self: *CommaSplitter) ?[]const u8 {
|
||||||
|
if (self.index >= self.str.len) return null;
|
||||||
|
defer self.index = self.str.len;
|
||||||
|
return self.str[self.index..];
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 1" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("a,b,c");
|
||||||
|
try testing.expectEqualStrings("a", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("b", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("c", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 2" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("");
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 3" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("a");
|
||||||
|
try testing.expectEqualStrings("a", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 4" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\x5a");
|
||||||
|
try testing.expectEqualStrings("\\x5a", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 5" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("'a',b");
|
||||||
|
try testing.expectEqualStrings("'a'", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("b", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 6" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("'a,b',c");
|
||||||
|
try testing.expectEqualStrings("'a", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("b'", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("c", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 7" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\"a,b\",c");
|
||||||
|
try testing.expectEqualStrings("\"a,b\"", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("c", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 8" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init(" a , b ");
|
||||||
|
try testing.expectEqualStrings(" a ", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings(" b ", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 9" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\x");
|
||||||
|
try testing.expectError(error.UnfinishedEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 10" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\x5");
|
||||||
|
try testing.expectError(error.UnfinishedEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 11" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\u");
|
||||||
|
try testing.expectError(error.UnfinishedEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 12" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\u{");
|
||||||
|
try testing.expectError(error.UnfinishedEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 13" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\u{}");
|
||||||
|
try testing.expectError(error.IllegalEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 14" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\u{h1}");
|
||||||
|
try testing.expectError(error.IllegalEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 15" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\u{10ffff}");
|
||||||
|
try testing.expectEqualStrings("\\u{10ffff}", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 16" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\u{110000}");
|
||||||
|
try testing.expectError(error.IllegalEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 17" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\d");
|
||||||
|
try testing.expectError(error.IllegalEscape, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 18" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\\n\\r\\t\\\"\\'\\\\");
|
||||||
|
try testing.expectEqualStrings("\\n\\r\\t\\\"\\'\\\\", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 19" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\"abc'def'ghi\"");
|
||||||
|
try testing.expectEqualStrings("\"abc'def'ghi\"", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 20" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("\",\",abc");
|
||||||
|
try testing.expectEqualStrings("\",\"", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("abc", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 21" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("'a','b', 'c'");
|
||||||
|
try testing.expectEqualStrings("'a'", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("'b'", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings(" 'c'", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 22" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("abc\"def");
|
||||||
|
try testing.expectError(error.UnclosedQuote, s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 23" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("title:\"Focus Split: Up\",description:\"Focus the split above, if it exists.\",action:goto_split:up");
|
||||||
|
try testing.expectEqualStrings("title:\"Focus Split: Up\"", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("description:\"Focus the split above, if it exists.\"", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("action:goto_split:up", (try s.next()).?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 24" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("a,b,c,def");
|
||||||
|
try testing.expectEqualStrings("a", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("b", (try s.next()).?);
|
||||||
|
try testing.expectEqualStrings("c,def", s.rest().?);
|
||||||
|
try testing.expect(null == try s.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "splitter 25" {
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var s: CommaSplitter = .init("a,\\u{10,df}");
|
||||||
|
try testing.expectEqualStrings("a", (try s.next()).?);
|
||||||
|
try testing.expectError(error.IllegalEscape, s.next());
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ const diags = @import("diagnostics.zig");
|
||||||
const internal_os = @import("../os/main.zig");
|
const internal_os = @import("../os/main.zig");
|
||||||
const Diagnostic = diags.Diagnostic;
|
const Diagnostic = diags.Diagnostic;
|
||||||
const DiagnosticList = diags.DiagnosticList;
|
const DiagnosticList = diags.DiagnosticList;
|
||||||
|
const CommaSplitter = @import("CommaSplitter.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.cli);
|
const log = std.log.scoped(.cli);
|
||||||
|
|
||||||
|
|
@ -527,24 +528,31 @@ pub fn parseAutoStruct(comptime T: type, alloc: Allocator, v: []const u8) !T {
|
||||||
const FieldSet = std.StaticBitSet(info.fields.len);
|
const FieldSet = std.StaticBitSet(info.fields.len);
|
||||||
var fields_set: FieldSet = .initEmpty();
|
var fields_set: FieldSet = .initEmpty();
|
||||||
|
|
||||||
// We split each value by ","
|
// We split each value by "," allowing for quoting and escaping.
|
||||||
var iter = std.mem.splitSequence(u8, v, ",");
|
var iter: CommaSplitter = .init(v);
|
||||||
loop: while (iter.next()) |entry| {
|
loop: while (try iter.next()) |entry| {
|
||||||
// Find the key/value, trimming whitespace. The value may be quoted
|
// Find the key/value, trimming whitespace. The value may be quoted
|
||||||
// which we strip the quotes from.
|
// which we strip the quotes from.
|
||||||
const idx = mem.indexOf(u8, entry, ":") orelse return error.InvalidValue;
|
const idx = mem.indexOf(u8, entry, ":") orelse return error.InvalidValue;
|
||||||
const key = std.mem.trim(u8, entry[0..idx], whitespace);
|
const key = std.mem.trim(u8, entry[0..idx], whitespace);
|
||||||
|
|
||||||
|
// used if we need to decode a double-quoted string.
|
||||||
|
var buf: std.ArrayListUnmanaged(u8) = .empty;
|
||||||
|
defer buf.deinit(alloc);
|
||||||
|
|
||||||
const value = value: {
|
const value = value: {
|
||||||
var value = std.mem.trim(u8, entry[idx + 1 ..], whitespace);
|
const value = std.mem.trim(u8, entry[idx + 1 ..], whitespace);
|
||||||
|
|
||||||
// Detect a quoted string.
|
// Detect a quoted string.
|
||||||
if (value.len >= 2 and
|
if (value.len >= 2 and
|
||||||
value[0] == '"' and
|
value[0] == '"' and
|
||||||
value[value.len - 1] == '"')
|
value[value.len - 1] == '"')
|
||||||
{
|
{
|
||||||
// Trim quotes since our CLI args processor expects
|
// Decode a double-quoted string as a Zig string literal.
|
||||||
// quotes to already be gone.
|
const writer = buf.writer(alloc);
|
||||||
value = value[1 .. value.len - 1];
|
const parsed = try std.zig.string_literal.parseWrite(writer, value);
|
||||||
|
if (parsed == .failure) return error.InvalidValue;
|
||||||
|
break :value buf.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
break :value value;
|
break :value value;
|
||||||
|
|
|
||||||
|
|
@ -2363,9 +2363,21 @@ keybind: Keybinds = .{},
|
||||||
/// (`:`), and then the specified value. The syntax for actions is identical
|
/// (`:`), and then the specified value. The syntax for actions is identical
|
||||||
/// to the one for keybind actions. Whitespace in between fields is ignored.
|
/// to the one for keybind actions. Whitespace in between fields is ignored.
|
||||||
///
|
///
|
||||||
|
/// If you need to embed commas or any other special characters in the values,
|
||||||
|
/// enclose the value in double quotes and it will be interpreted as a Zig
|
||||||
|
/// string literal. This is also useful for including whitespace at the
|
||||||
|
/// beginning or the end of a value. See the
|
||||||
|
/// [Zig documentation](https://ziglang.org/documentation/master/#Escape-Sequences)
|
||||||
|
/// for more information on string literals. Note that multiline string literals
|
||||||
|
/// are not supported.
|
||||||
|
///
|
||||||
|
/// Double quotes can not be used around the field names.
|
||||||
|
///
|
||||||
/// ```ini
|
/// ```ini
|
||||||
/// command-palette-entry = title:Reset Font Style, action:csi:0m
|
/// command-palette-entry = title:Reset Font Style, action:csi:0m
|
||||||
/// command-palette-entry = title:Crash on Main Thread,description:Causes a crash on the main (UI) thread.,action:crash:main
|
/// command-palette-entry = title:Crash on Main Thread,description:Causes a crash on the main (UI) thread.,action:crash:main
|
||||||
|
/// command-palette-entry = title:Focus Split: Right,description:"Focus the split to the right, if it exists.",action:goto_split:right
|
||||||
|
/// command-palette-entry = title:"Ghostty",description:"Add a little Ghostty to your terminal.",action:"text:\xf0\x9f\x91\xbb"
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// By default, the command palette is preloaded with most actions that might
|
/// By default, the command palette is preloaded with most actions that might
|
||||||
|
|
@ -3351,7 +3363,7 @@ pub fn loadOptionalFile(
|
||||||
fn writeConfigTemplate(path: []const u8) !void {
|
fn writeConfigTemplate(path: []const u8) !void {
|
||||||
log.info("creating template config file: path={s}", .{path});
|
log.info("creating template config file: path={s}", .{path});
|
||||||
if (std.fs.path.dirname(path)) |dir_path| {
|
if (std.fs.path.dirname(path)) |dir_path| {
|
||||||
try std.fs.makeDirAbsolute(dir_path);
|
try std.fs.cwd().makePath(dir_path);
|
||||||
}
|
}
|
||||||
const file = try std.fs.createFileAbsolute(path, .{});
|
const file = try std.fs.createFileAbsolute(path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
@ -7029,18 +7041,24 @@ pub const RepeatableCommand = struct {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf: [4096]u8 = undefined;
|
|
||||||
for (self.value.items) |item| {
|
for (self.value.items) |item| {
|
||||||
const str = if (item.description.len > 0) std.fmt.bufPrint(
|
var buf: [4096]u8 = undefined;
|
||||||
&buf,
|
var fbs = std.io.fixedBufferStream(&buf);
|
||||||
"title:{s},description:{s},action:{}",
|
var writer = fbs.writer();
|
||||||
.{ item.title, item.description, item.action },
|
|
||||||
) else std.fmt.bufPrint(
|
writer.writeAll("title:\"") catch return error.OutOfMemory;
|
||||||
&buf,
|
std.zig.stringEscape(item.title, "", .{}, writer) catch return error.OutOfMemory;
|
||||||
"title:{s},action:{}",
|
writer.writeAll("\"") catch return error.OutOfMemory;
|
||||||
.{ item.title, item.action },
|
|
||||||
);
|
if (item.description.len > 0) {
|
||||||
try formatter.formatEntry([]const u8, str catch return error.OutOfMemory);
|
writer.writeAll(",description:\"") catch return error.OutOfMemory;
|
||||||
|
std.zig.stringEscape(item.description, "", .{}, writer) catch return error.OutOfMemory;
|
||||||
|
writer.writeAll("\"") catch return error.OutOfMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.print(",action:\"{}\"", .{item.action}) catch return error.OutOfMemory;
|
||||||
|
|
||||||
|
try formatter.formatEntry([]const u8, fbs.getWritten());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7106,7 +7124,7 @@ pub const RepeatableCommand = struct {
|
||||||
var list: RepeatableCommand = .{};
|
var list: RepeatableCommand = .{};
|
||||||
try list.parseCLI(alloc, "title:Bobr, action:text:Bober");
|
try list.parseCLI(alloc, "title:Bobr, action:text:Bober");
|
||||||
try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
|
try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
|
||||||
try std.testing.expectEqualSlices(u8, "a = title:Bobr,action:text:Bober\n", buf.items);
|
try std.testing.expectEqualSlices(u8, "a = title:\"Bobr\",action:\"text:Bober\"\n", buf.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "RepeatableCommand formatConfig multiple items" {
|
test "RepeatableCommand formatConfig multiple items" {
|
||||||
|
|
@ -7122,7 +7140,40 @@ pub const RepeatableCommand = struct {
|
||||||
try list.parseCLI(alloc, "title:Bobr, action:text:kurwa");
|
try list.parseCLI(alloc, "title:Bobr, action:text:kurwa");
|
||||||
try list.parseCLI(alloc, "title:Ja, description: pierdole, action:text:jakie bydle");
|
try list.parseCLI(alloc, "title:Ja, description: pierdole, action:text:jakie bydle");
|
||||||
try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
|
try list.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
|
||||||
try std.testing.expectEqualSlices(u8, "a = title:Bobr,action:text:kurwa\na = title:Ja,description:pierdole,action:text:jakie bydle\n", buf.items);
|
try std.testing.expectEqualSlices(u8, "a = title:\"Bobr\",action:\"text:kurwa\"\na = title:\"Ja\",description:\"pierdole\",action:\"text:jakie bydle\"\n", buf.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "RepeatableCommand parseCLI commas" {
|
||||||
|
const testing = std.testing;
|
||||||
|
var buf = std.ArrayList(u8).init(testing.allocator);
|
||||||
|
defer buf.deinit();
|
||||||
|
|
||||||
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
|
{
|
||||||
|
var list: RepeatableCommand = .{};
|
||||||
|
try list.parseCLI(alloc, "title:\"Bo,br\",action:\"text:kur,wa\"");
|
||||||
|
try testing.expectEqual(@as(usize, 1), list.value.items.len);
|
||||||
|
|
||||||
|
const item = list.value.items[0];
|
||||||
|
try testing.expectEqualStrings("Bo,br", item.title);
|
||||||
|
try testing.expectEqualStrings("", item.description);
|
||||||
|
try testing.expect(item.action == .text);
|
||||||
|
try testing.expectEqualStrings("kur,wa", item.action.text);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var list: RepeatableCommand = .{};
|
||||||
|
try list.parseCLI(alloc, "title:\"Bo,br\",description:\"abc,def\",action:text:kurwa");
|
||||||
|
try testing.expectEqual(@as(usize, 1), list.value.items.len);
|
||||||
|
|
||||||
|
const item = list.value.items[0];
|
||||||
|
try testing.expectEqualStrings("Bo,br", item.title);
|
||||||
|
try testing.expectEqualStrings("abc,def", item.description);
|
||||||
|
try testing.expect(item.action == .text);
|
||||||
|
try testing.expectEqualStrings("kurwa", item.action.text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1213,7 +1213,7 @@ pub const Action = union(enum) {
|
||||||
const value_info = @typeInfo(Value);
|
const value_info = @typeInfo(Value);
|
||||||
switch (Value) {
|
switch (Value) {
|
||||||
void => {},
|
void => {},
|
||||||
[]const u8 => try writer.print("{s}", .{value}),
|
[]const u8 => try std.zig.stringEscape(value, "", .{}, writer),
|
||||||
else => switch (value_info) {
|
else => switch (value_info) {
|
||||||
.@"enum" => try writer.print("{s}", .{@tagName(value)}),
|
.@"enum" => try writer.print("{s}", .{@tagName(value)}),
|
||||||
.float => try writer.print("{d}", .{value}),
|
.float => try writer.print("{d}", .{value}),
|
||||||
|
|
@ -3227,3 +3227,18 @@ test "parse: set_font_size" {
|
||||||
try testing.expectEqual(13.5, binding.action.set_font_size);
|
try testing.expectEqual(13.5, binding.action.set_font_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "action: format" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
const a: Action = .{ .text = "👻" };
|
||||||
|
|
||||||
|
var buf: std.ArrayListUnmanaged(u8) = .empty;
|
||||||
|
defer buf.deinit(alloc);
|
||||||
|
|
||||||
|
const writer = buf.writer(alloc);
|
||||||
|
try a.format("", .{}, writer);
|
||||||
|
|
||||||
|
try testing.expectEqualStrings("text:\\xf0\\x9f\\x91\\xbb", buf.items);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -472,13 +472,18 @@ fn actionCommands(action: Action.Key) []const Command {
|
||||||
.description = "Quit the application.",
|
.description = "Quit the application.",
|
||||||
}},
|
}},
|
||||||
|
|
||||||
|
.text => comptime &.{.{
|
||||||
|
.action = .{ .text = "👻" },
|
||||||
|
.title = "Ghostty",
|
||||||
|
.description = "Put a little Ghostty in your terminal.",
|
||||||
|
}},
|
||||||
|
|
||||||
// No commands because they're parameterized and there
|
// No commands because they're parameterized and there
|
||||||
// aren't obvious values users would use. It is possible that
|
// aren't obvious values users would use. It is possible that
|
||||||
// these may have commands in the future if there are very
|
// these may have commands in the future if there are very
|
||||||
// common values that users tend to use.
|
// common values that users tend to use.
|
||||||
.csi,
|
.csi,
|
||||||
.esc,
|
.esc,
|
||||||
.text,
|
|
||||||
.cursor_key,
|
.cursor_key,
|
||||||
.set_font_size,
|
.set_font_size,
|
||||||
.scroll_page_fractional,
|
.scroll_page_fractional,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
/// Useful alias since they're required to create Zig allocators
|
||||||
|
pub const ZigVTable = std.mem.Allocator.VTable;
|
||||||
|
|
||||||
|
/// The VTable required by the C interface.
|
||||||
|
/// C: GhosttyAllocatorVtable
|
||||||
|
pub const VTable = extern struct {
|
||||||
|
alloc: *const fn (*anyopaque, len: usize, alignment: u8, ret_addr: usize) callconv(.c) ?[*]u8,
|
||||||
|
resize: *const fn (*anyopaque, memory: [*]u8, memory_len: usize, alignment: u8, new_len: usize, ret_addr: usize) callconv(.c) bool,
|
||||||
|
remap: *const fn (*anyopaque, memory: [*]u8, memory_len: usize, alignment: u8, new_len: usize, ret_addr: usize) callconv(.c) ?[*]u8,
|
||||||
|
free: *const fn (*anyopaque, memory: [*]u8, memory_len: usize, alignment: u8, ret_addr: usize) callconv(.c) void,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns an allocator to use for the given possibly-null C allocator,
|
||||||
|
/// ensuring some allocator is always returned.
|
||||||
|
pub fn default(c_alloc_: ?*const Allocator) std.mem.Allocator {
|
||||||
|
// If we're given an allocator, use it.
|
||||||
|
if (c_alloc_) |c_alloc| return c_alloc.zig();
|
||||||
|
|
||||||
|
// If we have libc, use that. We prefer libc if we have it because
|
||||||
|
// its generally fast but also lets the embedder easily override
|
||||||
|
// malloc/free with custom allocators like mimalloc or something.
|
||||||
|
if (comptime builtin.link_libc) return std.heap.c_allocator;
|
||||||
|
|
||||||
|
// No libc, use the preferred allocator for releases which is the
|
||||||
|
// Zig SMP allocator.
|
||||||
|
return std.heap.smp_allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Allocator interface for custom memory allocation strategies
|
||||||
|
/// within C libghostty APIs.
|
||||||
|
///
|
||||||
|
/// This -- purposely -- matches the Zig allocator interface. We do this
|
||||||
|
/// for two reasons: (1) Zig's allocator interface is well proven in
|
||||||
|
/// the real world to be flexible and useful, and (2) it allows us to
|
||||||
|
/// easily convert C allocators to Zig allocators and vice versa, since
|
||||||
|
/// we're written in Zig.
|
||||||
|
///
|
||||||
|
/// C: GhosttyAllocator
|
||||||
|
pub const Allocator = extern struct {
|
||||||
|
ctx: *anyopaque,
|
||||||
|
vtable: *const VTable,
|
||||||
|
|
||||||
|
/// vtable for the Zig allocator interface to map our extern
|
||||||
|
/// allocator to Zig's allocator interface.
|
||||||
|
pub const zig_vtable: ZigVTable = .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.resize = resize,
|
||||||
|
.remap = remap,
|
||||||
|
.free = free,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a C allocator from a Zig allocator. This requires that
|
||||||
|
/// the Zig allocator be pointer-stable for the lifetime of the
|
||||||
|
/// C allocator.
|
||||||
|
pub fn fromZig(zig_alloc: *const std.mem.Allocator) Allocator {
|
||||||
|
return .{
|
||||||
|
.ctx = @ptrCast(@constCast(zig_alloc)),
|
||||||
|
.vtable = &ZigAllocator.vtable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a Zig allocator from this C allocator. This requires
|
||||||
|
/// a pointer to a Zig allocator vtable that we can populate with
|
||||||
|
/// our callbacks.
|
||||||
|
pub fn zig(self: *const Allocator) std.mem.Allocator {
|
||||||
|
return .{
|
||||||
|
.ptr = @ptrCast(@constCast(self)),
|
||||||
|
.vtable = &zig_vtable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
len: usize,
|
||||||
|
alignment: std.mem.Alignment,
|
||||||
|
ra: usize,
|
||||||
|
) ?[*]u8 {
|
||||||
|
const self: *Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
return self.vtable.alloc(
|
||||||
|
self.ctx,
|
||||||
|
len,
|
||||||
|
@intFromEnum(alignment),
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
old_mem: []u8,
|
||||||
|
alignment: std.mem.Alignment,
|
||||||
|
new_len: usize,
|
||||||
|
ra: usize,
|
||||||
|
) bool {
|
||||||
|
const self: *Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
return self.vtable.resize(
|
||||||
|
self.ctx,
|
||||||
|
old_mem.ptr,
|
||||||
|
old_mem.len,
|
||||||
|
@intFromEnum(alignment),
|
||||||
|
new_len,
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
old_mem: []u8,
|
||||||
|
alignment: std.mem.Alignment,
|
||||||
|
new_len: usize,
|
||||||
|
ra: usize,
|
||||||
|
) ?[*]u8 {
|
||||||
|
const self: *Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
return self.vtable.remap(
|
||||||
|
self.ctx,
|
||||||
|
old_mem.ptr,
|
||||||
|
old_mem.len,
|
||||||
|
@intFromEnum(alignment),
|
||||||
|
new_len,
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
old_mem: []u8,
|
||||||
|
alignment: std.mem.Alignment,
|
||||||
|
ra: usize,
|
||||||
|
) void {
|
||||||
|
const self: *Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
self.vtable.free(
|
||||||
|
self.ctx,
|
||||||
|
old_mem.ptr,
|
||||||
|
old_mem.len,
|
||||||
|
@intFromEnum(alignment),
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An allocator implementation that wraps a Zig allocator so that
|
||||||
|
/// it can be exposed to C.
|
||||||
|
const ZigAllocator = struct {
|
||||||
|
const vtable: VTable = .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.resize = resize,
|
||||||
|
.remap = remap,
|
||||||
|
.free = free,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn alloc(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
len: usize,
|
||||||
|
alignment: u8,
|
||||||
|
ra: usize,
|
||||||
|
) callconv(.c) ?[*]u8 {
|
||||||
|
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
return zig_alloc.vtable.alloc(
|
||||||
|
zig_alloc.ptr,
|
||||||
|
len,
|
||||||
|
@enumFromInt(alignment),
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
memory: [*]u8,
|
||||||
|
memory_len: usize,
|
||||||
|
alignment: u8,
|
||||||
|
new_len: usize,
|
||||||
|
ra: usize,
|
||||||
|
) callconv(.c) bool {
|
||||||
|
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
return zig_alloc.vtable.resize(
|
||||||
|
zig_alloc.ptr,
|
||||||
|
memory[0..memory_len],
|
||||||
|
@enumFromInt(alignment),
|
||||||
|
new_len,
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
memory: [*]u8,
|
||||||
|
memory_len: usize,
|
||||||
|
alignment: u8,
|
||||||
|
new_len: usize,
|
||||||
|
ra: usize,
|
||||||
|
) callconv(.c) ?[*]u8 {
|
||||||
|
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
return zig_alloc.vtable.remap(
|
||||||
|
zig_alloc.ptr,
|
||||||
|
memory[0..memory_len],
|
||||||
|
@enumFromInt(alignment),
|
||||||
|
new_len,
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
memory: [*]u8,
|
||||||
|
memory_len: usize,
|
||||||
|
alignment: u8,
|
||||||
|
ra: usize,
|
||||||
|
) callconv(.c) void {
|
||||||
|
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
|
||||||
|
return zig_alloc.vtable.free(
|
||||||
|
zig_alloc.ptr,
|
||||||
|
memory[0..memory_len],
|
||||||
|
@enumFromInt(alignment),
|
||||||
|
ra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// libc Allocator, requires linking libc
|
||||||
|
pub const c_allocator: Allocator = .fromZig(&std.heap.c_allocator);
|
||||||
|
|
||||||
|
/// Allocator that can be sent to the C API that does full
|
||||||
|
/// leak checking within Zig tests. This should only be used from
|
||||||
|
/// Zig tests.
|
||||||
|
pub const test_allocator: Allocator = b: {
|
||||||
|
if (!builtin.is_test) @compileError("test_allocator can only be used in tests");
|
||||||
|
break :b .fromZig(&testing.allocator);
|
||||||
|
};
|
||||||
|
|
||||||
|
test "c allocator" {
|
||||||
|
if (!comptime builtin.link_libc) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const alloc = c_allocator.zig();
|
||||||
|
const str = try alloc.alloc(u8, 10);
|
||||||
|
defer alloc.free(str);
|
||||||
|
try testing.expectEqual(10, str.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "fba allocator" {
|
||||||
|
var buf: [1024]u8 = undefined;
|
||||||
|
var fba: std.heap.FixedBufferAllocator = .init(&buf);
|
||||||
|
const zig_alloc = fba.allocator();
|
||||||
|
|
||||||
|
// Convert the Zig allocator to a C interface
|
||||||
|
const c_alloc: Allocator = .fromZig(&zig_alloc);
|
||||||
|
|
||||||
|
// Convert back to Zig so we can test it.
|
||||||
|
const alloc = c_alloc.zig();
|
||||||
|
const str = try alloc.alloc(u8, 10);
|
||||||
|
defer alloc.free(str);
|
||||||
|
try testing.expectEqual(10, str.len);
|
||||||
|
}
|
||||||
|
|
@ -65,6 +65,19 @@ pub const EraseLine = terminal.EraseLine;
|
||||||
pub const TabClear = terminal.TabClear;
|
pub const TabClear = terminal.TabClear;
|
||||||
pub const Attribute = terminal.Attribute;
|
pub const Attribute = terminal.Attribute;
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
// If we're building the C library (vs. the Zig module) then
|
||||||
|
// we want to reference the C API so that it gets exported.
|
||||||
|
if (terminal.is_c_lib) {
|
||||||
|
const c = terminal.c_api;
|
||||||
|
@export(&c.osc_new, .{ .name = "ghostty_osc_new" });
|
||||||
|
@export(&c.osc_free, .{ .name = "ghostty_osc_free" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = terminal;
|
_ = terminal;
|
||||||
|
|
||||||
|
// Tests always test the C API
|
||||||
|
_ = terminal.c_api;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,4 +51,5 @@ pub const locales = [_][:0]const u8{
|
||||||
"hu_HU.UTF-8",
|
"hu_HU.UTF-8",
|
||||||
"he_IL.UTF-8",
|
"he_IL.UTF-8",
|
||||||
"zh_TW.UTF-8",
|
"zh_TW.UTF-8",
|
||||||
|
"hr_HR.UTF-8",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const lib_alloc = @import("../lib/allocator.zig");
|
||||||
|
const CAllocator = lib_alloc.Allocator;
|
||||||
|
const osc = @import("osc.zig");
|
||||||
|
|
||||||
|
/// C: GhosttyOscParser
|
||||||
|
pub const OscParser = ?*osc.Parser;
|
||||||
|
|
||||||
|
/// C: GhosttyResult
|
||||||
|
pub const Result = enum(c_int) {
|
||||||
|
success = 0,
|
||||||
|
out_of_memory = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn osc_new(
|
||||||
|
alloc_: ?*const CAllocator,
|
||||||
|
result: *OscParser,
|
||||||
|
) callconv(.c) Result {
|
||||||
|
const alloc = lib_alloc.default(alloc_);
|
||||||
|
const ptr = alloc.create(osc.Parser) catch
|
||||||
|
return .out_of_memory;
|
||||||
|
ptr.* = .initAlloc(alloc);
|
||||||
|
result.* = ptr;
|
||||||
|
return .success;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn osc_free(parser_: OscParser) callconv(.c) void {
|
||||||
|
// C-built parsers always have an associated allocator.
|
||||||
|
const parser = parser_ orelse return;
|
||||||
|
const alloc = parser.alloc.?;
|
||||||
|
parser.deinit();
|
||||||
|
alloc.destroy(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = lib_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "osc" {
|
||||||
|
const testing = std.testing;
|
||||||
|
var p: OscParser = undefined;
|
||||||
|
try testing.expectEqual(Result.success, osc_new(
|
||||||
|
&lib_alloc.test_allocator,
|
||||||
|
&p,
|
||||||
|
));
|
||||||
|
osc_free(p);
|
||||||
|
}
|
||||||
|
|
@ -62,6 +62,10 @@ pub const Attribute = sgr.Attribute;
|
||||||
|
|
||||||
pub const isSafePaste = sanitize.isSafePaste;
|
pub const isSafePaste = sanitize.isSafePaste;
|
||||||
|
|
||||||
|
/// This is set to true when we're building the C library.
|
||||||
|
pub const is_c_lib = @import("root") == @import("../lib_vt.zig");
|
||||||
|
pub const c_api = @import("c_api.zig");
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue