mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-18 17:56:09 +03:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*.{sh,bash}]
|
[*.{sh,bash,elv}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|
||||||
|
4
.github/workflows/nix.yml
vendored
4
.github/workflows/nix.yml
vendored
@ -36,13 +36,13 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- name: Setup Nix
|
- name: Setup Nix
|
||||||
uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
|
4
.github/workflows/release-pr.yml
vendored
4
.github/workflows/release-pr.yml
vendored
@ -57,7 +57,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -211,7 +211,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
|
6
.github/workflows/release-tag.yml
vendored
6
.github/workflows/release-tag.yml
vendored
@ -83,13 +83,13 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.0
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
|
19
.github/workflows/release-tip.yml
vendored
19
.github/workflows/release-tip.yml
vendored
@ -107,12 +107,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -164,7 +164,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -175,6 +175,9 @@ jobs:
|
|||||||
- name: XCode Select
|
- name: XCode Select
|
||||||
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
||||||
|
|
||||||
|
- name: Xcode Version
|
||||||
|
run: xcodebuild -version
|
||||||
|
|
||||||
# Setup Sparkle
|
# Setup Sparkle
|
||||||
- name: Setup Sparkle
|
- name: Setup Sparkle
|
||||||
env:
|
env:
|
||||||
@ -381,7 +384,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -392,6 +395,9 @@ jobs:
|
|||||||
- name: XCode Select
|
- name: XCode Select
|
||||||
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
||||||
|
|
||||||
|
- name: Xcode Version
|
||||||
|
run: xcodebuild -version
|
||||||
|
|
||||||
# Setup Sparkle
|
# Setup Sparkle
|
||||||
- name: Setup Sparkle
|
- name: Setup Sparkle
|
||||||
env:
|
env:
|
||||||
@ -558,7 +564,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -569,6 +575,9 @@ jobs:
|
|||||||
- name: XCode Select
|
- name: XCode Select
|
||||||
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
||||||
|
|
||||||
|
- name: Xcode Version
|
||||||
|
run: xcodebuild -version
|
||||||
|
|
||||||
# Setup Sparkle
|
# Setup Sparkle
|
||||||
- name: Setup Sparkle
|
- name: Setup Sparkle
|
||||||
env:
|
env:
|
||||||
|
118
.github/workflows/test.yml
vendored
118
.github/workflows/test.yml
vendored
@ -31,6 +31,7 @@ jobs:
|
|||||||
- prettier
|
- prettier
|
||||||
- alejandra
|
- alejandra
|
||||||
- typos
|
- typos
|
||||||
|
- shellcheck
|
||||||
- translations
|
- translations
|
||||||
- blueprint-compiler
|
- blueprint-compiler
|
||||||
- test-pkg-linux
|
- test-pkg-linux
|
||||||
@ -68,14 +69,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -99,14 +100,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -135,14 +136,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -164,14 +165,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -197,14 +198,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -241,14 +242,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -277,7 +278,7 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -288,6 +289,9 @@ jobs:
|
|||||||
- name: Xcode Select
|
- name: Xcode Select
|
||||||
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
run: sudo xcode-select -s /Applications/Xcode_26.0.app
|
||||||
|
|
||||||
|
- name: Xcode Version
|
||||||
|
run: xcodebuild -version
|
||||||
|
|
||||||
- name: get the Zig deps
|
- name: get the Zig deps
|
||||||
id: deps
|
id: deps
|
||||||
run: nix build -L .#deps && echo "deps=$(readlink ./result)" >> $GITHUB_OUTPUT
|
run: nix build -L .#deps && echo "deps=$(readlink ./result)" >> $GITHUB_OUTPUT
|
||||||
@ -357,7 +361,7 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -409,7 +413,7 @@ jobs:
|
|||||||
mkdir dist
|
mkdir dist
|
||||||
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
|
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
@ -504,14 +508,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -546,14 +550,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -594,14 +598,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -621,7 +625,7 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
# 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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -649,12 +653,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -677,12 +681,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -704,12 +708,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -731,12 +735,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -758,12 +762,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -775,6 +779,40 @@ jobs:
|
|||||||
- name: typos check
|
- name: typos check
|
||||||
run: nix develop -c typos
|
run: nix develop -c typos
|
||||||
|
|
||||||
|
shellcheck:
|
||||||
|
if: github.repository == 'ghostty-org/ghostty'
|
||||||
|
runs-on: namespace-profile-ghostty-xsm
|
||||||
|
timeout-minutes: 60
|
||||||
|
env:
|
||||||
|
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
|
||||||
|
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
- name: Setup Cache
|
||||||
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
/nix
|
||||||
|
/zig
|
||||||
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.0
|
||||||
|
with:
|
||||||
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
|
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
|
||||||
|
with:
|
||||||
|
name: ghostty
|
||||||
|
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
skipPush: true
|
||||||
|
useDaemon: false # sometimes fails on short jobs
|
||||||
|
- name: shellcheck
|
||||||
|
run: |
|
||||||
|
nix develop -c shellcheck \
|
||||||
|
--check-sourced \
|
||||||
|
--color=always \
|
||||||
|
--severity=warning \
|
||||||
|
--shell=bash \
|
||||||
|
--external-sources \
|
||||||
|
$(find . \( -name "*.sh" -o -name "*.bash" \) -type f ! -path "./zig-out/*" ! -path "./macos/build/*" ! -path "./.git/*" | sort)
|
||||||
|
|
||||||
translations:
|
translations:
|
||||||
if: github.repository == 'ghostty-org/ghostty'
|
if: github.repository == 'ghostty-org/ghostty'
|
||||||
runs-on: namespace-profile-ghostty-xsm
|
runs-on: namespace-profile-ghostty-xsm
|
||||||
@ -785,12 +823,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -812,12 +850,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -847,14 +885,14 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/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@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
- uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
@ -905,13 +943,13 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
- name: Setup Nix
|
- name: Setup Nix
|
||||||
uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
|
4
.github/workflows/update-colorschemes.yml
vendored
4
.github/workflows/update-colorschemes.yml
vendored
@ -22,14 +22,14 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@449c929cd5138e6607e7e78458e88cc476e76f89 # v1.2.8
|
uses: namespacelabs/nscloud-cache-action@0ac1550c04676e19d39872be6216ccbf9c6bab43 # v1.2.9
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/nix
|
/nix
|
||||||
/zig
|
/zig
|
||||||
|
|
||||||
- name: Setup Nix
|
- name: Setup Nix
|
||||||
uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31.4.1
|
uses: cachix/install-nix-action@cebd211ec2008b83bda8fb0b21c3c072f004fe04 # v31.5.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
|
||||||
|
41
build.zig
41
build.zig
@ -8,7 +8,22 @@ comptime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(b: *std.Build) !void {
|
pub fn build(b: *std.Build) !void {
|
||||||
|
// This defines all the available build options (e.g. `-D`).
|
||||||
const config = try buildpkg.Config.init(b);
|
const config = try buildpkg.Config.init(b);
|
||||||
|
const test_filter = b.option(
|
||||||
|
[]const u8,
|
||||||
|
"test-filter",
|
||||||
|
"Filter for test. Only applies to Zig tests.",
|
||||||
|
);
|
||||||
|
|
||||||
|
// All our steps which we'll hook up later. The steps are shown
|
||||||
|
// up here just so that they are more self-documenting.
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
const test_step = b.step("test", "Run all tests");
|
||||||
|
const translations_step = b.step(
|
||||||
|
"update-translations",
|
||||||
|
"Update translation files",
|
||||||
|
);
|
||||||
|
|
||||||
// Ghostty resources like terminfo, shell integration, themes, etc.
|
// Ghostty resources like terminfo, shell integration, themes, etc.
|
||||||
const resources = try buildpkg.GhosttyResources.init(b, &config);
|
const resources = try buildpkg.GhosttyResources.init(b, &config);
|
||||||
@ -131,7 +146,6 @@ pub fn build(b: *std.Build) !void {
|
|||||||
b.getInstallPath(.prefix, "share/ghostty"),
|
b.getInstallPath(.prefix, "share/ghostty"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const run_step = b.step("run", "Run the app");
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
run_step.dependOn(&run_cmd.step);
|
||||||
break :run;
|
break :run;
|
||||||
}
|
}
|
||||||
@ -157,16 +171,18 @@ pub fn build(b: *std.Build) !void {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const run_step = b.step("run", "Run the app");
|
// Run uses the native macOS app
|
||||||
run_step.dependOn(&macos_app_native_only.open.step);
|
run_step.dependOn(&macos_app_native_only.open.step);
|
||||||
|
|
||||||
|
// If we have no test filters, install the tests too
|
||||||
|
if (test_filter == null) {
|
||||||
|
macos_app_native_only.addTestStepDependencies(test_step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
{
|
{
|
||||||
const test_step = b.step("test", "Run all tests");
|
|
||||||
const test_filter = b.option([]const u8, "test-filter", "Filter for test");
|
|
||||||
|
|
||||||
const test_exe = b.addTest(.{
|
const test_exe = b.addTest(.{
|
||||||
.name = "ghostty-test",
|
.name = "ghostty-test",
|
||||||
.filters = if (test_filter) |v| &.{v} else &.{},
|
.filters = if (test_filter) |v| &.{v} else &.{},
|
||||||
@ -180,18 +196,13 @@ pub fn build(b: *std.Build) !void {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
if (config.emit_test_exe) b.installArtifact(test_exe);
|
||||||
if (config.emit_test_exe) b.installArtifact(test_exe);
|
_ = try deps.add(test_exe);
|
||||||
_ = try deps.add(test_exe);
|
const test_run = b.addRunArtifact(test_exe);
|
||||||
const test_run = b.addRunArtifact(test_exe);
|
test_step.dependOn(&test_run.step);
|
||||||
test_step.dependOn(&test_run.step);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update-translations does what it sounds like and updates the "pot"
|
// update-translations does what it sounds like and updates the "pot"
|
||||||
// files. These should be committed to the repo.
|
// files. These should be committed to the repo.
|
||||||
{
|
translations_step.dependOn(i18n.update_step);
|
||||||
const step = b.step("update-translations", "Update translation files");
|
|
||||||
step.dependOn(i18n.update_step);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -680,6 +680,12 @@ typedef struct {
|
|||||||
uintptr_t len;
|
uintptr_t len;
|
||||||
} ghostty_action_open_url_s;
|
} ghostty_action_open_url_s;
|
||||||
|
|
||||||
|
// apprt.surface.Message.ChildExited
|
||||||
|
typedef struct {
|
||||||
|
uint32_t exit_code;
|
||||||
|
uint64_t timetime_ms;
|
||||||
|
} ghostty_surface_message_childexited_s;
|
||||||
|
|
||||||
// apprt.Action.Key
|
// apprt.Action.Key
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GHOSTTY_ACTION_QUIT,
|
GHOSTTY_ACTION_QUIT,
|
||||||
@ -731,6 +737,7 @@ typedef enum {
|
|||||||
GHOSTTY_ACTION_REDO,
|
GHOSTTY_ACTION_REDO,
|
||||||
GHOSTTY_ACTION_CHECK_FOR_UPDATES,
|
GHOSTTY_ACTION_CHECK_FOR_UPDATES,
|
||||||
GHOSTTY_ACTION_OPEN_URL,
|
GHOSTTY_ACTION_OPEN_URL,
|
||||||
|
GHOSTTY_ACTION_SHOW_CHILD_EXITED
|
||||||
} ghostty_action_tag_e;
|
} ghostty_action_tag_e;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
@ -759,6 +766,7 @@ typedef union {
|
|||||||
ghostty_action_reload_config_s reload_config;
|
ghostty_action_reload_config_s reload_config;
|
||||||
ghostty_action_config_change_s config_change;
|
ghostty_action_config_change_s config_change;
|
||||||
ghostty_action_open_url_s open_url;
|
ghostty_action_open_url_s open_url;
|
||||||
|
ghostty_surface_message_childexited_s child_exited;
|
||||||
} ghostty_action_u;
|
} ghostty_action_u;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -932,6 +940,9 @@ bool ghostty_inspector_metal_shutdown(ghostty_inspector_t);
|
|||||||
// Don't use these unless you know what you're doing.
|
// Don't use these unless you know what you're doing.
|
||||||
void ghostty_set_window_background_blur(ghostty_app_t, void*);
|
void ghostty_set_window_background_blur(ghostty_app_t, void*);
|
||||||
|
|
||||||
|
// Benchmark API, if available.
|
||||||
|
bool ghostty_benchmark_cli(const char*, const char*);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 56;
|
objectVersion = 70;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@ -152,6 +152,16 @@
|
|||||||
FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */ = {isa = PBXBuildFile; fileRef = FC9ABA9B2D0F538D0020D4C8 /* bash-completion */; };
|
FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */ = {isa = PBXBuildFile; fileRef = FC9ABA9B2D0F538D0020D4C8 /* bash-completion */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
A54F45F72E1F047A0046BD5C /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = A5B30529299BEAAA0047F10C /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = A5B30530299BEAAA0047F10C;
|
||||||
|
remoteInfo = Ghostty;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
29C15B1C2CDC3B2000520DD4 /* bat */ = {isa = PBXFileReference; lastKnownFileType = folder; name = bat; path = "../zig-out/share/bat"; sourceTree = "<group>"; };
|
29C15B1C2CDC3B2000520DD4 /* bat */ = {isa = PBXFileReference; lastKnownFileType = folder; name = bat; path = "../zig-out/share/bat"; sourceTree = "<group>"; };
|
||||||
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyReleaseLocal.entitlements; sourceTree = "<group>"; };
|
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyReleaseLocal.entitlements; sourceTree = "<group>"; };
|
||||||
@ -199,6 +209,7 @@
|
|||||||
A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIcon.swift; sourceTree = "<group>"; };
|
A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIcon.swift; sourceTree = "<group>"; };
|
||||||
A54B0CEE2D0D2E2400CBEFF8 /* ColorizedGhosttyIconImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIconImage.swift; sourceTree = "<group>"; };
|
A54B0CEE2D0D2E2400CBEFF8 /* ColorizedGhosttyIconImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIconImage.swift; sourceTree = "<group>"; };
|
||||||
A54D786B2CA79788001B19B1 /* BaseTerminalController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTerminalController.swift; sourceTree = "<group>"; };
|
A54D786B2CA79788001B19B1 /* BaseTerminalController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTerminalController.swift; sourceTree = "<group>"; };
|
||||||
|
A54F45F32E1F047A0046BD5C /* GhosttyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GhosttyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
A553F4122E06EB1600257779 /* Ghostty.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; name = Ghostty.icon; path = ../images/Ghostty.icon; sourceTree = SOURCE_ROOT; };
|
A553F4122E06EB1600257779 /* Ghostty.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; name = Ghostty.icon; path = ../images/Ghostty.icon; sourceTree = SOURCE_ROOT; };
|
||||||
A5593FDE2DF8D57100B47B10 /* TerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalWindow.swift; sourceTree = "<group>"; };
|
A5593FDE2DF8D57100B47B10 /* TerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalWindow.swift; sourceTree = "<group>"; };
|
||||||
A5593FE02DF8D73400B47B10 /* HiddenTitlebarTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenTitlebarTerminalWindow.swift; sourceTree = "<group>"; };
|
A5593FE02DF8D73400B47B10 /* HiddenTitlebarTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenTitlebarTerminalWindow.swift; sourceTree = "<group>"; };
|
||||||
@ -291,7 +302,18 @@
|
|||||||
FC9ABA9B2D0F538D0020D4C8 /* bash-completion */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "bash-completion"; path = "../zig-out/share/bash-completion"; sourceTree = "<group>"; };
|
FC9ABA9B2D0F538D0020D4C8 /* bash-completion */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "bash-completion"; path = "../zig-out/share/bash-completion"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
A54F45F42E1F047A0046BD5C /* Tests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Tests; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
A54F45F02E1F047A0046BD5C /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
A5B3052E299BEAAA0047F10C /* Frameworks */ = {
|
A5B3052E299BEAAA0047F10C /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -590,6 +612,7 @@
|
|||||||
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
|
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
|
||||||
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */,
|
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */,
|
||||||
A54CD6ED299BEB14008C95BB /* Sources */,
|
A54CD6ED299BEB14008C95BB /* Sources */,
|
||||||
|
A54F45F42E1F047A0046BD5C /* Tests */,
|
||||||
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
||||||
A5A1F8862A489D7400D1E8BC /* Resources */,
|
A5A1F8862A489D7400D1E8BC /* Resources */,
|
||||||
A5B30532299BEAAA0047F10C /* Products */,
|
A5B30532299BEAAA0047F10C /* Products */,
|
||||||
@ -601,6 +624,7 @@
|
|||||||
children = (
|
children = (
|
||||||
A5B30531299BEAAA0047F10C /* Ghostty.app */,
|
A5B30531299BEAAA0047F10C /* Ghostty.app */,
|
||||||
A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */,
|
A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */,
|
||||||
|
A54F45F32E1F047A0046BD5C /* GhosttyTests.xctest */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -674,6 +698,29 @@
|
|||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
A54F45F22E1F047A0046BD5C /* GhosttyTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = A54F45FC2E1F047A0046BD5C /* Build configuration list for PBXNativeTarget "GhosttyTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
A54F45EF2E1F047A0046BD5C /* Sources */,
|
||||||
|
A54F45F02E1F047A0046BD5C /* Frameworks */,
|
||||||
|
A54F45F12E1F047A0046BD5C /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
A54F45F82E1F047A0046BD5C /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
A54F45F42E1F047A0046BD5C /* Tests */,
|
||||||
|
);
|
||||||
|
name = GhosttyTests;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = GhosttyTests;
|
||||||
|
productReference = A54F45F32E1F047A0046BD5C /* GhosttyTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
A5B30530299BEAAA0047F10C /* Ghostty */ = {
|
A5B30530299BEAAA0047F10C /* Ghostty */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = A5B30540299BEAAB0047F10C /* Build configuration list for PBXNativeTarget "Ghostty" */;
|
buildConfigurationList = A5B30540299BEAAB0047F10C /* Build configuration list for PBXNativeTarget "Ghostty" */;
|
||||||
@ -718,9 +765,13 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1520;
|
LastSwiftUpdateCheck = 2600;
|
||||||
LastUpgradeCheck = 1610;
|
LastUpgradeCheck = 1610;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
A54F45F22E1F047A0046BD5C = {
|
||||||
|
CreatedOnToolsVersion = 26.0;
|
||||||
|
TestTargetID = A5B30530299BEAAA0047F10C;
|
||||||
|
};
|
||||||
A5B30530299BEAAA0047F10C = {
|
A5B30530299BEAAA0047F10C = {
|
||||||
CreatedOnToolsVersion = 14.2;
|
CreatedOnToolsVersion = 14.2;
|
||||||
LastSwiftMigration = 1510;
|
LastSwiftMigration = 1510;
|
||||||
@ -748,11 +799,19 @@
|
|||||||
targets = (
|
targets = (
|
||||||
A5B30530299BEAAA0047F10C /* Ghostty */,
|
A5B30530299BEAAA0047F10C /* Ghostty */,
|
||||||
A5D4499C2B53AE7B000F5B83 /* Ghostty-iOS */,
|
A5D4499C2B53AE7B000F5B83 /* Ghostty-iOS */,
|
||||||
|
A54F45F22E1F047A0046BD5C /* GhosttyTests */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
A54F45F12E1F047A0046BD5C /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
A5B3052F299BEAAA0047F10C /* Resources */ = {
|
A5B3052F299BEAAA0047F10C /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -794,6 +853,13 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
A54F45EF2E1F047A0046BD5C /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
A5B3052D299BEAAA0047F10C /* Sources */ = {
|
A5B3052D299BEAAA0047F10C /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -925,6 +991,14 @@
|
|||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
A54F45F82E1F047A0046BD5C /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = A5B30530299BEAAA0047F10C /* Ghostty */;
|
||||||
|
targetProxy = A54F45F72E1F047A0046BD5C /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
3B39CAA22B33946300DABEB8 /* ReleaseLocal */ = {
|
3B39CAA22B33946300DABEB8 /* ReleaseLocal */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
@ -1034,6 +1108,76 @@
|
|||||||
};
|
};
|
||||||
name = ReleaseLocal;
|
name = ReleaseLocal;
|
||||||
};
|
};
|
||||||
|
A54F45F92E1F047A0046BD5C /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.5;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.GhosttyTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Ghostty.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ghostty";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
A54F45FA2E1F047A0046BD5C /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.5;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.GhosttyTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Ghostty.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ghostty";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
A54F45FB2E1F047A0046BD5C /* ReleaseLocal */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.5;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.GhosttyTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = NO;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Ghostty.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ghostty";
|
||||||
|
};
|
||||||
|
name = ReleaseLocal;
|
||||||
|
};
|
||||||
A5B3053E299BEAAB0047F10C /* Debug */ = {
|
A5B3053E299BEAAB0047F10C /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@ -1378,6 +1522,16 @@
|
|||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
A54F45FC2E1F047A0046BD5C /* Build configuration list for PBXNativeTarget "GhosttyTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
A54F45F92E1F047A0046BD5C /* Debug */,
|
||||||
|
A54F45FA2E1F047A0046BD5C /* Release */,
|
||||||
|
A54F45FB2E1F047A0046BD5C /* ReleaseLocal */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = ReleaseLocal;
|
||||||
|
};
|
||||||
A5B3052C299BEAAA0047F10C /* Build configuration list for PBXProject "Ghostty" */ = {
|
A5B3052C299BEAAA0047F10C /* Build configuration list for PBXProject "Ghostty" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
@ -28,6 +28,19 @@
|
|||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
shouldAutocreateTestPlan = "YES">
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "A54F45F22E1F047A0046BD5C"
|
||||||
|
BuildableName = "GhosttyTests.xctest"
|
||||||
|
BlueprintName = "GhosttyTests"
|
||||||
|
ReferencedContainer = "container:Ghostty.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
@ -579,6 +579,8 @@ extension Ghostty {
|
|||||||
case GHOSTTY_ACTION_SIZE_LIMIT:
|
case GHOSTTY_ACTION_SIZE_LIMIT:
|
||||||
fallthrough
|
fallthrough
|
||||||
case GHOSTTY_ACTION_QUIT_TIMER:
|
case GHOSTTY_ACTION_QUIT_TIMER:
|
||||||
|
fallthrough
|
||||||
|
case GHOSTTY_ACTION_SHOW_CHILD_EXITED:
|
||||||
Ghostty.logger.info("known but unimplemented action action=\(action.tag.rawValue)")
|
Ghostty.logger.info("known but unimplemented action action=\(action.tag.rawValue)")
|
||||||
return false
|
return false
|
||||||
default:
|
default:
|
||||||
|
32
macos/Tests/BenchmarkTests.swift
Normal file
32
macos/Tests/BenchmarkTests.swift
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// GhosttyTests.swift
|
||||||
|
// GhosttyTests
|
||||||
|
//
|
||||||
|
// Created by Mitchell Hashimoto on 7/9/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Testing
|
||||||
|
import GhosttyKit
|
||||||
|
|
||||||
|
extension Tag {
|
||||||
|
@Tag static var benchmark: Self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The whole idea behind these benchmarks is that they're run by right-clicking
|
||||||
|
/// in Xcode and using "Profile" to open them in instruments. They aren't meant to
|
||||||
|
/// be run in general.
|
||||||
|
///
|
||||||
|
/// When running them, set the `if:` to `true`. There's probably a better
|
||||||
|
/// programmatic way to do this but I don't know it yet!
|
||||||
|
@Suite(
|
||||||
|
"Benchmarks",
|
||||||
|
.enabled(if: false),
|
||||||
|
.tags(.benchmark)
|
||||||
|
)
|
||||||
|
struct BenchmarkTests {
|
||||||
|
@Test func example() async throws {
|
||||||
|
ghostty_benchmark_cli(
|
||||||
|
"terminal-stream",
|
||||||
|
"--data=/Users/mitchellh/Documents/ghostty/bug.osc.txt")
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
set -e # Exit immediately if a command exits with a non-zero status
|
set -e # Exit immediately if a command exits with a non-zero status
|
||||||
|
|
||||||
SCRIPT_PATH="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
SCRIPT_PATH="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
INPUT_FILE="$SCRIPT_PATH/../../build.zig.zon2json-lock"
|
INPUT_FILE="$SCRIPT_PATH/../../build.zig.zon2json-lock"
|
||||||
OUTPUT_DIR="blob"
|
OUTPUT_DIR="blob"
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
pinact,
|
pinact,
|
||||||
hyperfine,
|
hyperfine,
|
||||||
typos,
|
typos,
|
||||||
|
shellcheck,
|
||||||
uv,
|
uv,
|
||||||
wayland,
|
wayland,
|
||||||
wayland-scanner,
|
wayland-scanner,
|
||||||
@ -101,6 +102,7 @@ in
|
|||||||
alejandra
|
alejandra
|
||||||
pinact
|
pinact
|
||||||
typos
|
typos
|
||||||
|
shellcheck
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
parallel
|
parallel
|
||||||
|
@ -15,15 +15,23 @@ pub fn build(b: *std.Build) !void {
|
|||||||
});
|
});
|
||||||
const macos = b.dependency("macos", .{ .target = target, .optimize = optimize });
|
const macos = b.dependency("macos", .{ .target = target, .optimize = optimize });
|
||||||
|
|
||||||
const module = b.addModule("harfbuzz", .{
|
const module = harfbuzz: {
|
||||||
.root_source_file = b.path("main.zig"),
|
const module = b.addModule("harfbuzz", .{
|
||||||
.target = target,
|
.root_source_file = b.path("main.zig"),
|
||||||
.optimize = optimize,
|
.target = target,
|
||||||
.imports = &.{
|
.optimize = optimize,
|
||||||
.{ .name = "freetype", .module = freetype.module("freetype") },
|
.imports = &.{
|
||||||
.{ .name = "macos", .module = macos.module("macos") },
|
.{ .name = "freetype", .module = freetype.module("freetype") },
|
||||||
},
|
.{ .name = "macos", .module = macos.module("macos") },
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = b.addOptions();
|
||||||
|
options.addOption(bool, "coretext", coretext_enabled);
|
||||||
|
options.addOption(bool, "freetype", freetype_enabled);
|
||||||
|
module.addOptions("build_options", options);
|
||||||
|
break :harfbuzz module;
|
||||||
|
};
|
||||||
|
|
||||||
// For dynamic linking, we prefer dynamic linking and to search by
|
// For dynamic linking, we prefer dynamic linking and to search by
|
||||||
// mode first. Mode first will search all paths for a dynamic library
|
// mode first. Mode first will search all paths for a dynamic library
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
const build_options = @import("build_options");
|
||||||
|
|
||||||
pub const c = @cImport({
|
pub const c = @cImport({
|
||||||
@cInclude("hb.h");
|
@cInclude("hb.h");
|
||||||
@cInclude("hb-ft.h");
|
if (build_options.freetype) @cInclude("hb-ft.h");
|
||||||
if (builtin.os.tag == .macos) @cInclude("hb-coretext.h");
|
if (build_options.coretext) @cInclude("hb-coretext.h");
|
||||||
});
|
});
|
||||||
|
@ -18,15 +18,12 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
|
||||||
defer flags.deinit();
|
|
||||||
lib.addCSourceFile(.{
|
lib.addCSourceFile(.{
|
||||||
.file = b.path("os/zig_log.c"),
|
.file = b.path("os/zig_macos.c"),
|
||||||
.flags = flags.items,
|
.flags = &.{"-std=c99"},
|
||||||
});
|
});
|
||||||
lib.addCSourceFile(.{
|
lib.addCSourceFile(.{
|
||||||
.file = b.path("text/ext.c"),
|
.file = b.path("text/ext.c"),
|
||||||
.flags = flags.items,
|
|
||||||
});
|
});
|
||||||
lib.linkFramework("CoreFoundation");
|
lib.linkFramework("CoreFoundation");
|
||||||
lib.linkFramework("CoreGraphics");
|
lib.linkFramework("CoreGraphics");
|
||||||
|
@ -23,6 +23,7 @@ pub const c = @cImport({
|
|||||||
@cInclude("IOSurface/IOSurfaceRef.h");
|
@cInclude("IOSurface/IOSurfaceRef.h");
|
||||||
@cInclude("dispatch/dispatch.h");
|
@cInclude("dispatch/dispatch.h");
|
||||||
@cInclude("os/log.h");
|
@cInclude("os/log.h");
|
||||||
|
@cInclude("os/signpost.h");
|
||||||
|
|
||||||
if (builtin.os.tag == .macos) {
|
if (builtin.os.tag == .macos) {
|
||||||
@cInclude("Carbon/Carbon.h");
|
@cInclude("Carbon/Carbon.h");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const log = @import("os/log.zig");
|
const log = @import("os/log.zig");
|
||||||
|
|
||||||
pub const c = @import("os/c.zig");
|
pub const c = @import("os/c.zig");
|
||||||
|
pub const signpost = @import("os/signpost.zig");
|
||||||
pub const Log = log.Log;
|
pub const Log = log.Log;
|
||||||
pub const LogType = log.LogType;
|
pub const LogType = log.LogType;
|
||||||
|
|
||||||
|
@ -8,10 +8,10 @@ pub const Log = opaque {
|
|||||||
subsystem: [:0]const u8,
|
subsystem: [:0]const u8,
|
||||||
category: [:0]const u8,
|
category: [:0]const u8,
|
||||||
) *Log {
|
) *Log {
|
||||||
return @as(?*Log, @ptrFromInt(@intFromPtr(c.os_log_create(
|
return @ptrCast(c.os_log_create(
|
||||||
subsystem.ptr,
|
subsystem.ptr,
|
||||||
category.ptr,
|
category.ptr,
|
||||||
)))).?;
|
).?);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self: *Log) void {
|
pub fn release(self: *Log) void {
|
||||||
@ -32,7 +32,11 @@ pub const Log = opaque {
|
|||||||
comptime format: []const u8,
|
comptime format: []const u8,
|
||||||
args: anytype,
|
args: anytype,
|
||||||
) void {
|
) void {
|
||||||
const str = nosuspend std.fmt.allocPrintZ(alloc, format, args) catch return;
|
const str = nosuspend std.fmt.allocPrintZ(
|
||||||
|
alloc,
|
||||||
|
format,
|
||||||
|
args,
|
||||||
|
) catch return;
|
||||||
defer alloc.free(str);
|
defer alloc.free(str);
|
||||||
zig_os_log_with_type(self, typ, str.ptr);
|
zig_os_log_with_type(self, typ, str.ptr);
|
||||||
}
|
}
|
||||||
|
214
pkg/macos/os/signpost.zig
Normal file
214
pkg/macos/os/signpost.zig
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const c = @import("c.zig").c;
|
||||||
|
const logpkg = @import("log.zig");
|
||||||
|
const Log = logpkg.Log;
|
||||||
|
|
||||||
|
/// This should be called once at the start of the program to intialize
|
||||||
|
/// some required state for signpost logging.
|
||||||
|
///
|
||||||
|
/// This is all to workaround a Zig bug:
|
||||||
|
/// https://github.com/ziglang/zig/issues/24370
|
||||||
|
pub fn init() void {
|
||||||
|
if (__dso_handle != null) return;
|
||||||
|
|
||||||
|
const sym = comptime sym: {
|
||||||
|
const root = @import("root");
|
||||||
|
|
||||||
|
// If we have a main function, use that as the symbol.
|
||||||
|
if (@hasDecl(root, "main")) break :sym root.main;
|
||||||
|
|
||||||
|
// Otherwise, we're in a library, so we just use the first
|
||||||
|
// function in our root module. I actually don't know if this is
|
||||||
|
// all required or if we can just use the real `__dso_handle` symbol,
|
||||||
|
// but this seems to work for now.
|
||||||
|
for (@typeInfo(root).@"struct".decls) |decl_info| {
|
||||||
|
const decl = @field(root, decl_info.name);
|
||||||
|
if (@typeInfo(@TypeOf(decl)) == .@"fn") break :sym decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@compileError("no functions found in root module");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Since __dso_handle is not automatically populated by the linker,
|
||||||
|
// we populate it by looking up the main function's module address
|
||||||
|
// which should be a mach-o header.
|
||||||
|
var info: DlInfo = undefined;
|
||||||
|
const result = dladdr(sym, &info);
|
||||||
|
assert(result != 0);
|
||||||
|
__dso_handle = @ptrCast(@alignCast(info.dli_fbase));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This should REALLY be an extern var that is populated by the linker,
|
||||||
|
/// but there is a Zig bug: https://github.com/ziglang/zig/issues/24370
|
||||||
|
var __dso_handle: ?*c.mach_header = null;
|
||||||
|
|
||||||
|
// Import the necessary C functions and types
|
||||||
|
extern "c" fn dladdr(addr: ?*const anyopaque, info: *DlInfo) c_int;
|
||||||
|
|
||||||
|
// Define the Dl_info structure
|
||||||
|
const DlInfo = extern struct {
|
||||||
|
dli_fname: [*:0]const u8, // Pathname of shared object
|
||||||
|
dli_fbase: ?*anyopaque, // Base address of shared object
|
||||||
|
dli_sname: [*:0]const u8, // Name of nearest symbol
|
||||||
|
dli_saddr: ?*anyopaque, // Address of nearest symbol
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Checks whether signpost logging is enabled for the given log handle.
|
||||||
|
/// Returns true if signposts will be recorded for this log, false otherwise.
|
||||||
|
/// This can be used to avoid expensive operations when signpost logging is disabled.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_enabled?language=objc
|
||||||
|
pub fn enabled(log: *Log) bool {
|
||||||
|
return c.os_signpost_enabled(@ptrCast(log));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits a signpost event - a single point in time marker.
|
||||||
|
/// Events are useful for marking when specific actions occur, such as
|
||||||
|
/// user interactions, state changes, or other discrete occurrences.
|
||||||
|
/// The event will appear as a vertical line in Instruments.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_event_emit?language=objc
|
||||||
|
pub fn emitEvent(
|
||||||
|
log: *Log,
|
||||||
|
id: Id,
|
||||||
|
comptime name: [:0]const u8,
|
||||||
|
) void {
|
||||||
|
emitWithName(log, id, .event, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the beginning of a time interval.
|
||||||
|
/// Use this with intervalEnd to measure the duration of operations.
|
||||||
|
/// The same ID must be used for both the begin and end calls.
|
||||||
|
/// Intervals appear as horizontal bars in Instruments timeline.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_interval_begin?language=objc
|
||||||
|
pub fn intervalBegin(log: *Log, id: Id, comptime name: [:0]const u8) void {
|
||||||
|
emitWithName(log, id, .interval_begin, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the end of a time interval.
|
||||||
|
/// Must be paired with a prior intervalBegin call using the same ID.
|
||||||
|
/// The name should match the name used in intervalBegin.
|
||||||
|
/// Instruments will calculate and display the duration between begin and end.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_interval_end?language=objc
|
||||||
|
pub fn intervalEnd(log: *Log, id: Id, comptime name: [:0]const u8) void {
|
||||||
|
emitWithName(log, id, .interval_end, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The internal function to emit a signpost with a specific name.
|
||||||
|
fn emitWithName(
|
||||||
|
log: *Log,
|
||||||
|
id: Id,
|
||||||
|
typ: Type,
|
||||||
|
comptime name: [:0]const u8,
|
||||||
|
) void {
|
||||||
|
// Init must be called by this point.
|
||||||
|
assert(__dso_handle != null);
|
||||||
|
|
||||||
|
var buf: [2]u8 = @splat(0);
|
||||||
|
c._os_signpost_emit_with_name_impl(
|
||||||
|
__dso_handle,
|
||||||
|
@ptrCast(log),
|
||||||
|
@intFromEnum(typ),
|
||||||
|
@intFromEnum(id),
|
||||||
|
name.ptr,
|
||||||
|
"".ptr,
|
||||||
|
&buf,
|
||||||
|
buf.len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_id_t?language=objc
|
||||||
|
pub const Id = enum(u64) {
|
||||||
|
null = 0, // OS_SIGNPOST_ID_NULL
|
||||||
|
invalid = 0xFFFFFFFFFFFFFFFF, // OS_SIGNPOST_ID_INVALID
|
||||||
|
exclusive = 0xEEEEB0B5B2B2EEEE, // OS_SIGNPOST_ID_EXCLUSIVE
|
||||||
|
_,
|
||||||
|
|
||||||
|
/// Generates a new signpost ID for use with signpost operations.
|
||||||
|
/// The ID is unique for the given log handle and can be used to track
|
||||||
|
/// asynchronous operations or mark specific points of interest in the code.
|
||||||
|
/// Returns a unique signpost ID that can be used with os_signpost functions.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_id_generate?language=objc
|
||||||
|
pub fn generate(log: *Log) Id {
|
||||||
|
return @enumFromInt(c.os_signpost_id_generate(@ptrCast(log)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a signpost ID based on a pointer value.
|
||||||
|
/// This is useful for tracking operations associated with a specific object
|
||||||
|
/// or memory location. The same pointer will always generate the same ID
|
||||||
|
/// for a given log handle, allowing correlation of signpost events.
|
||||||
|
/// Pass null to get the null signpost ID.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_id_for_pointer?language=objc
|
||||||
|
pub fn forPointer(log: *Log, ptr: ?*anyopaque) Id {
|
||||||
|
return @enumFromInt(c.os_signpost_id_make_with_pointer(
|
||||||
|
@ptrCast(log),
|
||||||
|
@ptrCast(ptr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "generate ID" {
|
||||||
|
// We can't really test the return value because it may return null
|
||||||
|
// if signposts are disabled.
|
||||||
|
const id: Id = .generate(Log.create("com.mitchellh.ghostty", "test"));
|
||||||
|
try std.testing.expect(id != .invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "generate ID for pointer" {
|
||||||
|
var foo: usize = 0x1234;
|
||||||
|
const id: Id = .forPointer(Log.create("com.mitchellh.ghostty", "test"), &foo);
|
||||||
|
try std.testing.expect(id != .null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// https://developer.apple.com/documentation/os/ossignposttype?language=objc
|
||||||
|
pub const Type = enum(u8) {
|
||||||
|
event = 0, // OS_SIGNPOST_EVENT
|
||||||
|
interval_begin = 1, // OS_SIGNPOST_INTERVAL_BEGIN
|
||||||
|
interval_end = 2, // OS_SIGNPOST_INTERVAL_END
|
||||||
|
|
||||||
|
pub const mask: u8 = 0x03; // OS_SIGNPOST_TYPE_MASK
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Special os_log category values that surface in Instruments and other
|
||||||
|
/// tooling.
|
||||||
|
pub const Category = struct {
|
||||||
|
/// Points of Interest appear as a dedicated track in Instruments.
|
||||||
|
/// Use this for high-level application events that help understand
|
||||||
|
/// the flow of your application.
|
||||||
|
pub const points_of_interest: [:0]const u8 = "PointsOfInterest";
|
||||||
|
|
||||||
|
/// Dynamic Tracing category enables runtime-configurable logging.
|
||||||
|
/// Signposts in this category can be enabled/disabled dynamically
|
||||||
|
/// without recompiling.
|
||||||
|
pub const dynamic_tracing: [:0]const u8 = "DynamicTracing";
|
||||||
|
|
||||||
|
/// Dynamic Stack Tracing category captures call stacks at signpost
|
||||||
|
/// events. This provides deeper debugging information but has higher
|
||||||
|
/// performance overhead.
|
||||||
|
pub const dynamic_stack_tracing: [:0]const u8 = "DynamicStackTracing";
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
test enabled {
|
||||||
|
_ = enabled(Log.create("com.mitchellh.ghostty", "test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "intervals" {
|
||||||
|
init();
|
||||||
|
|
||||||
|
const log = Log.create("com.mitchellh.ghostty", "test");
|
||||||
|
defer log.release();
|
||||||
|
|
||||||
|
// Test that we can begin and end an interval
|
||||||
|
const id = Id.generate(log);
|
||||||
|
intervalBegin(log, id, "Test Interval");
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include <os/log.h>
|
#include <os/log.h>
|
||||||
|
#include <os/signpost.h>
|
||||||
|
|
||||||
// A wrapper so we can use the os_log_with_type macro.
|
// A wrapper so we can use the os_log_with_type macro.
|
||||||
void zig_os_log_with_type(
|
void zig_os_log_with_type(
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-05-19 11:34+0300\n"
|
"PO-Revision-Date: 2025-05-19 11:34+0300\n"
|
||||||
"Last-Translator: Damyan Bogoev <damyan.bogoev@gmail.com>\n"
|
"Last-Translator: Damyan Bogoev <damyan.bogoev@gmail.com>\n"
|
||||||
"Language-Team: Bulgarian <dict@ludost.net>\n"
|
"Language-Team: Bulgarian <dict@ludost.net>\n"
|
||||||
@ -236,7 +236,7 @@ msgstr ""
|
|||||||
"Поставянето на този текст в терминала може да е опасно, тъй като изглежда, "
|
"Поставянето на този текст в терминала може да е опасно, тъй като изглежда, "
|
||||||
"че може да бъдат изпълнени някои команди."
|
"че може да бъдат изпълнени някои команди."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Затвори"
|
msgstr "Затвори"
|
||||||
|
|
||||||
@ -276,6 +276,14 @@ msgstr "Текущият процес в това разделяне ще бъд
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Копирано в клипборда"
|
msgstr "Копирано в клипборда"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Главно меню"
|
msgstr "Главно меню"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-20 08:07+0100\n"
|
"PO-Revision-Date: 2025-03-20 08:07+0100\n"
|
||||||
"Last-Translator: Francesc Arpi <francesc.arpi@gmail.com>\n"
|
"Last-Translator: Francesc Arpi <francesc.arpi@gmail.com>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
@ -236,7 +236,7 @@ msgstr ""
|
|||||||
"Enganxar aquest text al terminal pot ser perillós, ja que sembla que es "
|
"Enganxar aquest text al terminal pot ser perillós, ja que sembla que es "
|
||||||
"podrien executar algunes ordres."
|
"podrien executar algunes ordres."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Tanca"
|
msgstr "Tanca"
|
||||||
|
|
||||||
@ -276,6 +276,14 @@ msgstr "El procés actualment en execució en aquesta divisió es tancarà."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Copiat al porta-retalls"
|
msgstr "Copiat al porta-retalls"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Menú principal"
|
msgstr "Menú principal"
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -228,7 +228,7 @@ msgid ""
|
|||||||
"commands may be executed."
|
"commands may be executed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -268,6 +268,14 @@ msgstr ""
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-06 14:57+0100\n"
|
"PO-Revision-Date: 2025-03-06 14:57+0100\n"
|
||||||
"Last-Translator: Robin <r@rpfaeffle.com>\n"
|
"Last-Translator: Robin <r@rpfaeffle.com>\n"
|
||||||
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
|
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
|
||||||
@ -235,7 +235,7 @@ msgstr ""
|
|||||||
"Diesen Text in das Terminal einzufügen könnte möglicherweise gefährlich "
|
"Diesen Text in das Terminal einzufügen könnte möglicherweise gefährlich "
|
||||||
"sein. Es scheint, dass Anweisungen ausgeführt werden könnten."
|
"sein. Es scheint, dass Anweisungen ausgeführt werden könnten."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Schließen"
|
msgstr "Schließen"
|
||||||
|
|
||||||
@ -275,6 +275,14 @@ msgstr "Der aktuell laufende Prozess in diesem geteilten Fenster wird beendet."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "In die Zwischenablage kopiert"
|
msgstr "In die Zwischenablage kopiert"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Hauptmenü"
|
msgstr "Hauptmenü"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-05-19 20:17-0300\n"
|
"PO-Revision-Date: 2025-05-19 20:17-0300\n"
|
||||||
"Last-Translator: Alan Moyano <alanmoyano203@gmail.com>\n"
|
"Last-Translator: Alan Moyano <alanmoyano203@gmail.com>\n"
|
||||||
"Language-Team: Argentinian <es@tp.org.es>\n"
|
"Language-Team: Argentinian <es@tp.org.es>\n"
|
||||||
@ -236,7 +236,7 @@ msgstr ""
|
|||||||
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
|
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
|
||||||
"algunos comandos podrían ejecutarse."
|
"algunos comandos podrían ejecutarse."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Cerrar"
|
msgstr "Cerrar"
|
||||||
|
|
||||||
@ -276,6 +276,14 @@ msgstr "El proceso actualmente en ejecución en esta división será terminado."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Copiado al portapapeles"
|
msgstr "Copiado al portapapeles"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Menú principal"
|
msgstr "Menú principal"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-28 17:46+0200\n"
|
"PO-Revision-Date: 2025-03-28 17:46+0200\n"
|
||||||
"Last-Translator: Miguel Peredo <miguelp@quientienemail.com>\n"
|
"Last-Translator: Miguel Peredo <miguelp@quientienemail.com>\n"
|
||||||
"Language-Team: Spanish <es@tp.org.es>\n"
|
"Language-Team: Spanish <es@tp.org.es>\n"
|
||||||
@ -236,7 +236,7 @@ msgstr ""
|
|||||||
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
|
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
|
||||||
"algunos comandos podrían ejecutarse."
|
"algunos comandos podrían ejecutarse."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Cerrar"
|
msgstr "Cerrar"
|
||||||
|
|
||||||
@ -276,6 +276,14 @@ msgstr "El proceso actualmente en ejecución en esta división será terminado."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Copiado al portapapeles"
|
msgstr "Copiado al portapapeles"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Menú principal"
|
msgstr "Menú principal"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-22 09:31+0100\n"
|
"PO-Revision-Date: 2025-03-22 09:31+0100\n"
|
||||||
"Last-Translator: Kirwiisp <swiip__@hotmail.com>\n"
|
"Last-Translator: Kirwiisp <swiip__@hotmail.com>\n"
|
||||||
"Language-Team: French <traduc@traduc.org>\n"
|
"Language-Team: French <traduc@traduc.org>\n"
|
||||||
@ -237,7 +237,7 @@ msgstr ""
|
|||||||
"Coller ce texte dans le terminal pourrait être dangereux, il semblerait que "
|
"Coller ce texte dans le terminal pourrait être dangereux, il semblerait que "
|
||||||
"certaines commandes pourraient être exécutées."
|
"certaines commandes pourraient être exécutées."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Fermer"
|
msgstr "Fermer"
|
||||||
|
|
||||||
@ -277,6 +277,14 @@ msgstr "Le processus en cours dans ce panneau va être arrêté."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Copié dans le presse-papiers"
|
msgstr "Copié dans le presse-papiers"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Menu principal"
|
msgstr "Menu principal"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-06-29 21:15+0100\n"
|
"PO-Revision-Date: 2025-06-29 21:15+0100\n"
|
||||||
"Last-Translator: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>\n"
|
"Last-Translator: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>\n"
|
||||||
"Language-Team: Irish <gaeilge-gnulinux@lists.sourceforge.net>\n"
|
"Language-Team: Irish <gaeilge-gnulinux@lists.sourceforge.net>\n"
|
||||||
@ -237,7 +237,7 @@ msgstr ""
|
|||||||
"D’fhéadfadh sé a bheith contúirteach an téacs seo a ghreamú isteach sa "
|
"D’fhéadfadh sé a bheith contúirteach an téacs seo a ghreamú isteach sa "
|
||||||
"teirminéal, toisc go d'fhéadfadh roinnt orduithe a fhorghníomhú."
|
"teirminéal, toisc go d'fhéadfadh roinnt orduithe a fhorghníomhú."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Dún"
|
msgstr "Dún"
|
||||||
|
|
||||||
@ -278,6 +278,14 @@ msgstr ""
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Cóipeáilte chuig an ghearrthaisce"
|
msgstr "Cóipeáilte chuig an ghearrthaisce"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Príomh-Roghchlár"
|
msgstr "Príomh-Roghchlár"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-13 00:00+0000\n"
|
"PO-Revision-Date: 2025-03-13 00:00+0000\n"
|
||||||
"Last-Translator: Sl (Shahaf Levi), Sl's Repository Ltd <ghostty@slsrepo."
|
"Last-Translator: Sl (Shahaf Levi), Sl's Repository Ltd <ghostty@slsrepo."
|
||||||
"com>\n"
|
"com>\n"
|
||||||
@ -234,7 +234,7 @@ msgstr ""
|
|||||||
"הדבקת טקסט זה במסוף עלולה להיות מסוכנת, מכיוון שככל הנראה היא תוביל להרצה של "
|
"הדבקת טקסט זה במסוף עלולה להיות מסוכנת, מכיוון שככל הנראה היא תוביל להרצה של "
|
||||||
"פקודות מסוימות."
|
"פקודות מסוימות."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "סגירה"
|
msgstr "סגירה"
|
||||||
|
|
||||||
@ -274,6 +274,14 @@ msgstr "התהליך שרץ כרגע בפיצול זה יסתיים."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "הועתק ללוח ההעתקה"
|
msgstr "הועתק ללוח ההעתקה"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "תפריט ראשי"
|
msgstr "תפריט ראשי"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-20 15:19+0700\n"
|
"PO-Revision-Date: 2025-03-20 15:19+0700\n"
|
||||||
"Last-Translator: Satrio Bayu Aji <halosatrio@gmail.com>\n"
|
"Last-Translator: Satrio Bayu Aji <halosatrio@gmail.com>\n"
|
||||||
"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
|
"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
|
||||||
@ -235,7 +235,7 @@ msgstr ""
|
|||||||
"Menempelkan teks ini ke terminal mungkin berbahaya karena sepertinya "
|
"Menempelkan teks ini ke terminal mungkin berbahaya karena sepertinya "
|
||||||
"beberapa perintah mungkin dijalankan."
|
"beberapa perintah mungkin dijalankan."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Tutup"
|
msgstr "Tutup"
|
||||||
|
|
||||||
@ -275,6 +275,14 @@ msgstr "Proses yang sedang berjalan dalam belahan ini akan diakhiri."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Disalin ke papan klip"
|
msgstr "Disalin ke papan klip"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Menu utama"
|
msgstr "Menu utama"
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-21 00:08+0900\n"
|
"PO-Revision-Date: 2025-03-21 00:08+0900\n"
|
||||||
"Last-Translator: Lon Sagisawa <lon@sagisawa.me>\n"
|
"Last-Translator: Lon Sagisawa <lon@sagisawa.me>\n"
|
||||||
"Language-Team: Japanese\n"
|
"Language-Team: Japanese\n"
|
||||||
@ -237,7 +237,7 @@ msgstr ""
|
|||||||
"このテキストには実行可能なコマンドが含まれており、ターミナルに貼り付けるのは"
|
"このテキストには実行可能なコマンドが含まれており、ターミナルに貼り付けるのは"
|
||||||
"危険な可能性があります。"
|
"危険な可能性があります。"
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "閉じる"
|
msgstr "閉じる"
|
||||||
|
|
||||||
@ -277,6 +277,14 @@ msgstr "分割ウィンドウ内のすべてのプロセスが終了します。
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "クリップボードにコピーしました"
|
msgstr "クリップボードにコピーしました"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "メインメニュー"
|
msgstr "メインメニュー"
|
||||||
|
@ -7,9 +7,9 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-31 03:08+0200\n"
|
"PO-Revision-Date: 2025-07-09 16:11-0400\n"
|
||||||
"Last-Translator: Ruben Engelbrecht <hey@rme.gg>\n"
|
"Last-Translator: Hojin You <dev.hojin@gmail.com>\n"
|
||||||
"Language-Team: Korean <translation-team-ko@googlegroups.com>\n"
|
"Language-Team: Korean <translation-team-ko@googlegroups.com>\n"
|
||||||
"Language: ko\n"
|
"Language: ko\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -87,7 +87,7 @@ msgstr "오른쪽으로 창 나누기"
|
|||||||
|
|
||||||
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
|
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
|
||||||
msgid "Execute a command…"
|
msgid "Execute a command…"
|
||||||
msgstr ""
|
msgstr "명령을 실행하세요…"
|
||||||
|
|
||||||
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
|
||||||
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
|
||||||
@ -160,7 +160,7 @@ msgstr "설정 열기"
|
|||||||
|
|
||||||
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
|
||||||
msgid "Command Palette"
|
msgid "Command Palette"
|
||||||
msgstr ""
|
msgstr "명령 팔레트"
|
||||||
|
|
||||||
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
|
||||||
msgid "Terminal Inspector"
|
msgid "Terminal Inspector"
|
||||||
@ -208,12 +208,12 @@ msgstr "허용"
|
|||||||
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
|
||||||
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
|
||||||
msgid "Remember choice for this split"
|
msgid "Remember choice for this split"
|
||||||
msgstr ""
|
msgstr "이 분할에 대한 선택 기억하기"
|
||||||
|
|
||||||
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
|
||||||
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
|
||||||
msgid "Reload configuration to show this prompt again"
|
msgid "Reload configuration to show this prompt again"
|
||||||
msgstr ""
|
msgstr "이 창을 다시 보려면 설정을 다시 불러오세요"
|
||||||
|
|
||||||
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
|
||||||
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
|
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
|
||||||
@ -236,7 +236,7 @@ msgstr ""
|
|||||||
"이 텍스트를 터미널에 붙여넣는 것은 위험할 수 있습니다. 일부 명령이 실행될 수 "
|
"이 텍스트를 터미널에 붙여넣는 것은 위험할 수 있습니다. 일부 명령이 실행될 수 "
|
||||||
"있는 것으로 보입니다."
|
"있는 것으로 보입니다."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "닫기"
|
msgstr "닫기"
|
||||||
|
|
||||||
@ -276,6 +276,14 @@ msgstr "이 분할에서 현재 실행 중인 프로세스가 종료됩니다."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "클립보드에 복사됨"
|
msgstr "클립보드에 복사됨"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "메인 메뉴"
|
msgstr "메인 메뉴"
|
||||||
@ -285,9 +293,8 @@ msgid "View Open Tabs"
|
|||||||
msgstr "열린 탭 보기"
|
msgstr "열린 탭 보기"
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:266
|
#: src/apprt/gtk/Window.zig:266
|
||||||
#, fuzzy
|
|
||||||
msgid "New Split"
|
msgid "New Split"
|
||||||
msgstr "나누기"
|
msgstr "새 분할"
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:329
|
#: src/apprt/gtk/Window.zig:329
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-23 14:17+0100\n"
|
"PO-Revision-Date: 2025-03-23 14:17+0100\n"
|
||||||
"Last-Translator: Andrej Daskalov <andrej.daskalov@gmail.com>\n"
|
"Last-Translator: Andrej Daskalov <andrej.daskalov@gmail.com>\n"
|
||||||
"Language-Team: Macedonian\n"
|
"Language-Team: Macedonian\n"
|
||||||
@ -236,7 +236,7 @@ msgstr ""
|
|||||||
"Вметнувањето на овој текст во терминалот може да биде опасно, бидејќи "
|
"Вметнувањето на овој текст во терминалот може да биде опасно, бидејќи "
|
||||||
"изгледа како да ќе се извршат одредени команди."
|
"изгледа како да ќе се извршат одредени команди."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Затвори"
|
msgstr "Затвори"
|
||||||
|
|
||||||
@ -276,6 +276,14 @@ msgstr "Процесот кој моментално се извршува во
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Копирано во привремена меморија"
|
msgstr "Копирано во привремена меморија"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Главно мени"
|
msgstr "Главно мени"
|
||||||
|
@ -10,7 +10,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-04-14 16:25+0200\n"
|
"PO-Revision-Date: 2025-04-14 16:25+0200\n"
|
||||||
"Last-Translator: cryptocode <cryptocode@zolo.io>\n"
|
"Last-Translator: cryptocode <cryptocode@zolo.io>\n"
|
||||||
"Language-Team: Norwegian Bokmal <l10n-no@lister.huftis.org>\n"
|
"Language-Team: Norwegian Bokmal <l10n-no@lister.huftis.org>\n"
|
||||||
@ -239,7 +239,7 @@ msgstr ""
|
|||||||
"Det ser ut som at kommandoer vil bli kjørt hvis du limer inn dette, vurder "
|
"Det ser ut som at kommandoer vil bli kjørt hvis du limer inn dette, vurder "
|
||||||
"om du mener det er trygt."
|
"om du mener det er trygt."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Lukk"
|
msgstr "Lukk"
|
||||||
|
|
||||||
@ -279,6 +279,14 @@ msgstr "Den kjørende prosessen for denne splitten vil bli avsluttet."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Kopiert til utklippstavlen"
|
msgstr "Kopiert til utklippstavlen"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Hovedmeny"
|
msgstr "Hovedmeny"
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-07-12 06:54+0200\n"
|
"PO-Revision-Date: 2025-07-12 06:54+0200\n"
|
||||||
"Last-Translator: Merijntje Tak <merijntje@tak.io>\n"
|
"Last-Translator: Merijntje Tak <merijntje@tak.io>\n"
|
||||||
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
|
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
|
||||||
@ -237,7 +237,7 @@ msgstr ""
|
|||||||
"Het plakken van deze tekst in de terminal is mogelijk gevaarlijk, omdat het "
|
"Het plakken van deze tekst in de terminal is mogelijk gevaarlijk, omdat het "
|
||||||
"lijkt op een commando dat uitgevoerd kan worden."
|
"lijkt op een commando dat uitgevoerd kan worden."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Afsluiten"
|
msgstr "Afsluiten"
|
||||||
|
|
||||||
@ -278,6 +278,14 @@ msgstr ""
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Gekopieerd naar klembord"
|
msgstr "Gekopieerd naar klembord"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Hoofdmenu"
|
msgstr "Hoofdmenu"
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-17 12:15+0100\n"
|
"PO-Revision-Date: 2025-03-17 12:15+0100\n"
|
||||||
"Last-Translator: Bartosz Sokorski <b.sokorski@gmail.com>\n"
|
"Last-Translator: Bartosz Sokorski <b.sokorski@gmail.com>\n"
|
||||||
"Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
|
"Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
|
||||||
@ -238,7 +238,7 @@ msgstr ""
|
|||||||
"Wklejenie tego tekstu do terminala może być niebezpieczne, ponieważ może "
|
"Wklejenie tego tekstu do terminala może być niebezpieczne, ponieważ może "
|
||||||
"spowodować wykonanie komend."
|
"spowodować wykonanie komend."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Zamknij"
|
msgstr "Zamknij"
|
||||||
|
|
||||||
@ -278,6 +278,14 @@ msgstr "Wszyskie trwające procesy w obecnym podziale zostaną zakończone."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Skopiowano do schowka"
|
msgstr "Skopiowano do schowka"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Menu główne"
|
msgstr "Menu główne"
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-06-20 10:19-0300\n"
|
"PO-Revision-Date: 2025-06-20 10:19-0300\n"
|
||||||
"Last-Translator: Mário Victor Ribeiro Silva <mariovictorrs@gmail.com>\n"
|
"Last-Translator: Mário Victor Ribeiro Silva <mariovictorrs@gmail.com>\n"
|
||||||
"Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
|
"Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
|
||||||
@ -238,7 +238,7 @@ msgstr ""
|
|||||||
"Colar esse texto em um terminal pode ser perigoso, pois parece que alguns "
|
"Colar esse texto em um terminal pode ser perigoso, pois parece que alguns "
|
||||||
"comandos podem ser executados."
|
"comandos podem ser executados."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Fechar"
|
msgstr "Fechar"
|
||||||
|
|
||||||
@ -278,6 +278,14 @@ msgstr "O processo atual rodando nessa divisão será finalizado."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Copiado para a área de transferência"
|
msgstr "Copiado para a área de transferência"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Menu Principal"
|
msgstr "Menu Principal"
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-24 00:01+0500\n"
|
"PO-Revision-Date: 2025-03-24 00:01+0500\n"
|
||||||
"Last-Translator: blackzeshi <sergey_zhuzhgov@mail.ru>\n"
|
"Last-Translator: blackzeshi <sergey_zhuzhgov@mail.ru>\n"
|
||||||
"Language-Team: Russian <gnu@d07.ru>\n"
|
"Language-Team: Russian <gnu@d07.ru>\n"
|
||||||
@ -237,7 +237,7 @@ msgstr ""
|
|||||||
"Вставка этого текста в терминал может быть опасной. Это выглядит как "
|
"Вставка этого текста в терминал может быть опасной. Это выглядит как "
|
||||||
"команды, которые могут быть исполнены."
|
"команды, которые могут быть исполнены."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Закрыть"
|
msgstr "Закрыть"
|
||||||
|
|
||||||
@ -277,6 +277,14 @@ msgstr "Процесс, работающий в этой сплит-област
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Скопировано в буфер обмена"
|
msgstr "Скопировано в буфер обмена"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Главное меню"
|
msgstr "Главное меню"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-24 22:01+0300\n"
|
"PO-Revision-Date: 2025-03-24 22:01+0300\n"
|
||||||
"Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
|
"Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
|
||||||
"Language-Team: Turkish\n"
|
"Language-Team: Turkish\n"
|
||||||
@ -237,7 +237,7 @@ msgstr ""
|
|||||||
"Bu metni uçbirime yapıştırmak tehlikeli olabilir; çünkü bir komut "
|
"Bu metni uçbirime yapıştırmak tehlikeli olabilir; çünkü bir komut "
|
||||||
"yürütülebilecekmiş gibi duruyor."
|
"yürütülebilecekmiş gibi duruyor."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Kapat"
|
msgstr "Kapat"
|
||||||
|
|
||||||
@ -277,6 +277,14 @@ msgstr "Bu bölmedeki şu anda çalışan süreç sonlandırılacaktır."
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Panoya kopyalandı"
|
msgstr "Panoya kopyalandı"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Ana Menü"
|
msgstr "Ana Menü"
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-03-16 20:16+0200\n"
|
"PO-Revision-Date: 2025-03-16 20:16+0200\n"
|
||||||
"Last-Translator: Danylo Zalizchuk <danilmail0110@gmail.com>\n"
|
"Last-Translator: Danylo Zalizchuk <danilmail0110@gmail.com>\n"
|
||||||
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
|
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
|
||||||
@ -238,7 +238,7 @@ msgstr ""
|
|||||||
"Вставка цього тексту в термінал може бути небезпечною, оскільки виглядає "
|
"Вставка цього тексту в термінал може бути небезпечною, оскільки виглядає "
|
||||||
"так, ніби деякі команди можуть бути виконані."
|
"так, ніби деякі команди можуть бути виконані."
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Закрити"
|
msgstr "Закрити"
|
||||||
|
|
||||||
@ -279,6 +279,14 @@ msgstr ""
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "Скопійовано в буфер обміну"
|
msgstr "Скопійовано в буфер обміну"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "Головне меню"
|
msgstr "Головне меню"
|
||||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: com.mitchellh.ghostty\n"
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
|
"POT-Creation-Date: 2025-07-11 22:56-0500\n"
|
||||||
"PO-Revision-Date: 2025-02-27 09:16+0100\n"
|
"PO-Revision-Date: 2025-02-27 09:16+0100\n"
|
||||||
"Last-Translator: Leah <hi@pluie.me>\n"
|
"Last-Translator: Leah <hi@pluie.me>\n"
|
||||||
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
|
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
|
||||||
@ -229,7 +229,7 @@ msgid ""
|
|||||||
"commands may be executed."
|
"commands may be executed."
|
||||||
msgstr "将以下内容粘贴至终端内将可能执行有害命令。"
|
msgstr "将以下内容粘贴至终端内将可能执行有害命令。"
|
||||||
|
|
||||||
#: src/apprt/gtk/CloseDialog.zig:47
|
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2520
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "关闭"
|
msgstr "关闭"
|
||||||
|
|
||||||
@ -269,6 +269,14 @@ msgstr "分屏内正在运行中的进程将被终止。"
|
|||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "已复制至剪贴板"
|
msgstr "已复制至剪贴板"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2514
|
||||||
|
msgid "Command succeeded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:2516
|
||||||
|
msgid "Command failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/apprt/gtk/Window.zig:216
|
#: src/apprt/gtk/Window.zig:216
|
||||||
msgid "Main Menu"
|
msgid "Main Menu"
|
||||||
msgstr "主菜单"
|
msgstr "主菜单"
|
||||||
|
@ -1011,8 +1011,18 @@ fn childExited(self: *Surface, info: apprt.surface.Message.ChildExited) void {
|
|||||||
|
|
||||||
log.warn("abnormal process exit detected, showing error message", .{});
|
log.warn("abnormal process exit detected, showing error message", .{});
|
||||||
|
|
||||||
// Update our terminal to note the abnormal exit. In the future we
|
// Try and show a GUI message. If it returns true, don't do anything else.
|
||||||
// may want the apprt to handle this to show some native GUI element.
|
if (self.rt_app.performAction(
|
||||||
|
.{ .surface = self },
|
||||||
|
.show_child_exited,
|
||||||
|
info,
|
||||||
|
) catch |err| gui: {
|
||||||
|
log.err("error trying to show native child exited GUI err={}", .{err});
|
||||||
|
break :gui false;
|
||||||
|
}) return;
|
||||||
|
|
||||||
|
// If a native GUI notification was not showm. update our terminal to
|
||||||
|
// note the abnormal exit.
|
||||||
self.childExitedAbnormally(info) catch |err| {
|
self.childExitedAbnormally(info) catch |err| {
|
||||||
log.err("error handling abnormal child exit err={}", .{err});
|
log.err("error handling abnormal child exit err={}", .{err});
|
||||||
return;
|
return;
|
||||||
@ -1028,6 +1038,18 @@ fn childExited(self: *Surface, info: apprt.surface.Message.ChildExited) void {
|
|||||||
// surface then they will see this message and know the process has
|
// surface then they will see this message and know the process has
|
||||||
// completed.
|
// completed.
|
||||||
terminal: {
|
terminal: {
|
||||||
|
// First try and show a native GUI message.
|
||||||
|
if (self.rt_app.performAction(
|
||||||
|
.{ .surface = self },
|
||||||
|
.show_child_exited,
|
||||||
|
info,
|
||||||
|
) catch |err| gui: {
|
||||||
|
log.err("error trying to show native child exited GUI err={}", .{err});
|
||||||
|
break :gui false;
|
||||||
|
}) break :terminal;
|
||||||
|
|
||||||
|
// If the native GUI can't be shown, display a text message in the
|
||||||
|
// terminal.
|
||||||
self.renderer_state.mutex.lock();
|
self.renderer_state.mutex.lock();
|
||||||
defer self.renderer_state.mutex.unlock();
|
defer self.renderer_state.mutex.unlock();
|
||||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||||
|
@ -272,6 +272,9 @@ pub const Action = union(Key) {
|
|||||||
/// apprt.
|
/// apprt.
|
||||||
open_url: OpenUrl,
|
open_url: OpenUrl,
|
||||||
|
|
||||||
|
/// Show a native GUI notification that the child process has exited.
|
||||||
|
show_child_exited: apprt.surface.Message.ChildExited,
|
||||||
|
|
||||||
/// Sync with: ghostty_action_tag_e
|
/// Sync with: ghostty_action_tag_e
|
||||||
pub const Key = enum(c_int) {
|
pub const Key = enum(c_int) {
|
||||||
quit,
|
quit,
|
||||||
@ -323,6 +326,7 @@ pub const Action = union(Key) {
|
|||||||
redo,
|
redo,
|
||||||
check_for_updates,
|
check_for_updates,
|
||||||
open_url,
|
open_url,
|
||||||
|
show_child_exited,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Sync with: ghostty_action_u
|
/// Sync with: ghostty_action_u
|
||||||
|
@ -521,6 +521,7 @@ pub fn performAction(
|
|||||||
.ring_bell => try self.ringBell(target),
|
.ring_bell => try self.ringBell(target),
|
||||||
.toggle_command_palette => try self.toggleCommandPalette(target),
|
.toggle_command_palette => try self.toggleCommandPalette(target),
|
||||||
.open_url => self.openUrl(value),
|
.open_url => self.openUrl(value),
|
||||||
|
.show_child_exited => return try self.showChildExited(target, value),
|
||||||
|
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
.close_all_windows,
|
.close_all_windows,
|
||||||
@ -846,6 +847,13 @@ fn toggleCommandPalette(_: *App, target: apprt.Target) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn showChildExited(_: *App, target: apprt.Target, value: apprt.surface.Message.ChildExited) error{}!bool {
|
||||||
|
switch (target) {
|
||||||
|
.app => return false,
|
||||||
|
.surface => |surface| return try surface.rt_surface.showChildExited(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
|
fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
.start => self.startQuitTimer(),
|
.start => self.startQuitTimer(),
|
||||||
|
@ -2503,3 +2503,40 @@ fn gtkStreamError(media_file: *gtk.MediaFile, _: *gobject.ParamSpec, _: ?*anyopa
|
|||||||
fn gtkStreamEnded(media_file: *gtk.MediaFile, _: *gobject.ParamSpec, _: ?*anyopaque) callconv(.c) void {
|
fn gtkStreamEnded(media_file: *gtk.MediaFile, _: *gobject.ParamSpec, _: ?*anyopaque) callconv(.c) void {
|
||||||
media_file.unref();
|
media_file.unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show native GUI element with a notification that the child process has
|
||||||
|
/// closed. Return `true` if we are able to show the GUI notification, and
|
||||||
|
/// `false` if we are not.
|
||||||
|
pub fn showChildExited(self: *Surface, info: apprt.surface.Message.ChildExited) error{}!bool {
|
||||||
|
if (!adw_version.supportsBanner()) return false;
|
||||||
|
|
||||||
|
const warning_text, const css_class = if (info.exit_code == 0)
|
||||||
|
.{ i18n._("Command succeeded"), "child_exited_normally" }
|
||||||
|
else
|
||||||
|
.{ i18n._("Command failed"), "child_exited_abnormally" };
|
||||||
|
|
||||||
|
const banner = adw.Banner.new(warning_text);
|
||||||
|
banner.setRevealed(1);
|
||||||
|
banner.setButtonLabel(i18n._("Close"));
|
||||||
|
|
||||||
|
_ = adw.Banner.signals.button_clicked.connect(
|
||||||
|
banner,
|
||||||
|
*Surface,
|
||||||
|
showChildExitedButtonClosed,
|
||||||
|
self,
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
|
||||||
|
const banner_widget = banner.as(gtk.Widget);
|
||||||
|
banner_widget.setHalign(.fill);
|
||||||
|
banner_widget.setValign(.end);
|
||||||
|
banner_widget.addCssClass(css_class);
|
||||||
|
|
||||||
|
self.overlay.addOverlay(banner_widget);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn showChildExitedButtonClosed(_: *adw.Banner, self: *Surface) callconv(.c) void {
|
||||||
|
self.close(false);
|
||||||
|
}
|
||||||
|
@ -93,3 +93,15 @@ window.ssd.no-border-radius {
|
|||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
banner.child_exited_normally revealer widget {
|
||||||
|
background-color: rgba(38, 162, 105, 0.5);
|
||||||
|
/* after GTK 4.16 is a requirement, switch to the following:
|
||||||
|
/* background-color: color-mix(in srgb, var(--success-bg-color), transparent 50%); */
|
||||||
|
}
|
||||||
|
|
||||||
|
banner.child_exited_abnormally revealer widget {
|
||||||
|
background-color: rgba(192, 28, 40, 0.5);
|
||||||
|
/* after GTK 4.16 is a requirement, switch to the following:
|
||||||
|
/* background-color: color-mix(in srgb, var(--error-bg-color), transparent 50%); */
|
||||||
|
}
|
||||||
|
@ -98,7 +98,7 @@ pub const Message = union(enum) {
|
|||||||
// This enum is a placeholder for future title styles.
|
// This enum is a placeholder for future title styles.
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ChildExited = struct {
|
pub const ChildExited = extern struct {
|
||||||
exit_code: u32,
|
exit_code: u32,
|
||||||
runtime_ms: u64,
|
runtime_ms: u64,
|
||||||
};
|
};
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# This is a trivial helper script to help run the codepoint-width benchmark.
|
|
||||||
# You probably want to tweak this script depending on what you're
|
|
||||||
# trying to measure.
|
|
||||||
|
|
||||||
# Options:
|
|
||||||
# - "ascii", uniform random ASCII bytes
|
|
||||||
# - "utf8", uniform random unicode characters, encoded as utf8
|
|
||||||
# - "rand", pure random data, will contain many invalid code sequences.
|
|
||||||
DATA="utf8"
|
|
||||||
SIZE="25000000"
|
|
||||||
|
|
||||||
# Add additional arguments
|
|
||||||
ARGS=""
|
|
||||||
|
|
||||||
# Generate the benchmark input ahead of time so it's not included in the time.
|
|
||||||
./zig-out/bin/bench-stream --mode=gen-$DATA | head -c $SIZE > /tmp/ghostty_bench_data
|
|
||||||
#cat ~/Downloads/JAPANESEBIBLE.txt > /tmp/ghostty_bench_data
|
|
||||||
|
|
||||||
# Uncomment to instead use the contents of `stream.txt` as input.
|
|
||||||
# yes $(cat ./stream.txt) | head -c $SIZE > /tmp/ghostty_bench_data
|
|
||||||
|
|
||||||
hyperfine \
|
|
||||||
--warmup 10 \
|
|
||||||
-n noop \
|
|
||||||
"./zig-out/bin/bench-codepoint-width --mode=noop${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n wcwidth \
|
|
||||||
"./zig-out/bin/bench-codepoint-width --mode=wcwidth${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n table \
|
|
||||||
"./zig-out/bin/bench-codepoint-width --mode=table${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n simd \
|
|
||||||
"./zig-out/bin/bench-codepoint-width --mode=simd${ARGS} </tmp/ghostty_bench_data"
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
|||||||
//! This benchmark tests the throughput of codepoint width calculation.
|
|
||||||
//! This is a common operation in terminal character printing and the
|
|
||||||
//! motivating factor to write this benchmark was discovering that our
|
|
||||||
//! codepoint width function was 30% of the runtime of every character
|
|
||||||
//! print.
|
|
||||||
//!
|
|
||||||
//! This will consume all of the available stdin, so you should run it
|
|
||||||
//! with `head` in a pipe to restrict. For example, to test ASCII input:
|
|
||||||
//!
|
|
||||||
//! bench-stream --mode=gen-ascii | head -c 50M | bench-codepoint-width --mode=ziglyph
|
|
||||||
//!
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
|
||||||
const ziglyph = @import("ziglyph");
|
|
||||||
const cli = @import("../cli.zig");
|
|
||||||
const simd = @import("../simd/main.zig");
|
|
||||||
const table = @import("../unicode/main.zig").table;
|
|
||||||
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
|
|
||||||
|
|
||||||
const Args = struct {
|
|
||||||
mode: Mode = .noop,
|
|
||||||
|
|
||||||
/// The size for read buffers. Doesn't usually need to be changed. The
|
|
||||||
/// main point is to make this runtime known so we can avoid compiler
|
|
||||||
/// optimizations.
|
|
||||||
@"buffer-size": usize = 4096,
|
|
||||||
|
|
||||||
/// This is set by the CLI parser for deinit.
|
|
||||||
_arena: ?ArenaAllocator = null,
|
|
||||||
|
|
||||||
pub fn deinit(self: *Args) void {
|
|
||||||
if (self._arena) |arena| arena.deinit();
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Mode = enum {
|
|
||||||
/// The baseline mode copies the data from the fd into a buffer. This
|
|
||||||
/// is used to show the minimal overhead of reading the fd into memory
|
|
||||||
/// and establishes a baseline for the other modes.
|
|
||||||
noop,
|
|
||||||
|
|
||||||
/// libc wcwidth
|
|
||||||
wcwidth,
|
|
||||||
|
|
||||||
/// Use ziglyph library to calculate the display width of each codepoint.
|
|
||||||
ziglyph,
|
|
||||||
|
|
||||||
/// Our SIMD implementation.
|
|
||||||
simd,
|
|
||||||
|
|
||||||
/// Test our lookup table implementation.
|
|
||||||
table,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
|
||||||
.log_level = .debug,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
// We want to use the c allocator because it is much faster than GPA.
|
|
||||||
const alloc = std.heap.c_allocator;
|
|
||||||
|
|
||||||
// Parse our args
|
|
||||||
var args: Args = .{};
|
|
||||||
defer args.deinit();
|
|
||||||
{
|
|
||||||
var iter = try cli.args.argsIterator(alloc);
|
|
||||||
defer iter.deinit();
|
|
||||||
try cli.args.parse(Args, alloc, &args, &iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = std.io.getStdIn().reader();
|
|
||||||
const buf = try alloc.alloc(u8, args.@"buffer-size");
|
|
||||||
|
|
||||||
// Handle the modes that do not depend on terminal state first.
|
|
||||||
switch (args.mode) {
|
|
||||||
.noop => try benchNoop(reader, buf),
|
|
||||||
.wcwidth => try benchWcwidth(reader, buf),
|
|
||||||
.ziglyph => try benchZiglyph(reader, buf),
|
|
||||||
.simd => try benchSimd(reader, buf),
|
|
||||||
.table => try benchTable(reader, buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchNoop(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
_ = d.next(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "c" fn wcwidth(c: u32) c_int;
|
|
||||||
|
|
||||||
noinline fn benchWcwidth(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
const cp_, const consumed = d.next(c);
|
|
||||||
assert(consumed);
|
|
||||||
if (cp_) |cp| {
|
|
||||||
const width = wcwidth(cp);
|
|
||||||
|
|
||||||
// Write the width to the buffer to avoid it being compiled away
|
|
||||||
buf[0] = @intCast(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchTable(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
const cp_, const consumed = d.next(c);
|
|
||||||
assert(consumed);
|
|
||||||
if (cp_) |cp| {
|
|
||||||
// This is the same trick we do in terminal.zig so we
|
|
||||||
// keep it here.
|
|
||||||
const width = if (cp <= 0xFF) 1 else table.get(@intCast(cp)).width;
|
|
||||||
|
|
||||||
// Write the width to the buffer to avoid it being compiled away
|
|
||||||
buf[0] = @intCast(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchZiglyph(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
const cp_, const consumed = d.next(c);
|
|
||||||
assert(consumed);
|
|
||||||
if (cp_) |cp| {
|
|
||||||
const width = ziglyph.display_width.codePointWidth(cp, .half);
|
|
||||||
|
|
||||||
// Write the width to the buffer to avoid it being compiled away
|
|
||||||
buf[0] = @intCast(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchSimd(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
const cp_, const consumed = d.next(c);
|
|
||||||
assert(consumed);
|
|
||||||
if (cp_) |cp| {
|
|
||||||
const width = simd.codepointWidth(cp);
|
|
||||||
|
|
||||||
// Write the width to the buffer to avoid it being compiled away
|
|
||||||
buf[0] = @intCast(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# This is a trivial helper script to help run the grapheme-break benchmark.
|
|
||||||
# You probably want to tweak this script depending on what you're
|
|
||||||
# trying to measure.
|
|
||||||
|
|
||||||
# Options:
|
|
||||||
# - "ascii", uniform random ASCII bytes
|
|
||||||
# - "utf8", uniform random unicode characters, encoded as utf8
|
|
||||||
# - "rand", pure random data, will contain many invalid code sequences.
|
|
||||||
DATA="utf8"
|
|
||||||
SIZE="25000000"
|
|
||||||
|
|
||||||
# Add additional arguments
|
|
||||||
ARGS=""
|
|
||||||
|
|
||||||
# Generate the benchmark input ahead of time so it's not included in the time.
|
|
||||||
./zig-out/bin/bench-stream --mode=gen-$DATA | head -c $SIZE > /tmp/ghostty_bench_data
|
|
||||||
#cat ~/Downloads/JAPANESEBIBLE.txt > /tmp/ghostty_bench_data
|
|
||||||
|
|
||||||
# Uncomment to instead use the contents of `stream.txt` as input.
|
|
||||||
# yes $(cat ./stream.txt) | head -c $SIZE > /tmp/ghostty_bench_data
|
|
||||||
|
|
||||||
hyperfine \
|
|
||||||
--warmup 10 \
|
|
||||||
-n noop \
|
|
||||||
"./zig-out/bin/bench-grapheme-break --mode=noop${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n ziglyph \
|
|
||||||
"./zig-out/bin/bench-grapheme-break --mode=ziglyph${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n table \
|
|
||||||
"./zig-out/bin/bench-grapheme-break --mode=table${ARGS} </tmp/ghostty_bench_data"
|
|
||||||
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
|||||||
//! This benchmark tests the throughput of grapheme break calculation.
|
|
||||||
//! This is a common operation in terminal character printing for terminals
|
|
||||||
//! that support grapheme clustering.
|
|
||||||
//!
|
|
||||||
//! This will consume all of the available stdin, so you should run it
|
|
||||||
//! with `head` in a pipe to restrict. For example, to test ASCII input:
|
|
||||||
//!
|
|
||||||
//! bench-stream --mode=gen-ascii | head -c 50M | bench-grapheme-break --mode=ziglyph
|
|
||||||
//!
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
|
||||||
const ziglyph = @import("ziglyph");
|
|
||||||
const cli = @import("../cli.zig");
|
|
||||||
const simd = @import("../simd/main.zig");
|
|
||||||
const unicode = @import("../unicode/main.zig");
|
|
||||||
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
|
|
||||||
|
|
||||||
const Args = struct {
|
|
||||||
mode: Mode = .noop,
|
|
||||||
|
|
||||||
/// The size for read buffers. Doesn't usually need to be changed. The
|
|
||||||
/// main point is to make this runtime known so we can avoid compiler
|
|
||||||
/// optimizations.
|
|
||||||
@"buffer-size": usize = 4096,
|
|
||||||
|
|
||||||
/// This is set by the CLI parser for deinit.
|
|
||||||
_arena: ?ArenaAllocator = null,
|
|
||||||
|
|
||||||
pub fn deinit(self: *Args) void {
|
|
||||||
if (self._arena) |arena| arena.deinit();
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Mode = enum {
|
|
||||||
/// The baseline mode copies the data from the fd into a buffer. This
|
|
||||||
/// is used to show the minimal overhead of reading the fd into memory
|
|
||||||
/// and establishes a baseline for the other modes.
|
|
||||||
noop,
|
|
||||||
|
|
||||||
/// Use ziglyph library to calculate the display width of each codepoint.
|
|
||||||
ziglyph,
|
|
||||||
|
|
||||||
/// Ghostty's table-based approach.
|
|
||||||
table,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
|
||||||
.log_level = .debug,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
// We want to use the c allocator because it is much faster than GPA.
|
|
||||||
const alloc = std.heap.c_allocator;
|
|
||||||
|
|
||||||
// Parse our args
|
|
||||||
var args: Args = .{};
|
|
||||||
defer args.deinit();
|
|
||||||
{
|
|
||||||
var iter = try cli.args.argsIterator(alloc);
|
|
||||||
defer iter.deinit();
|
|
||||||
try cli.args.parse(Args, alloc, &args, &iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = std.io.getStdIn().reader();
|
|
||||||
const buf = try alloc.alloc(u8, args.@"buffer-size");
|
|
||||||
|
|
||||||
// Handle the modes that do not depend on terminal state first.
|
|
||||||
switch (args.mode) {
|
|
||||||
.noop => try benchNoop(reader, buf),
|
|
||||||
.ziglyph => try benchZiglyph(reader, buf),
|
|
||||||
.table => try benchTable(reader, buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchNoop(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
_ = d.next(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchTable(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
var state: unicode.GraphemeBreakState = .{};
|
|
||||||
var cp1: u21 = 0;
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
const cp_, const consumed = d.next(c);
|
|
||||||
assert(consumed);
|
|
||||||
if (cp_) |cp2| {
|
|
||||||
const v = unicode.graphemeBreak(cp1, @intCast(cp2), &state);
|
|
||||||
buf[0] = @intCast(@intFromBool(v));
|
|
||||||
cp1 = cp2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchZiglyph(
|
|
||||||
reader: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
var d: UTF8Decoder = .{};
|
|
||||||
var state: u3 = 0;
|
|
||||||
var cp1: u21 = 0;
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| {
|
|
||||||
const cp_, const consumed = d.next(c);
|
|
||||||
assert(consumed);
|
|
||||||
if (cp_) |cp2| {
|
|
||||||
const v = ziglyph.graphemeBreak(cp1, @intCast(cp2), &state);
|
|
||||||
buf[0] = @intCast(@intFromBool(v));
|
|
||||||
cp1 = cp2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# This is a trivial helper script to help run the page init benchmark.
|
|
||||||
# You probably want to tweak this script depending on what you're
|
|
||||||
# trying to measure.
|
|
||||||
|
|
||||||
# Uncomment to test with an active terminal state.
|
|
||||||
# ARGS=" --terminal"
|
|
||||||
|
|
||||||
hyperfine \
|
|
||||||
--warmup 10 \
|
|
||||||
-n alloc \
|
|
||||||
"./zig-out/bin/bench-page-init --mode=alloc${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n pool \
|
|
||||||
"./zig-out/bin/bench-page-init --mode=pool${ARGS} </tmp/ghostty_bench_data"
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
|||||||
//! This benchmark tests the speed to create a terminal "page". This is
|
|
||||||
//! the internal data structure backing a terminal screen. The creation speed
|
|
||||||
//! is important because it is one of the primary bottlenecks for processing
|
|
||||||
//! large amounts of plaintext data.
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
|
||||||
const cli = @import("../cli.zig");
|
|
||||||
const terminal_new = @import("../terminal/main.zig");
|
|
||||||
|
|
||||||
const Args = struct {
|
|
||||||
mode: Mode = .alloc,
|
|
||||||
|
|
||||||
/// The number of pages to create sequentially.
|
|
||||||
count: usize = 10_000,
|
|
||||||
|
|
||||||
/// This is set by the CLI parser for deinit.
|
|
||||||
_arena: ?ArenaAllocator = null,
|
|
||||||
|
|
||||||
pub fn deinit(self: *Args) void {
|
|
||||||
if (self._arena) |arena| arena.deinit();
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Mode = enum {
|
|
||||||
/// The default allocation strategy of the structure.
|
|
||||||
alloc,
|
|
||||||
|
|
||||||
/// Use a memory pool to allocate pages from a backing buffer.
|
|
||||||
pool,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
|
||||||
.log_level = .debug,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
// We want to use the c allocator because it is much faster than GPA.
|
|
||||||
const alloc = std.heap.c_allocator;
|
|
||||||
|
|
||||||
// Parse our args
|
|
||||||
var args: Args = .{};
|
|
||||||
defer args.deinit();
|
|
||||||
{
|
|
||||||
var iter = try cli.args.argsIterator(alloc);
|
|
||||||
defer iter.deinit();
|
|
||||||
try cli.args.parse(Args, alloc, &args, &iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the modes that do not depend on terminal state first.
|
|
||||||
switch (args.mode) {
|
|
||||||
.alloc => try benchAlloc(args.count),
|
|
||||||
.pool => try benchPool(alloc, args.count),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchAlloc(count: usize) !void {
|
|
||||||
for (0..count) |_| {
|
|
||||||
_ = try terminal_new.Page.init(terminal_new.page.std_capacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchPool(alloc: Allocator, count: usize) !void {
|
|
||||||
var list = try terminal_new.PageList.init(
|
|
||||||
alloc,
|
|
||||||
terminal_new.page.std_capacity.cols,
|
|
||||||
terminal_new.page.std_capacity.rows,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
defer list.deinit();
|
|
||||||
|
|
||||||
for (0..count) |_| {
|
|
||||||
_ = try list.grow();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
//! This benchmark tests the throughput of the terminal escape code parser.
|
|
||||||
//!
|
|
||||||
//! To benchmark, this takes an input stream (which is expected to come in
|
|
||||||
//! as fast as possible), runs it through the parser, and does nothing
|
|
||||||
//! with the parse result. This bottlenecks and tests the throughput of the
|
|
||||||
//! parser.
|
|
||||||
//!
|
|
||||||
//! Usage:
|
|
||||||
//!
|
|
||||||
//! "--f=<path>" - A file to read to parse. If path is "-" then stdin
|
|
||||||
//! is read. Required.
|
|
||||||
//!
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
|
||||||
const cli = @import("../cli.zig");
|
|
||||||
const terminal = @import("../terminal/main.zig");
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
// Just use a GPA
|
|
||||||
const GPA = std.heap.GeneralPurposeAllocator(.{});
|
|
||||||
var gpa = GPA{};
|
|
||||||
defer _ = gpa.deinit();
|
|
||||||
const alloc = gpa.allocator();
|
|
||||||
|
|
||||||
// Parse our args
|
|
||||||
var args: Args = args: {
|
|
||||||
var args: Args = .{};
|
|
||||||
errdefer args.deinit();
|
|
||||||
var iter = try cli.args.argsIterator(alloc);
|
|
||||||
defer iter.deinit();
|
|
||||||
try cli.args.parse(Args, alloc, &args, &iter);
|
|
||||||
break :args args;
|
|
||||||
};
|
|
||||||
defer args.deinit();
|
|
||||||
|
|
||||||
// Read the file for our input
|
|
||||||
const file = file: {
|
|
||||||
if (std.mem.eql(u8, args.f, "-"))
|
|
||||||
break :file std.io.getStdIn();
|
|
||||||
|
|
||||||
@panic("file reading not implemented yet");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Read all into memory (TODO: support buffers one day)
|
|
||||||
const input = try file.reader().readAllAlloc(
|
|
||||||
alloc,
|
|
||||||
1024 * 1024 * 1024 * 1024 * 16, // 16 GB
|
|
||||||
);
|
|
||||||
defer alloc.free(input);
|
|
||||||
|
|
||||||
// Run our parser
|
|
||||||
var p: terminal.Parser = .{};
|
|
||||||
for (input) |c| {
|
|
||||||
const actions = p.next(c);
|
|
||||||
//std.log.warn("actions={any}", .{actions});
|
|
||||||
_ = actions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Args = struct {
|
|
||||||
f: []const u8 = "-",
|
|
||||||
|
|
||||||
/// This is set by the CLI parser for deinit.
|
|
||||||
_arena: ?ArenaAllocator = null,
|
|
||||||
|
|
||||||
pub fn deinit(self: *Args) void {
|
|
||||||
if (self._arena) |arena| arena.deinit();
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# This is a trivial helper script to help run the stream benchmark.
|
|
||||||
# You probably want to tweak this script depending on what you're
|
|
||||||
# trying to measure.
|
|
||||||
|
|
||||||
# Options:
|
|
||||||
# - "ascii", uniform random ASCII bytes
|
|
||||||
# - "utf8", uniform random unicode characters, encoded as utf8
|
|
||||||
# - "rand", pure random data, will contain many invalid code sequences.
|
|
||||||
DATA="ascii"
|
|
||||||
SIZE="25000000"
|
|
||||||
|
|
||||||
# Uncomment to test with an active terminal state.
|
|
||||||
# ARGS=" --terminal"
|
|
||||||
|
|
||||||
# Generate the benchmark input ahead of time so it's not included in the time.
|
|
||||||
./zig-out/bin/bench-stream --mode=gen-$DATA | head -c $SIZE > /tmp/ghostty_bench_data
|
|
||||||
|
|
||||||
# Uncomment to instead use the contents of `stream.txt` as input. (Ignores SIZE)
|
|
||||||
# echo $(cat ./stream.txt) > /tmp/ghostty_bench_data
|
|
||||||
|
|
||||||
hyperfine \
|
|
||||||
--warmup 10 \
|
|
||||||
-n memcpy \
|
|
||||||
"./zig-out/bin/bench-stream --mode=noop${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n scalar \
|
|
||||||
"./zig-out/bin/bench-stream --mode=scalar${ARGS} </tmp/ghostty_bench_data" \
|
|
||||||
-n simd \
|
|
||||||
"./zig-out/bin/bench-stream --mode=simd${ARGS} </tmp/ghostty_bench_data"
|
|
@ -1,253 +0,0 @@
|
|||||||
//! This benchmark tests the throughput of the VT stream. It has a few
|
|
||||||
//! modes in order to test different methods of stream processing. It
|
|
||||||
//! provides a "noop" mode to give us the `memcpy` speed.
|
|
||||||
//!
|
|
||||||
//! This will consume all of the available stdin, so you should run it
|
|
||||||
//! with `head` in a pipe to restrict. For example, to test ASCII input:
|
|
||||||
//!
|
|
||||||
//! bench-stream --mode=gen-ascii | head -c 50M | bench-stream --mode=simd
|
|
||||||
//!
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
|
||||||
const cli = @import("../cli.zig");
|
|
||||||
const terminal = @import("../terminal/main.zig");
|
|
||||||
const synthetic = @import("../synthetic/main.zig");
|
|
||||||
|
|
||||||
const Args = struct {
|
|
||||||
mode: Mode = .noop,
|
|
||||||
|
|
||||||
/// The PRNG seed used by the input generators.
|
|
||||||
/// -1 uses a random seed (default)
|
|
||||||
seed: i64 = -1,
|
|
||||||
|
|
||||||
/// Process input with a real terminal. This will be MUCH slower than
|
|
||||||
/// the other modes because it has to maintain terminal state but will
|
|
||||||
/// help get more realistic numbers.
|
|
||||||
terminal: Terminal = .none,
|
|
||||||
@"terminal-rows": usize = 80,
|
|
||||||
@"terminal-cols": usize = 120,
|
|
||||||
|
|
||||||
/// The size for read buffers. Doesn't usually need to be changed. The
|
|
||||||
/// main point is to make this runtime known so we can avoid compiler
|
|
||||||
/// optimizations.
|
|
||||||
@"buffer-size": usize = 4096,
|
|
||||||
|
|
||||||
/// This is set by the CLI parser for deinit.
|
|
||||||
_arena: ?ArenaAllocator = null,
|
|
||||||
|
|
||||||
pub fn deinit(self: *Args) void {
|
|
||||||
if (self._arena) |arena| arena.deinit();
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Terminal = enum { none, new };
|
|
||||||
};
|
|
||||||
|
|
||||||
const Mode = enum {
|
|
||||||
// Do nothing, just read from stdin into a stack-allocated buffer.
|
|
||||||
// This is used to benchmark our base-case: it gives us our maximum
|
|
||||||
// throughput on a basic read.
|
|
||||||
noop,
|
|
||||||
|
|
||||||
// These benchmark the throughput of the terminal stream parsing
|
|
||||||
// with and without SIMD. The "simd" option will use whatever is best
|
|
||||||
// for the running platform.
|
|
||||||
//
|
|
||||||
// Note that these run through the full VT parser but do not apply
|
|
||||||
// the operations to terminal state, so there is no terminal state
|
|
||||||
// overhead.
|
|
||||||
scalar,
|
|
||||||
simd,
|
|
||||||
|
|
||||||
// Generate an infinite stream of random printable ASCII characters.
|
|
||||||
@"gen-ascii",
|
|
||||||
|
|
||||||
// Generate an infinite stream of random printable unicode characters.
|
|
||||||
@"gen-utf8",
|
|
||||||
|
|
||||||
// Generate an infinite stream of arbitrary random bytes.
|
|
||||||
@"gen-rand",
|
|
||||||
|
|
||||||
// Generate an infinite stream of OSC requests. These will be mixed
|
|
||||||
// with valid and invalid OSC requests by default, but the
|
|
||||||
// `-valid` and `-invalid`-suffixed variants can be used to get only
|
|
||||||
// a specific type of OSC request.
|
|
||||||
@"gen-osc",
|
|
||||||
@"gen-osc-valid",
|
|
||||||
@"gen-osc-invalid",
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
|
||||||
.log_level = .debug,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
// We want to use the c allocator because it is much faster than GPA.
|
|
||||||
const alloc = std.heap.c_allocator;
|
|
||||||
|
|
||||||
// Parse our args
|
|
||||||
var args: Args = .{};
|
|
||||||
defer args.deinit();
|
|
||||||
{
|
|
||||||
var iter = try cli.args.argsIterator(alloc);
|
|
||||||
defer iter.deinit();
|
|
||||||
try cli.args.parse(Args, alloc, &args, &iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = std.io.getStdIn().reader();
|
|
||||||
const writer = std.io.getStdOut().writer();
|
|
||||||
const buf = try alloc.alloc(u8, args.@"buffer-size");
|
|
||||||
|
|
||||||
// Build our RNG
|
|
||||||
const seed: u64 = if (args.seed >= 0) @bitCast(args.seed) else @truncate(@as(u128, @bitCast(std.time.nanoTimestamp())));
|
|
||||||
var prng = std.Random.DefaultPrng.init(seed);
|
|
||||||
const rand = prng.random();
|
|
||||||
|
|
||||||
// Handle the modes that do not depend on terminal state first.
|
|
||||||
switch (args.mode) {
|
|
||||||
.@"gen-ascii" => {
|
|
||||||
var gen: synthetic.Bytes = .{
|
|
||||||
.rand = rand,
|
|
||||||
.alphabet = synthetic.Bytes.Alphabet.ascii,
|
|
||||||
};
|
|
||||||
try generate(writer, gen.generator());
|
|
||||||
},
|
|
||||||
|
|
||||||
.@"gen-utf8" => {
|
|
||||||
var gen: synthetic.Utf8 = .{
|
|
||||||
.rand = rand,
|
|
||||||
};
|
|
||||||
try generate(writer, gen.generator());
|
|
||||||
},
|
|
||||||
|
|
||||||
.@"gen-rand" => {
|
|
||||||
var gen: synthetic.Bytes = .{ .rand = rand };
|
|
||||||
try generate(writer, gen.generator());
|
|
||||||
},
|
|
||||||
|
|
||||||
.@"gen-osc" => {
|
|
||||||
var gen: synthetic.Osc = .{
|
|
||||||
.rand = rand,
|
|
||||||
.p_valid = 0.5,
|
|
||||||
};
|
|
||||||
try generate(writer, gen.generator());
|
|
||||||
},
|
|
||||||
|
|
||||||
.@"gen-osc-valid" => {
|
|
||||||
var gen: synthetic.Osc = .{
|
|
||||||
.rand = rand,
|
|
||||||
.p_valid = 1.0,
|
|
||||||
};
|
|
||||||
try generate(writer, gen.generator());
|
|
||||||
},
|
|
||||||
|
|
||||||
.@"gen-osc-invalid" => {
|
|
||||||
var gen: synthetic.Osc = .{
|
|
||||||
.rand = rand,
|
|
||||||
.p_valid = 0.0,
|
|
||||||
};
|
|
||||||
try generate(writer, gen.generator());
|
|
||||||
},
|
|
||||||
|
|
||||||
.noop => try benchNoop(reader, buf),
|
|
||||||
|
|
||||||
// Handle the ones that depend on terminal state next
|
|
||||||
inline .scalar,
|
|
||||||
.simd,
|
|
||||||
=> |tag| switch (args.terminal) {
|
|
||||||
.new => {
|
|
||||||
const TerminalStream = terminal.Stream(*TerminalHandler);
|
|
||||||
var t = try terminal.Terminal.init(alloc, .{
|
|
||||||
.cols = @intCast(args.@"terminal-cols"),
|
|
||||||
.rows = @intCast(args.@"terminal-rows"),
|
|
||||||
});
|
|
||||||
var handler: TerminalHandler = .{ .t = &t };
|
|
||||||
var stream: TerminalStream = .{ .handler = &handler };
|
|
||||||
switch (tag) {
|
|
||||||
.scalar => try benchScalar(reader, &stream, buf),
|
|
||||||
.simd => try benchSimd(reader, &stream, buf),
|
|
||||||
else => @compileError("missing case"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.none => {
|
|
||||||
var stream: terminal.Stream(NoopHandler) = .{ .handler = .{} };
|
|
||||||
switch (tag) {
|
|
||||||
.scalar => try benchScalar(reader, &stream, buf),
|
|
||||||
.simd => try benchSimd(reader, &stream, buf),
|
|
||||||
else => @compileError("missing case"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate(
|
|
||||||
writer: anytype,
|
|
||||||
gen: synthetic.Generator,
|
|
||||||
) !void {
|
|
||||||
var buf: [1024]u8 = undefined;
|
|
||||||
while (true) {
|
|
||||||
const data = try gen.next(&buf);
|
|
||||||
writer.writeAll(data) catch |err| switch (err) {
|
|
||||||
error.BrokenPipe => return, // stdout closed
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchNoop(reader: anytype, buf: []u8) !void {
|
|
||||||
var total: usize = 0;
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.readAll(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
total += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
std.log.info("total bytes len={}", .{total});
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchScalar(
|
|
||||||
reader: anytype,
|
|
||||||
stream: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
|
|
||||||
// Using stream.next directly with a for loop applies a naive
|
|
||||||
// scalar approach.
|
|
||||||
for (buf[0..n]) |c| try stream.next(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn benchSimd(
|
|
||||||
reader: anytype,
|
|
||||||
stream: anytype,
|
|
||||||
buf: []u8,
|
|
||||||
) !void {
|
|
||||||
while (true) {
|
|
||||||
const n = try reader.read(buf);
|
|
||||||
if (n == 0) break;
|
|
||||||
try stream.nextSlice(buf[0..n]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const NoopHandler = struct {
|
|
||||||
pub fn print(self: NoopHandler, cp: u21) !void {
|
|
||||||
_ = self;
|
|
||||||
_ = cp;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const TerminalHandler = struct {
|
|
||||||
t: *terminal.Terminal,
|
|
||||||
|
|
||||||
pub fn print(self: *TerminalHandler, cp: u21) !void {
|
|
||||||
try self.t.print(cp);
|
|
||||||
}
|
|
||||||
};
|
|
166
src/benchmark/Benchmark.zig
Normal file
166
src/benchmark/Benchmark.zig
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
//! A single benchmark case.
|
||||||
|
const Benchmark = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const macos = @import("macos");
|
||||||
|
const build_config = @import("../build_config.zig");
|
||||||
|
|
||||||
|
ptr: *anyopaque,
|
||||||
|
vtable: VTable,
|
||||||
|
|
||||||
|
/// Create a new benchmark from a pointer and a vtable.
|
||||||
|
///
|
||||||
|
/// This usually is only called by benchmark implementations, not
|
||||||
|
/// benchmark users.
|
||||||
|
pub fn init(
|
||||||
|
pointer: anytype,
|
||||||
|
vtable: VTable,
|
||||||
|
) Benchmark {
|
||||||
|
const Ptr = @TypeOf(pointer);
|
||||||
|
assert(@typeInfo(Ptr) == .pointer); // Must be a pointer
|
||||||
|
assert(@typeInfo(Ptr).pointer.size == .one); // Must be a single-item pointer
|
||||||
|
assert(@typeInfo(@typeInfo(Ptr).pointer.child) == .@"struct"); // Must point to a struct
|
||||||
|
return .{ .ptr = pointer, .vtable = vtable };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the benchmark.
|
||||||
|
pub fn run(
|
||||||
|
self: Benchmark,
|
||||||
|
mode: RunMode,
|
||||||
|
) Error!RunResult {
|
||||||
|
// Run our setup function if it exists. We do this first because
|
||||||
|
// we don't want this part of our benchmark and we want to fail fast.
|
||||||
|
if (self.vtable.setupFn) |func| try func(self.ptr);
|
||||||
|
defer if (self.vtable.teardownFn) |func| func(self.ptr);
|
||||||
|
|
||||||
|
// Our result accumulator. This will be returned at the end of the run.
|
||||||
|
var result: RunResult = .{};
|
||||||
|
|
||||||
|
// If we're on macOS, we setup signposts so its easier to find
|
||||||
|
// the results in Instruments. There's a lot of nasty comptime stuff
|
||||||
|
// here but its just to ensure this does nothing on other platforms.
|
||||||
|
const signpost_name = "ghostty";
|
||||||
|
const signpost: if (builtin.target.os.tag.isDarwin()) struct {
|
||||||
|
log: *macos.os.Log,
|
||||||
|
id: macos.os.signpost.Id,
|
||||||
|
} else void = if (builtin.target.os.tag.isDarwin()) darwin: {
|
||||||
|
macos.os.signpost.init();
|
||||||
|
const log = macos.os.Log.create(
|
||||||
|
build_config.bundle_id,
|
||||||
|
macos.os.signpost.Category.points_of_interest,
|
||||||
|
);
|
||||||
|
const id = macos.os.signpost.Id.forPointer(log, self.ptr);
|
||||||
|
macos.os.signpost.intervalBegin(log, id, signpost_name);
|
||||||
|
break :darwin .{ .log = log, .id = id };
|
||||||
|
} else {};
|
||||||
|
defer if (comptime builtin.target.os.tag.isDarwin()) {
|
||||||
|
macos.os.signpost.intervalEnd(
|
||||||
|
signpost.log,
|
||||||
|
signpost.id,
|
||||||
|
signpost_name,
|
||||||
|
);
|
||||||
|
signpost.log.release();
|
||||||
|
};
|
||||||
|
|
||||||
|
const start = std.time.Instant.now() catch return error.BenchmarkFailed;
|
||||||
|
while (true) {
|
||||||
|
// Run our step function. If it fails, we return the error.
|
||||||
|
try self.vtable.stepFn(self.ptr);
|
||||||
|
result.iterations += 1;
|
||||||
|
|
||||||
|
// Get our current monotonic time and check our exit conditions.
|
||||||
|
const now = std.time.Instant.now() catch return error.BenchmarkFailed;
|
||||||
|
const exit = switch (mode) {
|
||||||
|
.once => true,
|
||||||
|
.duration => |ns| now.since(start) >= ns,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (exit) {
|
||||||
|
result.duration = now.since(start);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We exit within the loop body.
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of benchmark run. This is used to determine how the benchmark
|
||||||
|
/// is executed.
|
||||||
|
pub const RunMode = union(enum) {
|
||||||
|
/// Run the benchmark exactly once.
|
||||||
|
once,
|
||||||
|
|
||||||
|
/// Run the benchmark for a fixed duration in nanoseconds. This
|
||||||
|
/// will not interrupt a running step so if the granularity of the
|
||||||
|
/// duration is too low, benchmark results may be inaccurate.
|
||||||
|
duration: u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The result of a benchmark run.
|
||||||
|
pub const RunResult = struct {
|
||||||
|
/// The total iterations that step was executed. For "once" run
|
||||||
|
/// modes this will always be 1.
|
||||||
|
iterations: u32 = 0,
|
||||||
|
|
||||||
|
/// The total time taken for the run. For "duration" run modes
|
||||||
|
/// this will be relatively close to the requested duration.
|
||||||
|
/// The units are nanoseconds.
|
||||||
|
duration: u64 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The possible errors that can occur during various stages of the
|
||||||
|
/// benchmark. Right now its just "failure" which ends the benchmark.
|
||||||
|
pub const Error = error{BenchmarkFailed};
|
||||||
|
|
||||||
|
/// The vtable that must be provided to invoke the real implementation.
|
||||||
|
pub const VTable = struct {
|
||||||
|
/// A single step to execute the benchmark. This should do the work
|
||||||
|
/// that is under test. This may be called multiple times if we're
|
||||||
|
/// testing throughput.
|
||||||
|
stepFn: *const fn (ptr: *anyopaque) Error!void,
|
||||||
|
|
||||||
|
/// Setup and teardown functions. These are called once before
|
||||||
|
/// the first step and once after the last step. They are not part
|
||||||
|
/// of the benchmark results (unless you're benchmarking the full
|
||||||
|
/// binary).
|
||||||
|
setupFn: ?*const fn (ptr: *anyopaque) Error!void = null,
|
||||||
|
teardownFn: ?*const fn (ptr: *anyopaque) void = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
test Benchmark {
|
||||||
|
const testing = std.testing;
|
||||||
|
const Simple = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
setup_i: usize = 0,
|
||||||
|
step_i: usize = 0,
|
||||||
|
|
||||||
|
pub fn benchmark(self: *Self) Benchmark {
|
||||||
|
return .init(self, .{
|
||||||
|
.stepFn = step,
|
||||||
|
.setupFn = setup,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(ptr: *anyopaque) Error!void {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(ptr));
|
||||||
|
self.setup_i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(ptr: *anyopaque) Error!void {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(ptr));
|
||||||
|
self.step_i += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var s: Simple = .{};
|
||||||
|
const b = s.benchmark();
|
||||||
|
const result = try b.run(.once);
|
||||||
|
try testing.expectEqual(1, s.setup_i);
|
||||||
|
try testing.expectEqual(1, s.step_i);
|
||||||
|
try testing.expectEqual(1, result.iterations);
|
||||||
|
try testing.expect(result.duration > 0);
|
||||||
|
}
|
34
src/benchmark/CApi.zig
Normal file
34
src/benchmark/CApi.zig
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const cli = @import("cli.zig");
|
||||||
|
const state = &@import("../global.zig").state;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.benchmark);
|
||||||
|
|
||||||
|
/// Run the Ghostty benchmark CLI with the given action and arguments.
|
||||||
|
export fn ghostty_benchmark_cli(
|
||||||
|
action_name_: [*:0]const u8,
|
||||||
|
args: [*:0]const u8,
|
||||||
|
) bool {
|
||||||
|
const action_name = std.mem.sliceTo(action_name_, 0);
|
||||||
|
const action: cli.Action = std.meta.stringToEnum(
|
||||||
|
cli.Action,
|
||||||
|
action_name,
|
||||||
|
) orelse {
|
||||||
|
log.warn("unknown action={s}", .{action_name});
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
cli.mainAction(
|
||||||
|
state.alloc,
|
||||||
|
action,
|
||||||
|
.{ .string = std.mem.sliceTo(args, 0) },
|
||||||
|
) catch |err| {
|
||||||
|
log.warn("failed to run action={s} err={}", .{
|
||||||
|
@tagName(action),
|
||||||
|
err,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
204
src/benchmark/CodepointWidth.zig
Normal file
204
src/benchmark/CodepointWidth.zig
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
//! This benchmark tests the throughput of codepoint width calculation.
|
||||||
|
//! This is a common operation in terminal character printing and the
|
||||||
|
//! motivating factor to write this benchmark was discovering that our
|
||||||
|
//! codepoint width function was 30% of the runtime of every character
|
||||||
|
//! print.
|
||||||
|
const CodepointWidth = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const Benchmark = @import("Benchmark.zig");
|
||||||
|
const options = @import("options.zig");
|
||||||
|
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
|
||||||
|
const simd = @import("../simd/main.zig");
|
||||||
|
const table = @import("../unicode/main.zig").table;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.@"terminal-stream-bench");
|
||||||
|
|
||||||
|
opts: Options,
|
||||||
|
|
||||||
|
/// The file, opened in the setup function.
|
||||||
|
data_f: ?std.fs.File = null,
|
||||||
|
|
||||||
|
pub const Options = struct {
|
||||||
|
/// The type of codepoint width calculation to use.
|
||||||
|
mode: Mode = .noop,
|
||||||
|
|
||||||
|
/// The data to read as a filepath. If this is "-" then
|
||||||
|
/// we will read stdin. If this is unset, then we will
|
||||||
|
/// do nothing (benchmark is a noop). It'd be more unixy to
|
||||||
|
/// use stdin by default but I find that a hanging CLI command
|
||||||
|
/// with no interaction is a bit annoying.
|
||||||
|
data: ?[]const u8 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Mode = enum {
|
||||||
|
/// The baseline mode copies the data from the fd into a buffer. This
|
||||||
|
/// is used to show the minimal overhead of reading the fd into memory
|
||||||
|
/// and establishes a baseline for the other modes.
|
||||||
|
noop,
|
||||||
|
|
||||||
|
/// libc wcwidth
|
||||||
|
wcwidth,
|
||||||
|
|
||||||
|
/// Our SIMD implementation.
|
||||||
|
simd,
|
||||||
|
|
||||||
|
/// Test our lookup table implementation.
|
||||||
|
table,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a new terminal stream handler for the given arguments.
|
||||||
|
pub fn create(
|
||||||
|
alloc: Allocator,
|
||||||
|
opts: Options,
|
||||||
|
) !*CodepointWidth {
|
||||||
|
const ptr = try alloc.create(CodepointWidth);
|
||||||
|
errdefer alloc.destroy(ptr);
|
||||||
|
ptr.* = .{ .opts = opts };
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *CodepointWidth, alloc: Allocator) void {
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn benchmark(self: *CodepointWidth) Benchmark {
|
||||||
|
return .init(self, .{
|
||||||
|
.stepFn = switch (self.opts.mode) {
|
||||||
|
.noop => stepNoop,
|
||||||
|
.wcwidth => stepWcwidth,
|
||||||
|
.table => stepTable,
|
||||||
|
.simd => stepSimd,
|
||||||
|
},
|
||||||
|
.setupFn = setup,
|
||||||
|
.teardownFn = teardown,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
// Open our data file to prepare for reading. We can do more
|
||||||
|
// validation here eventually.
|
||||||
|
assert(self.data_f == null);
|
||||||
|
self.data_f = options.dataFile(self.opts.data) catch |err| {
|
||||||
|
log.warn("error opening data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teardown(ptr: *anyopaque) void {
|
||||||
|
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
|
||||||
|
if (self.data_f) |f| {
|
||||||
|
f.close();
|
||||||
|
self.data_f = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stepNoop(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
_ = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "c" fn wcwidth(c: u32) c_int;
|
||||||
|
|
||||||
|
fn stepWcwidth(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
const f = self.data_f orelse return;
|
||||||
|
var r = std.io.bufferedReader(f.reader());
|
||||||
|
var d: UTF8Decoder = .{};
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const n = r.read(&buf) catch |err| {
|
||||||
|
log.warn("error reading data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
if (n == 0) break; // EOF reached
|
||||||
|
|
||||||
|
for (buf[0..n]) |c| {
|
||||||
|
const cp_, const consumed = d.next(c);
|
||||||
|
assert(consumed);
|
||||||
|
if (cp_) |cp| {
|
||||||
|
const width = wcwidth(cp);
|
||||||
|
|
||||||
|
// Write the width to the buffer to avoid it being compiled
|
||||||
|
// away
|
||||||
|
buf[0] = @intCast(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
const f = self.data_f orelse return;
|
||||||
|
var r = std.io.bufferedReader(f.reader());
|
||||||
|
var d: UTF8Decoder = .{};
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const n = r.read(&buf) catch |err| {
|
||||||
|
log.warn("error reading data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
if (n == 0) break; // EOF reached
|
||||||
|
|
||||||
|
for (buf[0..n]) |c| {
|
||||||
|
const cp_, const consumed = d.next(c);
|
||||||
|
assert(consumed);
|
||||||
|
if (cp_) |cp| {
|
||||||
|
// This is the same trick we do in terminal.zig so we
|
||||||
|
// keep it here.
|
||||||
|
const width = if (cp <= 0xFF)
|
||||||
|
1
|
||||||
|
else
|
||||||
|
table.get(@intCast(cp)).width;
|
||||||
|
|
||||||
|
// Write the width to the buffer to avoid it being compiled
|
||||||
|
// away
|
||||||
|
buf[0] = @intCast(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stepSimd(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
const f = self.data_f orelse return;
|
||||||
|
var r = std.io.bufferedReader(f.reader());
|
||||||
|
var d: UTF8Decoder = .{};
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const n = r.read(&buf) catch |err| {
|
||||||
|
log.warn("error reading data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
if (n == 0) break; // EOF reached
|
||||||
|
|
||||||
|
for (buf[0..n]) |c| {
|
||||||
|
const cp_, const consumed = d.next(c);
|
||||||
|
assert(consumed);
|
||||||
|
if (cp_) |cp| {
|
||||||
|
const width = simd.codepointWidth(cp);
|
||||||
|
|
||||||
|
// Write the width to the buffer to avoid it being compiled
|
||||||
|
// away
|
||||||
|
buf[0] = @intCast(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test CodepointWidth {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
const impl: *CodepointWidth = try .create(alloc, .{});
|
||||||
|
defer impl.destroy(alloc);
|
||||||
|
|
||||||
|
const bench = impl.benchmark();
|
||||||
|
_ = try bench.run(.once);
|
||||||
|
}
|
146
src/benchmark/GraphemeBreak.zig
Normal file
146
src/benchmark/GraphemeBreak.zig
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
//! This benchmark tests the throughput of grapheme break calculation.
|
||||||
|
//! This is a common operation in terminal character printing for terminals
|
||||||
|
//! that support grapheme clustering.
|
||||||
|
const GraphemeBreak = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const Benchmark = @import("Benchmark.zig");
|
||||||
|
const options = @import("options.zig");
|
||||||
|
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
|
||||||
|
const unicode = @import("../unicode/main.zig");
|
||||||
|
|
||||||
|
const log = std.log.scoped(.@"terminal-stream-bench");
|
||||||
|
|
||||||
|
opts: Options,
|
||||||
|
|
||||||
|
/// The file, opened in the setup function.
|
||||||
|
data_f: ?std.fs.File = null,
|
||||||
|
|
||||||
|
pub const Options = struct {
|
||||||
|
/// The type of codepoint width calculation to use.
|
||||||
|
mode: Mode = .table,
|
||||||
|
|
||||||
|
/// The data to read as a filepath. If this is "-" then
|
||||||
|
/// we will read stdin. If this is unset, then we will
|
||||||
|
/// do nothing (benchmark is a noop). It'd be more unixy to
|
||||||
|
/// use stdin by default but I find that a hanging CLI command
|
||||||
|
/// with no interaction is a bit annoying.
|
||||||
|
data: ?[]const u8 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Mode = enum {
|
||||||
|
/// The baseline mode copies the data from the fd into a buffer. This
|
||||||
|
/// is used to show the minimal overhead of reading the fd into memory
|
||||||
|
/// and establishes a baseline for the other modes.
|
||||||
|
noop,
|
||||||
|
|
||||||
|
/// Ghostty's table-based approach.
|
||||||
|
table,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a new terminal stream handler for the given arguments.
|
||||||
|
pub fn create(
|
||||||
|
alloc: Allocator,
|
||||||
|
opts: Options,
|
||||||
|
) !*GraphemeBreak {
|
||||||
|
const ptr = try alloc.create(GraphemeBreak);
|
||||||
|
errdefer alloc.destroy(ptr);
|
||||||
|
ptr.* = .{ .opts = opts };
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *GraphemeBreak, alloc: Allocator) void {
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn benchmark(self: *GraphemeBreak) Benchmark {
|
||||||
|
return .init(self, .{
|
||||||
|
.stepFn = switch (self.opts.mode) {
|
||||||
|
.noop => stepNoop,
|
||||||
|
.table => stepTable,
|
||||||
|
},
|
||||||
|
.setupFn = setup,
|
||||||
|
.teardownFn = teardown,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
// Open our data file to prepare for reading. We can do more
|
||||||
|
// validation here eventually.
|
||||||
|
assert(self.data_f == null);
|
||||||
|
self.data_f = options.dataFile(self.opts.data) catch |err| {
|
||||||
|
log.warn("error opening data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teardown(ptr: *anyopaque) void {
|
||||||
|
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
|
||||||
|
if (self.data_f) |f| {
|
||||||
|
f.close();
|
||||||
|
self.data_f = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stepNoop(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
const f = self.data_f orelse return;
|
||||||
|
var r = std.io.bufferedReader(f.reader());
|
||||||
|
var d: UTF8Decoder = .{};
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const n = r.read(&buf) catch |err| {
|
||||||
|
log.warn("error reading data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
if (n == 0) break; // EOF reached
|
||||||
|
|
||||||
|
for (buf[0..n]) |c| {
|
||||||
|
_ = d.next(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
const f = self.data_f orelse return;
|
||||||
|
var r = std.io.bufferedReader(f.reader());
|
||||||
|
var d: UTF8Decoder = .{};
|
||||||
|
var state: unicode.GraphemeBreakState = .{};
|
||||||
|
var cp1: u21 = 0;
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const n = r.read(&buf) catch |err| {
|
||||||
|
log.warn("error reading data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
if (n == 0) break; // EOF reached
|
||||||
|
|
||||||
|
for (buf[0..n]) |c| {
|
||||||
|
const cp_, const consumed = d.next(c);
|
||||||
|
assert(consumed);
|
||||||
|
if (cp_) |cp2| {
|
||||||
|
const v = unicode.graphemeBreak(cp1, @intCast(cp2), &state);
|
||||||
|
buf[0] = @intCast(@intFromBool(v));
|
||||||
|
cp1 = cp2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test GraphemeBreak {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
const impl: *GraphemeBreak = try .create(alloc, .{});
|
||||||
|
defer impl.destroy(alloc);
|
||||||
|
|
||||||
|
const bench = impl.benchmark();
|
||||||
|
_ = try bench.run(.once);
|
||||||
|
}
|
106
src/benchmark/TerminalParser.zig
Normal file
106
src/benchmark/TerminalParser.zig
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
//! This benchmark tests the throughput of the terminal escape code parser.
|
||||||
|
const TerminalParser = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const terminalpkg = @import("../terminal/main.zig");
|
||||||
|
const Benchmark = @import("Benchmark.zig");
|
||||||
|
const options = @import("options.zig");
|
||||||
|
|
||||||
|
const log = std.log.scoped(.@"terminal-stream-bench");
|
||||||
|
|
||||||
|
opts: Options,
|
||||||
|
|
||||||
|
/// The file, opened in the setup function.
|
||||||
|
data_f: ?std.fs.File = null,
|
||||||
|
|
||||||
|
pub const Options = struct {
|
||||||
|
/// The data to read as a filepath. If this is "-" then
|
||||||
|
/// we will read stdin. If this is unset, then we will
|
||||||
|
/// do nothing (benchmark is a noop). It'd be more unixy to
|
||||||
|
/// use stdin by default but I find that a hanging CLI command
|
||||||
|
/// with no interaction is a bit annoying.
|
||||||
|
data: ?[]const u8 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn create(
|
||||||
|
alloc: Allocator,
|
||||||
|
opts: Options,
|
||||||
|
) !*TerminalParser {
|
||||||
|
const ptr = try alloc.create(TerminalParser);
|
||||||
|
errdefer alloc.destroy(ptr);
|
||||||
|
ptr.* = .{ .opts = opts };
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *TerminalParser, alloc: Allocator) void {
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn benchmark(self: *TerminalParser) Benchmark {
|
||||||
|
return .init(self, .{
|
||||||
|
.stepFn = step,
|
||||||
|
.setupFn = setup,
|
||||||
|
.teardownFn = teardown,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *TerminalParser = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
// Open our data file to prepare for reading. We can do more
|
||||||
|
// validation here eventually.
|
||||||
|
assert(self.data_f == null);
|
||||||
|
self.data_f = options.dataFile(self.opts.data) catch |err| {
|
||||||
|
log.warn("error opening data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teardown(ptr: *anyopaque) void {
|
||||||
|
const self: *TerminalParser = @ptrCast(@alignCast(ptr));
|
||||||
|
if (self.data_f) |f| {
|
||||||
|
f.close();
|
||||||
|
self.data_f = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *TerminalParser = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
// Get our buffered reader so we're not predominantly
|
||||||
|
// waiting on file IO. It'd be better to move this fully into
|
||||||
|
// memory. If we're IO bound though that should show up on
|
||||||
|
// the benchmark results and... I know writing this that we
|
||||||
|
// aren't currently IO bound.
|
||||||
|
const f = self.data_f orelse return;
|
||||||
|
var r = std.io.bufferedReader(f.reader());
|
||||||
|
|
||||||
|
var p: terminalpkg.Parser = .{};
|
||||||
|
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const n = r.read(&buf) catch |err| {
|
||||||
|
log.warn("error reading data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
if (n == 0) break; // EOF reached
|
||||||
|
for (buf[0..n]) |c| {
|
||||||
|
const actions = p.next(c);
|
||||||
|
//std.log.warn("actions={any}", .{actions});
|
||||||
|
_ = actions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test TerminalParser {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
const impl: *TerminalParser = try .create(alloc, .{});
|
||||||
|
defer impl.destroy(alloc);
|
||||||
|
|
||||||
|
const bench = impl.benchmark();
|
||||||
|
_ = try bench.run(.once);
|
||||||
|
}
|
153
src/benchmark/TerminalStream.zig
Normal file
153
src/benchmark/TerminalStream.zig
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
//! This benchmark tests the performance of the terminal stream
|
||||||
|
//! handler from input to terminal state update. This is useful to
|
||||||
|
//! test general throughput of VT parsing and handling.
|
||||||
|
//!
|
||||||
|
//! Note that the handler used for this benchmark isn't the full
|
||||||
|
//! terminal handler, since that requires a significant amount of
|
||||||
|
//! state. This is a simplified version that only handles specific
|
||||||
|
//! terminal operations like printing characters. We should expand
|
||||||
|
//! this to include more operations to improve the accuracy of the
|
||||||
|
//! benchmark.
|
||||||
|
//!
|
||||||
|
//! It is a fairly broad benchmark that can be used to determine
|
||||||
|
//! if we need to optimize something more specific (e.g. the parser).
|
||||||
|
const TerminalStream = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const terminalpkg = @import("../terminal/main.zig");
|
||||||
|
const Benchmark = @import("Benchmark.zig");
|
||||||
|
const options = @import("options.zig");
|
||||||
|
const Terminal = terminalpkg.Terminal;
|
||||||
|
const Stream = terminalpkg.Stream(*Handler);
|
||||||
|
|
||||||
|
const log = std.log.scoped(.@"terminal-stream-bench");
|
||||||
|
|
||||||
|
opts: Options,
|
||||||
|
terminal: Terminal,
|
||||||
|
handler: Handler,
|
||||||
|
stream: Stream,
|
||||||
|
|
||||||
|
/// The file, opened in the setup function.
|
||||||
|
data_f: ?std.fs.File = null,
|
||||||
|
|
||||||
|
pub const Options = struct {
|
||||||
|
/// The size of the terminal. This affects benchmarking when
|
||||||
|
/// dealing with soft line wrapping and the memory impact
|
||||||
|
/// of page sizes.
|
||||||
|
@"terminal-rows": u16 = 80,
|
||||||
|
@"terminal-cols": u16 = 120,
|
||||||
|
|
||||||
|
/// The data to read as a filepath. If this is "-" then
|
||||||
|
/// we will read stdin. If this is unset, then we will
|
||||||
|
/// do nothing (benchmark is a noop). It'd be more unixy to
|
||||||
|
/// use stdin by default but I find that a hanging CLI command
|
||||||
|
/// with no interaction is a bit annoying.
|
||||||
|
data: ?[]const u8 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a new terminal stream handler for the given arguments.
|
||||||
|
pub fn create(
|
||||||
|
alloc: Allocator,
|
||||||
|
opts: Options,
|
||||||
|
) !*TerminalStream {
|
||||||
|
const ptr = try alloc.create(TerminalStream);
|
||||||
|
errdefer alloc.destroy(ptr);
|
||||||
|
|
||||||
|
ptr.* = .{
|
||||||
|
.opts = opts,
|
||||||
|
.terminal = try .init(alloc, .{
|
||||||
|
.rows = opts.@"terminal-rows",
|
||||||
|
.cols = opts.@"terminal-cols",
|
||||||
|
}),
|
||||||
|
.handler = .{ .t = &ptr.terminal },
|
||||||
|
.stream = .{ .handler = &ptr.handler },
|
||||||
|
};
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *TerminalStream, alloc: Allocator) void {
|
||||||
|
self.terminal.deinit(alloc);
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn benchmark(self: *TerminalStream) Benchmark {
|
||||||
|
return .init(self, .{
|
||||||
|
.stepFn = step,
|
||||||
|
.setupFn = setup,
|
||||||
|
.teardownFn = teardown,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *TerminalStream = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
// Always reset our terminal state
|
||||||
|
self.terminal.fullReset();
|
||||||
|
|
||||||
|
// Open our data file to prepare for reading. We can do more
|
||||||
|
// validation here eventually.
|
||||||
|
assert(self.data_f == null);
|
||||||
|
self.data_f = options.dataFile(self.opts.data) catch |err| {
|
||||||
|
log.warn("error opening data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teardown(ptr: *anyopaque) void {
|
||||||
|
const self: *TerminalStream = @ptrCast(@alignCast(ptr));
|
||||||
|
if (self.data_f) |f| {
|
||||||
|
f.close();
|
||||||
|
self.data_f = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(ptr: *anyopaque) Benchmark.Error!void {
|
||||||
|
const self: *TerminalStream = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
// Get our buffered reader so we're not predominantly
|
||||||
|
// waiting on file IO. It'd be better to move this fully into
|
||||||
|
// memory. If we're IO bound though that should show up on
|
||||||
|
// the benchmark results and... I know writing this that we
|
||||||
|
// aren't currently IO bound.
|
||||||
|
const f = self.data_f orelse return;
|
||||||
|
var r = std.io.bufferedReader(f.reader());
|
||||||
|
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
const n = r.read(&buf) catch |err| {
|
||||||
|
log.warn("error reading data file err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
if (n == 0) break; // EOF reached
|
||||||
|
const chunk = buf[0..n];
|
||||||
|
self.stream.nextSlice(chunk) catch |err| {
|
||||||
|
log.warn("error processing data file chunk err={}", .{err});
|
||||||
|
return error.BenchmarkFailed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements the handler interface for the terminal.Stream.
|
||||||
|
/// We should expand this to include more operations to make
|
||||||
|
/// our benchmark more realistic.
|
||||||
|
const Handler = struct {
|
||||||
|
t: *Terminal,
|
||||||
|
|
||||||
|
pub fn print(self: *Handler, cp: u21) !void {
|
||||||
|
try self.t.print(cp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test TerminalStream {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
const impl: *TerminalStream = try .create(alloc, .{});
|
||||||
|
defer impl.destroy(alloc);
|
||||||
|
|
||||||
|
const bench = impl.benchmark();
|
||||||
|
_ = try bench.run(.once);
|
||||||
|
}
|
94
src/benchmark/cli.zig
Normal file
94
src/benchmark/cli.zig
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const cli = @import("../cli.zig");
|
||||||
|
|
||||||
|
/// The available actions for the CLI. This is the list of available
|
||||||
|
/// benchmarks. View docs for each individual one in the predictably
|
||||||
|
/// named files.
|
||||||
|
pub const Action = enum {
|
||||||
|
@"codepoint-width",
|
||||||
|
@"grapheme-break",
|
||||||
|
@"terminal-parser",
|
||||||
|
@"terminal-stream",
|
||||||
|
|
||||||
|
/// Returns the struct associated with the action. The struct
|
||||||
|
/// should have a few decls:
|
||||||
|
///
|
||||||
|
/// - `const Options`: The CLI options for the action.
|
||||||
|
/// - `fn create`: Create a new instance of the action from options.
|
||||||
|
/// - `fn benchmark`: Returns a `Benchmark` instance for the action.
|
||||||
|
///
|
||||||
|
/// See TerminalStream for an example.
|
||||||
|
pub fn Struct(comptime action: Action) type {
|
||||||
|
return switch (action) {
|
||||||
|
.@"terminal-stream" => @import("TerminalStream.zig"),
|
||||||
|
.@"codepoint-width" => @import("CodepointWidth.zig"),
|
||||||
|
.@"grapheme-break" => @import("GraphemeBreak.zig"),
|
||||||
|
.@"terminal-parser" => @import("TerminalParser.zig"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An entrypoint for the benchmark CLI.
|
||||||
|
pub fn main() !void {
|
||||||
|
const alloc = std.heap.c_allocator;
|
||||||
|
const action_ = try cli.action.detectArgs(Action, alloc);
|
||||||
|
const action = action_ orelse return error.NoAction;
|
||||||
|
try mainAction(alloc, action, .cli);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arguments that can be passed to the benchmark.
|
||||||
|
pub const Args = union(enum) {
|
||||||
|
/// The arguments passed to the CLI via argc/argv.
|
||||||
|
cli,
|
||||||
|
|
||||||
|
/// Simple string arguments, parsed via std.process.ArgIteratorGeneral.
|
||||||
|
string: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn mainAction(
|
||||||
|
alloc: Allocator,
|
||||||
|
action: Action,
|
||||||
|
args: Args,
|
||||||
|
) !void {
|
||||||
|
switch (action) {
|
||||||
|
inline else => |comptime_action| {
|
||||||
|
const BenchmarkImpl = Action.Struct(comptime_action);
|
||||||
|
try mainActionImpl(BenchmarkImpl, alloc, args);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mainActionImpl(
|
||||||
|
comptime BenchmarkImpl: type,
|
||||||
|
alloc: Allocator,
|
||||||
|
args: Args,
|
||||||
|
) !void {
|
||||||
|
// First, parse our CLI options.
|
||||||
|
const Options = BenchmarkImpl.Options;
|
||||||
|
var opts: Options = .{};
|
||||||
|
defer if (@hasDecl(Options, "deinit")) opts.deinit();
|
||||||
|
switch (args) {
|
||||||
|
.cli => {
|
||||||
|
var iter = try cli.args.argsIterator(alloc);
|
||||||
|
defer iter.deinit();
|
||||||
|
try cli.args.parse(Options, alloc, &opts, &iter);
|
||||||
|
},
|
||||||
|
.string => |str| {
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
str,
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
try cli.args.parse(Options, alloc, &opts, &iter);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create our implementation
|
||||||
|
const impl = try BenchmarkImpl.create(alloc, opts);
|
||||||
|
defer impl.destroy(alloc);
|
||||||
|
|
||||||
|
// Initialize our benchmark
|
||||||
|
const b = impl.benchmark();
|
||||||
|
_ = try b.run(.once);
|
||||||
|
}
|
11
src/benchmark/main.zig
Normal file
11
src/benchmark/main.zig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
pub const cli = @import("cli.zig");
|
||||||
|
pub const Benchmark = @import("Benchmark.zig");
|
||||||
|
pub const CApi = @import("CApi.zig");
|
||||||
|
pub const TerminalStream = @import("TerminalStream.zig");
|
||||||
|
pub const CodepointWidth = @import("CodepointWidth.zig");
|
||||||
|
pub const GraphemeBreak = @import("GraphemeBreak.zig");
|
||||||
|
pub const TerminalParser = @import("TerminalParser.zig");
|
||||||
|
|
||||||
|
test {
|
||||||
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
}
|
20
src/benchmark/options.zig
Normal file
20
src/benchmark/options.zig
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//! This file contains helpers for CLI options.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
/// Returns the data file for the given path in a way that is consistent
|
||||||
|
/// across our CLI. If the path is not set then no file is returned.
|
||||||
|
/// If the path is "-", then we will return stdin. If the path is
|
||||||
|
/// a file then we will open and return the handle.
|
||||||
|
pub fn dataFile(path_: ?[]const u8) !?std.fs.File {
|
||||||
|
const path = path_ orelse return null;
|
||||||
|
|
||||||
|
// Stdin
|
||||||
|
if (std.mem.eql(u8, path, "-")) return std.io.getStdIn();
|
||||||
|
|
||||||
|
// Normal file
|
||||||
|
const file = try std.fs.cwd().openFile(path, .{});
|
||||||
|
errdefer file.close();
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
@ -528,11 +528,6 @@ pub const ExeEntrypoint = enum {
|
|||||||
webgen_config,
|
webgen_config,
|
||||||
webgen_actions,
|
webgen_actions,
|
||||||
webgen_commands,
|
webgen_commands,
|
||||||
bench_parser,
|
|
||||||
bench_stream,
|
|
||||||
bench_codepoint_width,
|
|
||||||
bench_grapheme_break,
|
|
||||||
bench_page_init,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The release channel for the build.
|
/// The release channel for the build.
|
||||||
|
@ -14,52 +14,37 @@ pub fn init(
|
|||||||
var steps = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
|
var steps = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
|
||||||
errdefer steps.deinit();
|
errdefer steps.deinit();
|
||||||
|
|
||||||
// Open the directory ./src/bench
|
// Our synthetic data generator
|
||||||
const c_dir_path = b.pathFromRoot("src/bench");
|
{
|
||||||
var c_dir = try std.fs.cwd().openDir(c_dir_path, .{ .iterate = true });
|
const exe = b.addExecutable(.{
|
||||||
defer c_dir.close();
|
.name = "ghostty-gen",
|
||||||
|
|
||||||
// Go through and add each as a step
|
|
||||||
var c_dir_it = c_dir.iterate();
|
|
||||||
while (try c_dir_it.next()) |entry| {
|
|
||||||
// Get the index of the last '.' so we can strip the extension.
|
|
||||||
const index = std.mem.lastIndexOfScalar(u8, entry.name, '.') orelse continue;
|
|
||||||
if (index == 0) continue;
|
|
||||||
|
|
||||||
// If it doesn't end in 'zig' then ignore
|
|
||||||
if (!std.mem.eql(u8, entry.name[index + 1 ..], "zig")) continue;
|
|
||||||
|
|
||||||
// Name of the conformance app and full path to the entrypoint.
|
|
||||||
const name = entry.name[0..index];
|
|
||||||
|
|
||||||
// Executable builder.
|
|
||||||
const bin_name = try std.fmt.allocPrint(b.allocator, "bench-{s}", .{name});
|
|
||||||
const c_exe = b.addExecutable(.{
|
|
||||||
.name = bin_name,
|
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/main_gen.zig"),
|
||||||
.target = deps.config.target,
|
.target = deps.config.target,
|
||||||
|
// We always want our datagen to be fast because it
|
||||||
|
// takes awhile to run.
|
||||||
|
.optimize = .ReleaseFast,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
exe.linkLibC();
|
||||||
|
_ = try deps.add(exe);
|
||||||
|
try steps.append(exe);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our benchmarking application.
|
||||||
|
{
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "ghostty-bench",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/main_bench.zig"),
|
||||||
|
.target = deps.config.target,
|
||||||
// We always want our benchmarks to be in release mode.
|
// We always want our benchmarks to be in release mode.
|
||||||
.optimize = .ReleaseFast,
|
.optimize = .ReleaseFast,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
c_exe.linkLibC();
|
exe.linkLibC();
|
||||||
|
_ = try deps.add(exe);
|
||||||
// Update our entrypoint
|
try steps.append(exe);
|
||||||
var enum_name: [64]u8 = undefined;
|
|
||||||
@memcpy(enum_name[0..name.len], name);
|
|
||||||
std.mem.replaceScalar(u8, enum_name[0..name.len], '-', '_');
|
|
||||||
|
|
||||||
var buf: [64]u8 = undefined;
|
|
||||||
const new_deps = try deps.changeEntrypoint(b, std.meta.stringToEnum(
|
|
||||||
Config.ExeEntrypoint,
|
|
||||||
try std.fmt.bufPrint(&buf, "bench_{s}", .{enum_name[0..name.len]}),
|
|
||||||
).?);
|
|
||||||
|
|
||||||
_ = try new_deps.add(c_exe);
|
|
||||||
|
|
||||||
try steps.append(c_exe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{ .steps = steps.items };
|
return .{ .steps = steps.items };
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const GhosttyLib = @This();
|
const GhosttyLib = @This();
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const RunStep = std.Build.Step.Run;
|
||||||
const Config = @import("Config.zig");
|
const Config = @import("Config.zig");
|
||||||
const SharedDeps = @import("SharedDeps.zig");
|
const SharedDeps = @import("SharedDeps.zig");
|
||||||
const LibtoolStep = @import("LibtoolStep.zig");
|
const LibtoolStep = @import("LibtoolStep.zig");
|
||||||
@ -11,6 +12,7 @@ step: *std.Build.Step,
|
|||||||
|
|
||||||
/// The final static library file
|
/// The final static library file
|
||||||
output: std.Build.LazyPath,
|
output: std.Build.LazyPath,
|
||||||
|
dsym: ?std.Build.LazyPath,
|
||||||
|
|
||||||
pub fn initStatic(
|
pub fn initStatic(
|
||||||
b: *std.Build,
|
b: *std.Build,
|
||||||
@ -18,9 +20,14 @@ pub fn initStatic(
|
|||||||
) !GhosttyLib {
|
) !GhosttyLib {
|
||||||
const lib = b.addStaticLibrary(.{
|
const lib = b.addStaticLibrary(.{
|
||||||
.name = "ghostty",
|
.name = "ghostty",
|
||||||
.root_source_file = b.path("src/main_c.zig"),
|
.root_module = b.createModule(.{
|
||||||
.target = deps.config.target,
|
.root_source_file = b.path("src/main_c.zig"),
|
||||||
.optimize = deps.config.optimize,
|
.target = deps.config.target,
|
||||||
|
.optimize = deps.config.optimize,
|
||||||
|
.strip = deps.config.strip,
|
||||||
|
.omit_frame_pointer = deps.config.strip,
|
||||||
|
.unwind_tables = if (deps.config.strip) .none else .sync,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
lib.linkLibC();
|
lib.linkLibC();
|
||||||
|
|
||||||
@ -37,6 +44,7 @@ pub fn initStatic(
|
|||||||
if (!deps.config.target.result.os.tag.isDarwin()) return .{
|
if (!deps.config.target.result.os.tag.isDarwin()) return .{
|
||||||
.step = &lib.step,
|
.step = &lib.step,
|
||||||
.output = lib.getEmittedBin(),
|
.output = lib.getEmittedBin(),
|
||||||
|
.dsym = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a static lib that contains all our dependencies.
|
// Create a static lib that contains all our dependencies.
|
||||||
@ -50,6 +58,9 @@ pub fn initStatic(
|
|||||||
return .{
|
return .{
|
||||||
.step = libtool.step,
|
.step = libtool.step,
|
||||||
.output = libtool.output,
|
.output = libtool.output,
|
||||||
|
|
||||||
|
// Static libraries cannot have dSYMs because they aren't linked.
|
||||||
|
.dsym = null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,16 +70,35 @@ pub fn initShared(
|
|||||||
) !GhosttyLib {
|
) !GhosttyLib {
|
||||||
const lib = b.addSharedLibrary(.{
|
const lib = b.addSharedLibrary(.{
|
||||||
.name = "ghostty",
|
.name = "ghostty",
|
||||||
.root_source_file = b.path("src/main_c.zig"),
|
.root_module = b.createModule(.{
|
||||||
.target = deps.config.target,
|
.root_source_file = b.path("src/main_c.zig"),
|
||||||
.optimize = deps.config.optimize,
|
.target = deps.config.target,
|
||||||
.strip = deps.config.strip,
|
.optimize = deps.config.optimize,
|
||||||
|
.strip = deps.config.strip,
|
||||||
|
.omit_frame_pointer = deps.config.strip,
|
||||||
|
.unwind_tables = if (deps.config.strip) .none else .sync,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
_ = try deps.add(lib);
|
_ = try deps.add(lib);
|
||||||
|
|
||||||
|
// Get our debug symbols
|
||||||
|
const dsymutil: ?std.Build.LazyPath = dsymutil: {
|
||||||
|
if (!deps.config.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.dSYM");
|
||||||
|
break :dsymutil output;
|
||||||
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.step = &lib.step,
|
.step = &lib.step,
|
||||||
.output = lib.getEmittedBin(),
|
.output = lib.getEmittedBin(),
|
||||||
|
.dsym = dsymutil,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +125,10 @@ pub fn initMacOSUniversal(
|
|||||||
return .{
|
return .{
|
||||||
.step = universal.step,
|
.step = universal.step,
|
||||||
.output = universal.output,
|
.output = universal.output,
|
||||||
|
|
||||||
|
// You can't run dsymutil on a universal binary, you have to
|
||||||
|
// do it on the individual binaries.
|
||||||
|
.dsym = null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,20 +64,24 @@ pub fn init(
|
|||||||
.{
|
.{
|
||||||
.library = macos_universal.output,
|
.library = macos_universal.output,
|
||||||
.headers = b.path("include"),
|
.headers = b.path("include"),
|
||||||
|
.dsym = macos_universal.dsym,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.library = ios.output,
|
.library = ios.output,
|
||||||
.headers = b.path("include"),
|
.headers = b.path("include"),
|
||||||
|
.dsym = ios.dsym,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.library = ios_sim.output,
|
.library = ios_sim.output,
|
||||||
.headers = b.path("include"),
|
.headers = b.path("include"),
|
||||||
|
.dsym = ios_sim.dsym,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
.native => &.{.{
|
.native => &.{.{
|
||||||
.library = macos_native.output,
|
.library = macos_native.output,
|
||||||
.headers = b.path("include"),
|
.headers = b.path("include"),
|
||||||
|
.dsym = macos_native.dsym,
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,7 @@ const XCFramework = @import("GhosttyXCFramework.zig");
|
|||||||
build: *std.Build.Step.Run,
|
build: *std.Build.Step.Run,
|
||||||
open: *std.Build.Step.Run,
|
open: *std.Build.Step.Run,
|
||||||
copy: *std.Build.Step.Run,
|
copy: *std.Build.Step.Run,
|
||||||
|
xctest: *std.Build.Step.Run,
|
||||||
|
|
||||||
pub const Deps = struct {
|
pub const Deps = struct {
|
||||||
xcframework: *const XCFramework,
|
xcframework: *const XCFramework,
|
||||||
@ -33,6 +34,21 @@ pub fn init(
|
|||||||
=> "Release",
|
=> "Release",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const xc_arch: ?[]const u8 = switch (deps.xcframework.target) {
|
||||||
|
// Universal is our default target, so we don't have to
|
||||||
|
// add anything.
|
||||||
|
.universal => null,
|
||||||
|
|
||||||
|
// Native we need to override the architecture in the Xcode
|
||||||
|
// project with the -arch flag.
|
||||||
|
.native => switch (builtin.cpu.arch) {
|
||||||
|
.aarch64 => "arm64",
|
||||||
|
.x86_64 => "x86_64",
|
||||||
|
else => @panic("unsupported macOS arch"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const env = try std.process.getEnvMap(b.allocator);
|
||||||
const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
|
const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
|
||||||
|
|
||||||
// Our step to build the Ghostty macOS app.
|
// Our step to build the Ghostty macOS app.
|
||||||
@ -41,12 +57,13 @@ pub fn init(
|
|||||||
// we create a new empty environment.
|
// we create a new empty environment.
|
||||||
const env_map = try b.allocator.create(std.process.EnvMap);
|
const env_map = try b.allocator.create(std.process.EnvMap);
|
||||||
env_map.* = .init(b.allocator);
|
env_map.* = .init(b.allocator);
|
||||||
|
if (env.get("PATH")) |v| try env_map.put("PATH", v);
|
||||||
|
|
||||||
const build = RunStep.create(b, "xcodebuild");
|
const step = RunStep.create(b, "xcodebuild");
|
||||||
build.has_side_effects = true;
|
step.has_side_effects = true;
|
||||||
build.cwd = b.path("macos");
|
step.cwd = b.path("macos");
|
||||||
build.env_map = env_map;
|
step.env_map = env_map;
|
||||||
build.addArgs(&.{
|
step.addArgs(&.{
|
||||||
"xcodebuild",
|
"xcodebuild",
|
||||||
"-target",
|
"-target",
|
||||||
"Ghostty",
|
"Ghostty",
|
||||||
@ -54,36 +71,55 @@ pub fn init(
|
|||||||
xc_config,
|
xc_config,
|
||||||
});
|
});
|
||||||
|
|
||||||
switch (deps.xcframework.target) {
|
// If we have a specific architecture, we need to pass it
|
||||||
// Universal is our default target, so we don't have to
|
// to xcodebuild.
|
||||||
// add anything.
|
if (xc_arch) |arch| step.addArgs(&.{ "-arch", arch });
|
||||||
.universal => {},
|
|
||||||
|
|
||||||
// Native we need to override the architecture in the Xcode
|
|
||||||
// project with the -arch flag.
|
|
||||||
.native => build.addArgs(&.{
|
|
||||||
"-arch",
|
|
||||||
switch (builtin.cpu.arch) {
|
|
||||||
.aarch64 => "arm64",
|
|
||||||
.x86_64 => "x86_64",
|
|
||||||
else => @panic("unsupported macOS arch"),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need the xcframework
|
// We need the xcframework
|
||||||
deps.xcframework.addStepDependencies(&build.step);
|
deps.xcframework.addStepDependencies(&step.step);
|
||||||
|
|
||||||
// We also need all these resources because the xcode project
|
// We also need all these resources because the xcode project
|
||||||
// references them via symlinks.
|
// references them via symlinks.
|
||||||
deps.resources.addStepDependencies(&build.step);
|
deps.resources.addStepDependencies(&step.step);
|
||||||
deps.i18n.addStepDependencies(&build.step);
|
deps.i18n.addStepDependencies(&step.step);
|
||||||
deps.docs.installDummy(&build.step);
|
deps.docs.installDummy(&step.step);
|
||||||
|
|
||||||
// Expect success
|
// Expect success
|
||||||
build.expectExitCode(0);
|
step.expectExitCode(0);
|
||||||
|
|
||||||
break :build build;
|
break :build step;
|
||||||
|
};
|
||||||
|
|
||||||
|
const xctest = xctest: {
|
||||||
|
const env_map = try b.allocator.create(std.process.EnvMap);
|
||||||
|
env_map.* = .init(b.allocator);
|
||||||
|
if (env.get("PATH")) |v| try env_map.put("PATH", v);
|
||||||
|
|
||||||
|
const step = RunStep.create(b, "xcodebuild test");
|
||||||
|
step.has_side_effects = true;
|
||||||
|
step.cwd = b.path("macos");
|
||||||
|
step.env_map = env_map;
|
||||||
|
step.addArgs(&.{
|
||||||
|
"xcodebuild",
|
||||||
|
"test",
|
||||||
|
"-scheme",
|
||||||
|
"Ghostty",
|
||||||
|
});
|
||||||
|
if (xc_arch) |arch| step.addArgs(&.{ "-arch", arch });
|
||||||
|
|
||||||
|
// We need the xcframework
|
||||||
|
deps.xcframework.addStepDependencies(&step.step);
|
||||||
|
|
||||||
|
// We also need all these resources because the xcode project
|
||||||
|
// references them via symlinks.
|
||||||
|
deps.resources.addStepDependencies(&step.step);
|
||||||
|
deps.i18n.addStepDependencies(&step.step);
|
||||||
|
deps.docs.installDummy(&step.step);
|
||||||
|
|
||||||
|
// Expect success
|
||||||
|
step.expectExitCode(0);
|
||||||
|
|
||||||
|
break :xctest step;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Our step to open the resulting Ghostty app.
|
// Our step to open the resulting Ghostty app.
|
||||||
@ -143,6 +179,7 @@ pub fn init(
|
|||||||
.build = build,
|
.build = build,
|
||||||
.open = open,
|
.open = open,
|
||||||
.copy = copy,
|
.copy = copy,
|
||||||
|
.xctest = xctest,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,3 +192,10 @@ pub fn installXcframework(self: *const Ghostty) void {
|
|||||||
const b = self.build.step.owner;
|
const b = self.build.step.owner;
|
||||||
b.getInstallStep().dependOn(&self.build.step);
|
b.getInstallStep().dependOn(&self.build.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addTestStepDependencies(
|
||||||
|
self: *const Ghostty,
|
||||||
|
other_step: *std.Build.Step,
|
||||||
|
) void {
|
||||||
|
other_step.dependOn(&self.xctest.step);
|
||||||
|
}
|
||||||
|
@ -139,7 +139,7 @@ pub fn add(
|
|||||||
if (b.lazyDependency("harfbuzz", .{
|
if (b.lazyDependency("harfbuzz", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.@"enable-freetype" = true,
|
.@"enable-freetype" = self.config.font_backend.hasFreetype(),
|
||||||
.@"enable-coretext" = self.config.font_backend.hasCoretext(),
|
.@"enable-coretext" = self.config.font_backend.hasCoretext(),
|
||||||
})) |harfbuzz_dep| {
|
})) |harfbuzz_dep| {
|
||||||
step.root_module.addImport(
|
step.root_module.addImport(
|
||||||
|
@ -26,6 +26,9 @@ pub const Library = struct {
|
|||||||
|
|
||||||
/// Path to a directory with the headers.
|
/// Path to a directory with the headers.
|
||||||
headers: LazyPath,
|
headers: LazyPath,
|
||||||
|
|
||||||
|
/// Path to a debug symbols file (.dSYM) if available.
|
||||||
|
dsym: ?LazyPath,
|
||||||
};
|
};
|
||||||
|
|
||||||
step: *Step,
|
step: *Step,
|
||||||
@ -52,6 +55,10 @@ pub fn create(b: *std.Build, opts: Options) *XCFrameworkStep {
|
|||||||
run.addFileArg(lib.library);
|
run.addFileArg(lib.library);
|
||||||
run.addArg("-headers");
|
run.addArg("-headers");
|
||||||
run.addFileArg(lib.headers);
|
run.addFileArg(lib.headers);
|
||||||
|
if (lib.dsym) |dsym| {
|
||||||
|
run.addArg("-debug-symbols");
|
||||||
|
run.addFileArg(dsym);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
run.addArg("-output");
|
run.addArg("-output");
|
||||||
run.addArg(opts.out_path);
|
run.addArg(opts.out_path);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const Config = @import("../config/Config.zig");
|
const Config = @import("../config/Config.zig");
|
||||||
const Action = @import("../cli/action.zig").Action;
|
const Action = @import("../cli.zig").ghostty.Action;
|
||||||
|
|
||||||
/// A bash completions configuration that contains all the available commands
|
/// A bash completions configuration that contains all the available commands
|
||||||
/// and options.
|
/// and options.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const Config = @import("../config/Config.zig");
|
const Config = @import("../config/Config.zig");
|
||||||
const Action = @import("../cli/action.zig").Action;
|
const Action = @import("../cli.zig").ghostty.Action;
|
||||||
|
|
||||||
/// A fish completions configuration that contains all the available commands
|
/// A fish completions configuration that contains all the available commands
|
||||||
/// and options.
|
/// and options.
|
||||||
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||||||
const help_strings = @import("help_strings");
|
const help_strings = @import("help_strings");
|
||||||
const build_config = @import("../../build_config.zig");
|
const build_config = @import("../../build_config.zig");
|
||||||
const Config = @import("../../config/Config.zig");
|
const Config = @import("../../config/Config.zig");
|
||||||
const Action = @import("../../cli/action.zig").Action;
|
const Action = @import("../../cli/ghostty.zig").Action;
|
||||||
const KeybindAction = @import("../../input/Binding.zig").Action;
|
const KeybindAction = @import("../../input/Binding.zig").Action;
|
||||||
|
|
||||||
pub fn substitute(alloc: std.mem.Allocator, input: []const u8, writer: anytype) !void {
|
pub fn substitute(alloc: std.mem.Allocator, input: []const u8, writer: anytype) !void {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const Config = @import("../config/Config.zig");
|
const Config = @import("../config/Config.zig");
|
||||||
const Action = @import("../cli/action.zig").Action;
|
const Action = @import("../cli.zig").ghostty.Action;
|
||||||
|
|
||||||
/// A zsh completions configuration that contains all the available commands
|
/// A zsh completions configuration that contains all the available commands
|
||||||
/// and options.
|
/// and options.
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
const diags = @import("cli/diagnostics.zig");
|
const diags = @import("cli/diagnostics.zig");
|
||||||
|
|
||||||
pub const args = @import("cli/args.zig");
|
pub const args = @import("cli/args.zig");
|
||||||
pub const Action = @import("cli/action.zig").Action;
|
pub const action = @import("cli/action.zig");
|
||||||
|
pub const ghostty = @import("cli/ghostty.zig");
|
||||||
pub const CompatibilityHandler = args.CompatibilityHandler;
|
pub const CompatibilityHandler = args.CompatibilityHandler;
|
||||||
pub const compatibilityRenamed = args.compatibilityRenamed;
|
pub const compatibilityRenamed = args.compatibilityRenamed;
|
||||||
pub const DiagnosticList = diags.DiagnosticList;
|
pub const DiagnosticList = diags.DiagnosticList;
|
||||||
|
@ -1,320 +1,277 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const help_strings = @import("help_strings");
|
|
||||||
|
|
||||||
const list_fonts = @import("list_fonts.zig");
|
pub const DetectError = error{
|
||||||
const help = @import("help.zig");
|
/// Multiple actions were detected. You can specify at most one
|
||||||
const version = @import("version.zig");
|
/// action on the CLI otherwise the behavior desired is ambiguous.
|
||||||
const list_keybinds = @import("list_keybinds.zig");
|
MultipleActions,
|
||||||
const list_themes = @import("list_themes.zig");
|
|
||||||
const list_colors = @import("list_colors.zig");
|
|
||||||
const list_actions = @import("list_actions.zig");
|
|
||||||
const ssh_cache = @import("ssh_cache.zig");
|
|
||||||
const edit_config = @import("edit_config.zig");
|
|
||||||
const show_config = @import("show_config.zig");
|
|
||||||
const validate_config = @import("validate_config.zig");
|
|
||||||
const crash_report = @import("crash_report.zig");
|
|
||||||
const show_face = @import("show_face.zig");
|
|
||||||
const boo = @import("boo.zig");
|
|
||||||
|
|
||||||
/// Special commands that can be invoked via CLI flags. These are all
|
/// An unknown action was specified.
|
||||||
/// invoked by using `+<action>` as a CLI flag. The only exception is
|
InvalidAction,
|
||||||
/// "version" which can be invoked additionally with `--version`.
|
|
||||||
pub const Action = enum {
|
|
||||||
/// Output the version and exit
|
|
||||||
version,
|
|
||||||
|
|
||||||
/// Output help information for the CLI or configuration
|
|
||||||
help,
|
|
||||||
|
|
||||||
/// List available fonts
|
|
||||||
@"list-fonts",
|
|
||||||
|
|
||||||
/// List available keybinds
|
|
||||||
@"list-keybinds",
|
|
||||||
|
|
||||||
/// List available themes
|
|
||||||
@"list-themes",
|
|
||||||
|
|
||||||
/// List named RGB colors
|
|
||||||
@"list-colors",
|
|
||||||
|
|
||||||
/// List keybind actions
|
|
||||||
@"list-actions",
|
|
||||||
|
|
||||||
/// Manage SSH terminfo cache for automatic remote host setup
|
|
||||||
@"ssh-cache",
|
|
||||||
|
|
||||||
/// Edit the config file in the configured terminal editor.
|
|
||||||
@"edit-config",
|
|
||||||
|
|
||||||
/// Dump the config to stdout
|
|
||||||
@"show-config",
|
|
||||||
|
|
||||||
// Validate passed config file
|
|
||||||
@"validate-config",
|
|
||||||
|
|
||||||
// Show which font face Ghostty loads a codepoint from.
|
|
||||||
@"show-face",
|
|
||||||
|
|
||||||
// List, (eventually) view, and (eventually) send crash reports.
|
|
||||||
@"crash-report",
|
|
||||||
|
|
||||||
// Boo!
|
|
||||||
boo,
|
|
||||||
|
|
||||||
pub const Error = error{
|
|
||||||
/// Multiple actions were detected. You can specify at most one
|
|
||||||
/// action on the CLI otherwise the behavior desired is ambiguous.
|
|
||||||
MultipleActions,
|
|
||||||
|
|
||||||
/// An unknown action was specified.
|
|
||||||
InvalidAction,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// This should be returned by actions that want to print the help text.
|
|
||||||
pub const help_error = error.ActionHelpRequested;
|
|
||||||
|
|
||||||
/// Detect the action from CLI args.
|
|
||||||
pub fn detectCLI(alloc: Allocator) !?Action {
|
|
||||||
var iter = try std.process.argsWithAllocator(alloc);
|
|
||||||
defer iter.deinit();
|
|
||||||
return try detectIter(&iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Detect the action from any iterator, used primarily for tests.
|
|
||||||
pub fn detectIter(iter: anytype) Error!?Action {
|
|
||||||
var pending_help: bool = false;
|
|
||||||
var pending: ?Action = null;
|
|
||||||
while (iter.next()) |arg| {
|
|
||||||
// If we see a "-e" and we haven't seen a command yet, then
|
|
||||||
// we are done looking for commands. This special case enables
|
|
||||||
// `ghostty -e ghostty +command`. If we've seen a command we
|
|
||||||
// still want to keep looking because
|
|
||||||
// `ghostty +command -e +command` is invalid.
|
|
||||||
if (std.mem.eql(u8, arg, "-e") and pending == null) return null;
|
|
||||||
|
|
||||||
// Special case, --version always outputs the version no
|
|
||||||
// matter what, no matter what other args exist.
|
|
||||||
if (std.mem.eql(u8, arg, "--version")) return .version;
|
|
||||||
|
|
||||||
// --help matches "help" but if a subcommand is specified
|
|
||||||
// then we match the subcommand.
|
|
||||||
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
|
|
||||||
pending_help = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands must start with "+"
|
|
||||||
if (arg.len == 0 or arg[0] != '+') continue;
|
|
||||||
if (pending != null) return Error.MultipleActions;
|
|
||||||
pending = std.meta.stringToEnum(Action, arg[1..]) orelse return Error.InvalidAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have an action, we always return that action, even if we've
|
|
||||||
// seen "--help" or "-h" because the action may have its own help text.
|
|
||||||
if (pending != null) return pending;
|
|
||||||
|
|
||||||
// If we've seen "--help" or "-h" then we return the help action.
|
|
||||||
if (pending_help) return .help;
|
|
||||||
|
|
||||||
return pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the action. This returns the exit code to exit with.
|
|
||||||
pub fn run(self: Action, alloc: Allocator) !u8 {
|
|
||||||
return self.runMain(alloc) catch |err| switch (err) {
|
|
||||||
// If help is requested, then we use some comptime trickery
|
|
||||||
// to find this action in the help strings and output that.
|
|
||||||
help_error => err: {
|
|
||||||
inline for (@typeInfo(Action).@"enum".fields) |field| {
|
|
||||||
// Future note: for now we just output the help text directly
|
|
||||||
// to stdout. In the future we can style this much prettier
|
|
||||||
// for all commands by just changing this one place.
|
|
||||||
|
|
||||||
if (std.mem.eql(u8, field.name, @tagName(self))) {
|
|
||||||
const stdout = std.io.getStdOut().writer();
|
|
||||||
const text = @field(help_strings.Action, field.name) ++ "\n";
|
|
||||||
stdout.writeAll(text) catch |write_err| {
|
|
||||||
std.log.warn("failed to write help text: {}\n", .{write_err});
|
|
||||||
break :err 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
break :err 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break :err err;
|
|
||||||
},
|
|
||||||
else => err,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn runMain(self: Action, alloc: Allocator) !u8 {
|
|
||||||
return switch (self) {
|
|
||||||
.version => try version.run(alloc),
|
|
||||||
.help => try help.run(alloc),
|
|
||||||
.@"list-fonts" => try list_fonts.run(alloc),
|
|
||||||
.@"list-keybinds" => try list_keybinds.run(alloc),
|
|
||||||
.@"list-themes" => try list_themes.run(alloc),
|
|
||||||
.@"list-colors" => try list_colors.run(alloc),
|
|
||||||
.@"list-actions" => try list_actions.run(alloc),
|
|
||||||
.@"ssh-cache" => try ssh_cache.run(alloc),
|
|
||||||
.@"edit-config" => try edit_config.run(alloc),
|
|
||||||
.@"show-config" => try show_config.run(alloc),
|
|
||||||
.@"validate-config" => try validate_config.run(alloc),
|
|
||||||
.@"crash-report" => try crash_report.run(alloc),
|
|
||||||
.@"show-face" => try show_face.run(alloc),
|
|
||||||
.boo => try boo.run(alloc),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the filename associated with an action. This is a relative
|
|
||||||
/// path from the root src/ directory.
|
|
||||||
pub fn file(comptime self: Action) []const u8 {
|
|
||||||
comptime {
|
|
||||||
const filename = filename: {
|
|
||||||
const tag = @tagName(self);
|
|
||||||
var filename: [tag.len]u8 = undefined;
|
|
||||||
_ = std.mem.replace(u8, tag, "-", "_", &filename);
|
|
||||||
break :filename &filename;
|
|
||||||
};
|
|
||||||
|
|
||||||
return "cli/" ++ filename ++ ".zig";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the options of action. Supports generating shell completions
|
|
||||||
/// without duplicating the mapping from Action to relevant Option
|
|
||||||
/// @import(..) declaration.
|
|
||||||
pub fn options(comptime self: Action) type {
|
|
||||||
comptime {
|
|
||||||
return switch (self) {
|
|
||||||
.version => version.Options,
|
|
||||||
.help => help.Options,
|
|
||||||
.@"list-fonts" => list_fonts.Options,
|
|
||||||
.@"list-keybinds" => list_keybinds.Options,
|
|
||||||
.@"list-themes" => list_themes.Options,
|
|
||||||
.@"list-colors" => list_colors.Options,
|
|
||||||
.@"list-actions" => list_actions.Options,
|
|
||||||
.@"ssh-cache" => ssh_cache.Options,
|
|
||||||
.@"edit-config" => edit_config.Options,
|
|
||||||
.@"show-config" => show_config.Options,
|
|
||||||
.@"validate-config" => validate_config.Options,
|
|
||||||
.@"crash-report" => crash_report.Options,
|
|
||||||
.@"show-face" => show_face.Options,
|
|
||||||
.boo => boo.Options,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
test "parse action none" {
|
/// Detect the action from CLI args.
|
||||||
|
pub fn detectArgs(comptime E: type, alloc: Allocator) !?E {
|
||||||
|
var iter = try std.process.argsWithAllocator(alloc);
|
||||||
|
defer iter.deinit();
|
||||||
|
return try detectIter(E, &iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Detect the action from any iterator. Each iterator value should yield
|
||||||
|
/// a CLI argument such as "--foo".
|
||||||
|
///
|
||||||
|
/// The comptime type E must be an enum with the available actions.
|
||||||
|
/// If the type E has a decl `detectSpecialCase`, then it will be called
|
||||||
|
/// for each argument to allow handling of special cases. The function
|
||||||
|
/// signature for `detectSpecialCase` should be:
|
||||||
|
///
|
||||||
|
/// fn detectSpecialCase(arg: []const u8) ?SpecialCase(E)
|
||||||
|
///
|
||||||
|
pub fn detectIter(
|
||||||
|
comptime E: type,
|
||||||
|
iter: anytype,
|
||||||
|
) DetectError!?E {
|
||||||
|
var fallback: ?E = null;
|
||||||
|
var pending: ?E = null;
|
||||||
|
while (iter.next()) |arg| {
|
||||||
|
// Allow handling of special cases.
|
||||||
|
if (@hasDecl(E, "detectSpecialCase")) special: {
|
||||||
|
const special = E.detectSpecialCase(arg) orelse break :special;
|
||||||
|
switch (special) {
|
||||||
|
.action => |a| return a,
|
||||||
|
.fallback => |a| fallback = a,
|
||||||
|
.abort_if_no_action => if (pending == null) return null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commands must start with "+"
|
||||||
|
if (arg.len == 0 or arg[0] != '+') continue;
|
||||||
|
if (pending != null) return DetectError.MultipleActions;
|
||||||
|
pending = std.meta.stringToEnum(E, arg[1..]) orelse
|
||||||
|
return DetectError.InvalidAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have an action, we always return that action, even if we've
|
||||||
|
// seen "--help" or "-h" because the action may have its own help text.
|
||||||
|
if (pending != null) return pending;
|
||||||
|
|
||||||
|
// If we have no action but we have a fallback, then we return that.
|
||||||
|
if (fallback) |a| return a;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The action enum E can implement the decl `detectSpecialCase` to
|
||||||
|
/// return this enum in order to perform various special case actions.
|
||||||
|
pub fn SpecialCase(comptime E: type) type {
|
||||||
|
return union(enum) {
|
||||||
|
/// Immediately return this action.
|
||||||
|
action: E,
|
||||||
|
|
||||||
|
/// Return this action if no other action is found.
|
||||||
|
fallback: E,
|
||||||
|
|
||||||
|
/// If there is no pending action (we haven't seen an action yet)
|
||||||
|
/// then we should return no action. This is kind of weird but is
|
||||||
|
/// a special case to allow "-e" in Ghostty.
|
||||||
|
abort_if_no_action,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test "detect direct match" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
const Enum = enum { foo, bar, baz };
|
||||||
|
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
alloc,
|
alloc,
|
||||||
"--a=42 --b --b-f=false",
|
"+foo",
|
||||||
);
|
);
|
||||||
defer iter.deinit();
|
defer iter.deinit();
|
||||||
const action = try Action.detectIter(&iter);
|
const result = try detectIter(Enum, &iter);
|
||||||
try testing.expect(action == null);
|
try testing.expectEqual(Enum.foo, result.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "parse action version" {
|
test "detect invalid match" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
const Enum = enum { foo, bar, baz };
|
||||||
|
|
||||||
{
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
alloc,
|
||||||
alloc,
|
"+invalid",
|
||||||
"--a=42 --b --b-f=false --version",
|
);
|
||||||
);
|
defer iter.deinit();
|
||||||
defer iter.deinit();
|
try testing.expectError(
|
||||||
const action = try Action.detectIter(&iter);
|
DetectError.InvalidAction,
|
||||||
try testing.expect(action.? == .version);
|
detectIter(Enum, &iter),
|
||||||
}
|
);
|
||||||
|
|
||||||
{
|
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
|
||||||
alloc,
|
|
||||||
"--version --a=42 --b --b-f=false",
|
|
||||||
);
|
|
||||||
defer iter.deinit();
|
|
||||||
const action = try Action.detectIter(&iter);
|
|
||||||
try testing.expect(action.? == .version);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
|
||||||
alloc,
|
|
||||||
"--c=84 --d --version --a=42 --b --b-f=false",
|
|
||||||
);
|
|
||||||
defer iter.deinit();
|
|
||||||
const action = try Action.detectIter(&iter);
|
|
||||||
try testing.expect(action.? == .version);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "parse action plus" {
|
test "detect multiple actions" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
const Enum = enum { foo, bar, baz };
|
||||||
|
|
||||||
{
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
alloc,
|
||||||
alloc,
|
"+foo +bar",
|
||||||
"--a=42 --b --b-f=false +version",
|
);
|
||||||
);
|
defer iter.deinit();
|
||||||
defer iter.deinit();
|
try testing.expectError(
|
||||||
const action = try Action.detectIter(&iter);
|
DetectError.MultipleActions,
|
||||||
try testing.expect(action.? == .version);
|
detectIter(Enum, &iter),
|
||||||
}
|
);
|
||||||
|
|
||||||
{
|
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
|
||||||
alloc,
|
|
||||||
"+version --a=42 --b --b-f=false",
|
|
||||||
);
|
|
||||||
defer iter.deinit();
|
|
||||||
const action = try Action.detectIter(&iter);
|
|
||||||
try testing.expect(action.? == .version);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
|
||||||
alloc,
|
|
||||||
"--c=84 --d +version --a=42 --b --b-f=false",
|
|
||||||
);
|
|
||||||
defer iter.deinit();
|
|
||||||
const action = try Action.detectIter(&iter);
|
|
||||||
try testing.expect(action.? == .version);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "parse action plus ignores -e" {
|
test "detect no match" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
const Enum = enum { foo, bar, baz };
|
||||||
|
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--some-flag",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expect(result == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "detect special case action" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
const Enum = enum {
|
||||||
|
foo,
|
||||||
|
bar,
|
||||||
|
|
||||||
|
fn detectSpecialCase(arg: []const u8) ?SpecialCase(@This()) {
|
||||||
|
return if (std.mem.eql(u8, arg, "--special"))
|
||||||
|
.{ .action = .foo }
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
alloc,
|
alloc,
|
||||||
"--a=42 -e +version",
|
"--special +bar",
|
||||||
);
|
);
|
||||||
defer iter.deinit();
|
defer iter.deinit();
|
||||||
const action = try Action.detectIter(&iter);
|
const result = try detectIter(Enum, &iter);
|
||||||
try testing.expect(action == null);
|
try testing.expectEqual(Enum.foo, result.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
alloc,
|
alloc,
|
||||||
"+list-fonts --a=42 -e +version",
|
"+bar --special",
|
||||||
);
|
);
|
||||||
defer iter.deinit();
|
defer iter.deinit();
|
||||||
try testing.expectError(
|
const result = try detectIter(Enum, &iter);
|
||||||
Action.Error.MultipleActions,
|
try testing.expectEqual(Enum.foo, result.?);
|
||||||
Action.detectIter(&iter),
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"+bar",
|
||||||
);
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expectEqual(Enum.bar, result.?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "detect special case fallback" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
const Enum = enum {
|
||||||
|
foo,
|
||||||
|
bar,
|
||||||
|
|
||||||
|
fn detectSpecialCase(arg: []const u8) ?SpecialCase(@This()) {
|
||||||
|
return if (std.mem.eql(u8, arg, "--special"))
|
||||||
|
.{ .fallback = .foo }
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--special",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expectEqual(Enum.foo, result.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"+bar --special",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expectEqual(Enum.bar, result.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--special +bar",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expectEqual(Enum.bar, result.?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "detect special case abort_if_no_action" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
const Enum = enum {
|
||||||
|
foo,
|
||||||
|
bar,
|
||||||
|
|
||||||
|
fn detectSpecialCase(arg: []const u8) ?SpecialCase(@This()) {
|
||||||
|
return if (std.mem.eql(u8, arg, "-e"))
|
||||||
|
.abort_if_no_action
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"-e",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expect(result == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"+foo -e",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expectEqual(Enum.foo, result.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"-e +bar",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const result = try detectIter(Enum, &iter);
|
||||||
|
try testing.expect(result == null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const help_strings = @import("help_strings");
|
const help_strings = @import("help_strings");
|
||||||
const vaxis = @import("vaxis");
|
const vaxis = @import("vaxis");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const Config = @import("../config.zig").Config;
|
const Config = @import("../config.zig").Config;
|
||||||
const crash = @import("../crash/main.zig");
|
const crash = @import("../crash/main.zig");
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ const builtin = @import("builtin");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const configpkg = @import("../config.zig");
|
const configpkg = @import("../config.zig");
|
||||||
const internal_os = @import("../os/main.zig");
|
const internal_os = @import("../os/main.zig");
|
||||||
const Config = configpkg.Config;
|
const Config = configpkg.Config;
|
||||||
|
290
src/cli/ghostty.zig
Normal file
290
src/cli/ghostty.zig
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const help_strings = @import("help_strings");
|
||||||
|
const actionpkg = @import("action.zig");
|
||||||
|
const SpecialCase = actionpkg.SpecialCase;
|
||||||
|
|
||||||
|
const list_fonts = @import("list_fonts.zig");
|
||||||
|
const help = @import("help.zig");
|
||||||
|
const version = @import("version.zig");
|
||||||
|
const list_keybinds = @import("list_keybinds.zig");
|
||||||
|
const list_themes = @import("list_themes.zig");
|
||||||
|
const list_colors = @import("list_colors.zig");
|
||||||
|
const list_actions = @import("list_actions.zig");
|
||||||
|
const ssh_cache = @import("ssh_cache.zig");
|
||||||
|
const edit_config = @import("edit_config.zig");
|
||||||
|
const show_config = @import("show_config.zig");
|
||||||
|
const validate_config = @import("validate_config.zig");
|
||||||
|
const crash_report = @import("crash_report.zig");
|
||||||
|
const show_face = @import("show_face.zig");
|
||||||
|
const boo = @import("boo.zig");
|
||||||
|
|
||||||
|
/// Special commands that can be invoked via CLI flags. These are all
|
||||||
|
/// invoked by using `+<action>` as a CLI flag. The only exception is
|
||||||
|
/// "version" which can be invoked additionally with `--version`.
|
||||||
|
pub const Action = enum {
|
||||||
|
/// Output the version and exit
|
||||||
|
version,
|
||||||
|
|
||||||
|
/// Output help information for the CLI or configuration
|
||||||
|
help,
|
||||||
|
|
||||||
|
/// List available fonts
|
||||||
|
@"list-fonts",
|
||||||
|
|
||||||
|
/// List available keybinds
|
||||||
|
@"list-keybinds",
|
||||||
|
|
||||||
|
/// List available themes
|
||||||
|
@"list-themes",
|
||||||
|
|
||||||
|
/// List named RGB colors
|
||||||
|
@"list-colors",
|
||||||
|
|
||||||
|
/// List keybind actions
|
||||||
|
@"list-actions",
|
||||||
|
|
||||||
|
/// Manage SSH terminfo cache for automatic remote host setup
|
||||||
|
@"ssh-cache",
|
||||||
|
|
||||||
|
/// Edit the config file in the configured terminal editor.
|
||||||
|
@"edit-config",
|
||||||
|
|
||||||
|
/// Dump the config to stdout
|
||||||
|
@"show-config",
|
||||||
|
|
||||||
|
// Validate passed config file
|
||||||
|
@"validate-config",
|
||||||
|
|
||||||
|
// Show which font face Ghostty loads a codepoint from.
|
||||||
|
@"show-face",
|
||||||
|
|
||||||
|
// List, (eventually) view, and (eventually) send crash reports.
|
||||||
|
@"crash-report",
|
||||||
|
|
||||||
|
// Boo!
|
||||||
|
boo,
|
||||||
|
|
||||||
|
pub fn detectSpecialCase(arg: []const u8) ?SpecialCase(Action) {
|
||||||
|
// If we see a "-e" and we haven't seen a command yet, then
|
||||||
|
// we are done looking for commands. This special case enables
|
||||||
|
// `ghostty -e ghostty +command`. If we've seen a command we
|
||||||
|
// still want to keep looking because
|
||||||
|
// `ghostty +command -e +command` is invalid.
|
||||||
|
if (std.mem.eql(u8, arg, "-e")) return .abort_if_no_action;
|
||||||
|
|
||||||
|
// Special case, --version always outputs the version no
|
||||||
|
// matter what, no matter what other args exist.
|
||||||
|
if (std.mem.eql(u8, arg, "--version")) {
|
||||||
|
return .{ .action = .version };
|
||||||
|
}
|
||||||
|
|
||||||
|
// --help matches "help" but if a subcommand is specified
|
||||||
|
// then we match the subcommand.
|
||||||
|
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
|
||||||
|
return .{ .fallback = .help };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This should be returned by actions that want to print the help text.
|
||||||
|
pub const help_error = error.ActionHelpRequested;
|
||||||
|
|
||||||
|
/// Run the action. This returns the exit code to exit with.
|
||||||
|
pub fn run(self: Action, alloc: Allocator) !u8 {
|
||||||
|
return self.runMain(alloc) catch |err| switch (err) {
|
||||||
|
// If help is requested, then we use some comptime trickery
|
||||||
|
// to find this action in the help strings and output that.
|
||||||
|
help_error => err: {
|
||||||
|
inline for (@typeInfo(Action).@"enum".fields) |field| {
|
||||||
|
// Future note: for now we just output the help text directly
|
||||||
|
// to stdout. In the future we can style this much prettier
|
||||||
|
// for all commands by just changing this one place.
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, field.name, @tagName(self))) {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
const text = @field(help_strings.Action, field.name) ++ "\n";
|
||||||
|
stdout.writeAll(text) catch |write_err| {
|
||||||
|
std.log.warn("failed to write help text: {}\n", .{write_err});
|
||||||
|
break :err 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
break :err 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break :err err;
|
||||||
|
},
|
||||||
|
else => err,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn runMain(self: Action, alloc: Allocator) !u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.version => try version.run(alloc),
|
||||||
|
.help => try help.run(alloc),
|
||||||
|
.@"list-fonts" => try list_fonts.run(alloc),
|
||||||
|
.@"list-keybinds" => try list_keybinds.run(alloc),
|
||||||
|
.@"list-themes" => try list_themes.run(alloc),
|
||||||
|
.@"list-colors" => try list_colors.run(alloc),
|
||||||
|
.@"list-actions" => try list_actions.run(alloc),
|
||||||
|
.@"ssh-cache" => try ssh_cache.run(alloc),
|
||||||
|
.@"edit-config" => try edit_config.run(alloc),
|
||||||
|
.@"show-config" => try show_config.run(alloc),
|
||||||
|
.@"validate-config" => try validate_config.run(alloc),
|
||||||
|
.@"crash-report" => try crash_report.run(alloc),
|
||||||
|
.@"show-face" => try show_face.run(alloc),
|
||||||
|
.boo => try boo.run(alloc),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the filename associated with an action. This is a relative
|
||||||
|
/// path from the root src/ directory.
|
||||||
|
pub fn file(comptime self: Action) []const u8 {
|
||||||
|
comptime {
|
||||||
|
const filename = filename: {
|
||||||
|
const tag = @tagName(self);
|
||||||
|
var filename: [tag.len]u8 = undefined;
|
||||||
|
_ = std.mem.replace(u8, tag, "-", "_", &filename);
|
||||||
|
break :filename &filename;
|
||||||
|
};
|
||||||
|
|
||||||
|
return "cli/" ++ filename ++ ".zig";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the options of action. Supports generating shell completions
|
||||||
|
/// without duplicating the mapping from Action to relevant Option
|
||||||
|
/// @import(..) declaration.
|
||||||
|
pub fn options(comptime self: Action) type {
|
||||||
|
comptime {
|
||||||
|
return switch (self) {
|
||||||
|
.version => version.Options,
|
||||||
|
.help => help.Options,
|
||||||
|
.@"list-fonts" => list_fonts.Options,
|
||||||
|
.@"list-keybinds" => list_keybinds.Options,
|
||||||
|
.@"list-themes" => list_themes.Options,
|
||||||
|
.@"list-colors" => list_colors.Options,
|
||||||
|
.@"list-actions" => list_actions.Options,
|
||||||
|
.@"ssh-cache" => ssh_cache.Options,
|
||||||
|
.@"edit-config" => edit_config.Options,
|
||||||
|
.@"show-config" => show_config.Options,
|
||||||
|
.@"validate-config" => validate_config.Options,
|
||||||
|
.@"crash-report" => crash_report.Options,
|
||||||
|
.@"show-face" => show_face.Options,
|
||||||
|
.boo => boo.Options,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "parse action none" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--a=42 --b --b-f=false",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parse action version" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--a=42 --b --b-f=false --version",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action.? == .version);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--version --a=42 --b --b-f=false",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action.? == .version);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--c=84 --d --version --a=42 --b --b-f=false",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action.? == .version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parse action plus" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--a=42 --b --b-f=false +version",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action.? == .version);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"+version --a=42 --b --b-f=false",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action.? == .version);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--c=84 --d +version --a=42 --b --b-f=false",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action.? == .version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parse action plus ignores -e" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"--a=42 -e +version",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
const action = try actionpkg.detectIter(Action, &iter);
|
||||||
|
try testing.expect(action == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
alloc,
|
||||||
|
"+list-fonts --a=42 -e +version",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
try testing.expectError(
|
||||||
|
actionpkg.DetectError.MultipleActions,
|
||||||
|
actionpkg.detectIter(Action, &iter),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
|
|
||||||
// Note that this options struct doesn't implement the `help` decl like other
|
// Note that this options struct doesn't implement the `help` decl like other
|
||||||
// actions. That is because the help command is special and wants to handle its
|
// actions. That is because the help command is special and wants to handle its
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const helpgen_actions = @import("../input/helpgen_actions.zig");
|
const helpgen_actions = @import("../input/helpgen_actions.zig");
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const x11_color = @import("../terminal/main.zig").x11_color;
|
const x11_color = @import("../terminal/main.zig").x11_color;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const font = @import("../font/main.zig");
|
const font = @import("../font/main.zig");
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const Arena = std.heap.ArenaAllocator;
|
const Arena = std.heap.ArenaAllocator;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const configpkg = @import("../config.zig");
|
const configpkg = @import("../config.zig");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const inputpkg = @import("../input.zig");
|
const inputpkg = @import("../input.zig");
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const Config = @import("../config/Config.zig");
|
const Config = @import("../config/Config.zig");
|
||||||
const themepkg = @import("../config/theme.zig");
|
const themepkg = @import("../config/theme.zig");
|
||||||
const tui = @import("tui.zig");
|
const tui = @import("tui.zig");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const configpkg = @import("../config.zig");
|
const configpkg = @import("../config.zig");
|
||||||
const Config = configpkg.Config;
|
const Config = configpkg.Config;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const diagnostics = @import("diagnostics.zig");
|
const diagnostics = @import("diagnostics.zig");
|
||||||
const font = @import("../font/main.zig");
|
const font = @import("../font/main.zig");
|
||||||
|
@ -3,7 +3,7 @@ const fs = std.fs;
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const xdg = @import("../os/xdg.zig");
|
const xdg = @import("../os/xdg.zig");
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
pub const Entry = @import("ssh-cache/Entry.zig");
|
pub const Entry = @import("ssh-cache/Entry.zig");
|
||||||
pub const DiskCache = @import("ssh-cache/DiskCache.zig");
|
pub const DiskCache = @import("ssh-cache/DiskCache.zig");
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const args = @import("args.zig");
|
const args = @import("args.zig");
|
||||||
const Action = @import("action.zig").Action;
|
const Action = @import("ghostty.zig").Action;
|
||||||
const Config = @import("../config.zig").Config;
|
const Config = @import("../config.zig").Config;
|
||||||
const cli = @import("../cli.zig");
|
const cli = @import("../cli.zig");
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ pub const BackgroundImageFit = Config.BackgroundImageFit;
|
|||||||
pub const LinkPreviews = Config.LinkPreviews;
|
pub const LinkPreviews = Config.LinkPreviews;
|
||||||
|
|
||||||
// Alternate APIs
|
// Alternate APIs
|
||||||
pub const CAPI = @import("config/CAPI.zig");
|
pub const CApi = @import("config/CApi.zig");
|
||||||
pub const Wasm = if (!builtin.target.cpu.arch.isWasm()) struct {} else @import("config/Wasm.zig");
|
pub const Wasm = if (!builtin.target.cpu.arch.isWasm()) struct {} else @import("config/Wasm.zig");
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
@ -814,6 +814,22 @@ palette: Palette = .{},
|
|||||||
/// On macOS, changing this configuration requires restarting Ghostty completely.
|
/// On macOS, changing this configuration requires restarting Ghostty completely.
|
||||||
@"background-opacity": f64 = 1.0,
|
@"background-opacity": f64 = 1.0,
|
||||||
|
|
||||||
|
/// Applies background opacity to cells with an explicit background color
|
||||||
|
/// set.
|
||||||
|
///
|
||||||
|
/// Normally, `background-opacity` is only applied to the window background.
|
||||||
|
/// If a cell has an explicit background color set, such as red, then that
|
||||||
|
/// background color will be fully opaque. An effect of this is that some
|
||||||
|
/// terminal applications that repaint the background color of the terminal
|
||||||
|
/// such as a Neovim and Tmux may not respect the `background-opacity`
|
||||||
|
/// (by design).
|
||||||
|
///
|
||||||
|
/// Setting this to `true` will apply the `background-opacity` to all cells
|
||||||
|
/// regardless of whether they have an explicit background color set or not.
|
||||||
|
///
|
||||||
|
/// Available since: 1.2.0
|
||||||
|
@"background-opacity-cells": bool = false,
|
||||||
|
|
||||||
/// Whether to blur the background when `background-opacity` is less than 1.
|
/// Whether to blur the background when `background-opacity` is less than 1.
|
||||||
///
|
///
|
||||||
/// Valid values are:
|
/// Valid values are:
|
||||||
|
@ -30,7 +30,7 @@ pub const GlobalState = struct {
|
|||||||
|
|
||||||
gpa: ?GPA,
|
gpa: ?GPA,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
action: ?cli.Action,
|
action: ?cli.ghostty.Action,
|
||||||
logging: Logging,
|
logging: Logging,
|
||||||
rlimits: ResourceLimits = .{},
|
rlimits: ResourceLimits = .{},
|
||||||
|
|
||||||
@ -92,7 +92,10 @@ pub const GlobalState = struct {
|
|||||||
unreachable;
|
unreachable;
|
||||||
|
|
||||||
// We first try to parse any action that we may be executing.
|
// We first try to parse any action that we may be executing.
|
||||||
self.action = try cli.Action.detectCLI(self.alloc);
|
self.action = try cli.action.detectArgs(
|
||||||
|
cli.ghostty.Action,
|
||||||
|
self.alloc,
|
||||||
|
);
|
||||||
|
|
||||||
// If we have an action executing, we disable logging by default
|
// If we have an action executing, we disable logging by default
|
||||||
// since we write to stderr we don't want logs messing up our
|
// since we write to stderr we don't want logs messing up our
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Config = @import("config/Config.zig");
|
const Config = @import("config/Config.zig");
|
||||||
const Action = @import("cli/action.zig").Action;
|
const Action = @import("cli.zig").ghostty.Action;
|
||||||
const KeybindAction = @import("input/Binding.zig").Action;
|
const KeybindAction = @import("input/Binding.zig").Action;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user