Update Ghostty integration to latest libghostty-vt API #535
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| DOTNET_VERSION: '10.0.x' | |
| DOTNET_NOLOGO: true | |
| DOTNET_CLI_TELEMETRY_OPTOUT: true | |
| DOTNET_NUGET_SIGNATURE_VERIFICATION: false | |
| jobs: | |
| build: | |
| name: Build & Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| needs: [native-build-macos, native-build-linux, native-build-windows] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Download macOS arm64 native | |
| if: matrix.os == 'macos-latest' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-osx-arm64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/osx-arm64/native/ | |
| - name: Download macOS x64 native | |
| if: matrix.os == 'macos-latest' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-osx-x64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/osx-x64/native/ | |
| - name: Download Linux x64 native | |
| if: matrix.os == 'ubuntu-latest' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-linux-x64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.Linux64/runtimes/linux-x64/native/ | |
| - name: Download Linux arm64 native | |
| if: matrix.os == 'ubuntu-latest' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-linux-arm64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.Linux64/runtimes/linux-arm64/native/ | |
| - name: Download Windows x64 native | |
| if: matrix.os == 'windows-latest' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-win-x64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.Win64/runtimes/win-x64/native/ | |
| - name: Stage native artifacts for managed interop (macOS) | |
| if: matrix.os == 'macos-latest' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| for rid in osx-arm64 osx-x64; do | |
| src="src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/${rid}/native" | |
| dst_interop="src/RoyalTerminal.Rendering.Interop.Ghostty/runtimes/${rid}/native" | |
| dst_fixture="native/${rid}" | |
| mkdir -p "${dst_interop}" "${dst_fixture}" | |
| cp -f "${src}"/* "${dst_interop}/" | |
| cp -f "${src}"/* "${dst_fixture}/" | |
| done | |
| ls -la src/RoyalTerminal.Rendering.Interop.Ghostty/runtimes/osx-arm64/native/ | |
| - name: Stage native artifacts for managed interop (Linux) | |
| if: matrix.os == 'ubuntu-latest' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| for rid in linux-x64 linux-arm64; do | |
| src="src/RoyalTerminal.GhosttySharp.Native.Linux64/runtimes/${rid}/native" | |
| dst_interop="src/RoyalTerminal.Rendering.Interop.Ghostty/runtimes/${rid}/native" | |
| dst_fixture="native/${rid}" | |
| mkdir -p "${dst_interop}" "${dst_fixture}" | |
| cp -f "${src}"/* "${dst_interop}/" | |
| cp -f "${src}"/* "${dst_fixture}/" | |
| done | |
| ls -la src/RoyalTerminal.Rendering.Interop.Ghostty/runtimes/linux-x64/native/ | |
| - name: Stage native artifacts for managed interop (Windows) | |
| if: matrix.os == 'windows-latest' | |
| shell: pwsh | |
| run: | | |
| $rid = "win-x64" | |
| $src = "src/RoyalTerminal.GhosttySharp.Native.Win64/runtimes/$rid/native" | |
| $dstInterop = "src/RoyalTerminal.Rendering.Interop.Ghostty/runtimes/$rid/native" | |
| $dstFixture = "native/$rid" | |
| New-Item -Path $dstInterop -ItemType Directory -Force | Out-Null | |
| New-Item -Path $dstFixture -ItemType Directory -Force | Out-Null | |
| Copy-Item "$src/*" $dstInterop -Recurse -Force | |
| Copy-Item "$src/*" $dstFixture -Recurse -Force | |
| Get-ChildItem $dstInterop | Format-Table Name, Length -AutoSize | |
| - name: Restore | |
| run: dotnet restore | |
| - name: Build | |
| run: dotnet build -c Release --no-restore | |
| - name: Test (Unit - Batches) | |
| shell: bash | |
| env: | |
| ROYALTERMINAL_TEST_BLAME_CRASH: ${{ matrix.os == 'ubuntu-latest' && 'true' || 'false' }} | |
| ROYALTERMINAL_TEST_BLAME_HANG: ${{ matrix.os == 'ubuntu-latest' && 'true' || 'false' }} | |
| ROYALTERMINAL_TEST_BLAME_HANG_TIMEOUT: 5m | |
| run: bash scripts/run-unit-test-batches.sh | |
| - name: Test (Mode Startup Smoke) | |
| run: dotnet test tests/RoyalTerminal.Tests/RoyalTerminal.Tests.csproj -c Release --no-build --filter "(FullyQualifiedName~TerminalModeResolverTests)|(FullyQualifiedName~Headless_FallbackParity_AutoAndManaged_PreserveKeyboardMousePasteAndResize_WhenHostedInScrollViewer)" --logger "trx;LogFileName=mode-startup-smoke-results.trx" --results-directory ./test-results | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: test-results-${{ matrix.os }} | |
| path: test-results/ | |
| retention-days: 7 | |
| native-build-macos: | |
| name: Native Build (macOS) | |
| # Pin macOS 15 for reproducible SDK compatibility with the native artifacts. | |
| runs-on: macos-15 | |
| strategy: | |
| matrix: | |
| arch: [arm64, x64] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - name: Setup Zig | |
| uses: mlugg/setup-zig@v2 | |
| with: | |
| version: 0.16.0 | |
| cache-key: ${{ matrix.arch }} | |
| - name: Build libghostty-vt | |
| working-directory: external/ghostty | |
| run: | | |
| if [ "${{ matrix.arch }}" = "arm64" ]; then | |
| zig build -Doptimize=ReleaseFast -Dapp-runtime=none -Demit-lib-vt=true -Demit-xcframework=false -Demit-macos-app=false | |
| else | |
| zig build -Doptimize=ReleaseFast -Dapp-runtime=none -Demit-lib-vt=true -Demit-xcframework=false -Demit-macos-app=false -Dtarget=x86_64-macos | |
| fi | |
| - name: Build ghostty-renderer-capi | |
| working-directory: native/ghostty-renderer-capi | |
| run: | | |
| if [ "${{ matrix.arch }}" = "arm64" ]; then | |
| zig build -Doptimize=ReleaseFast | |
| else | |
| zig build -Doptimize=ReleaseFast -Dtarget=x86_64-macos | |
| fi | |
| - name: Collect artifacts | |
| run: | | |
| mkdir -p artifacts/osx-${{ matrix.arch }}/native | |
| find external/ghostty/zig-out -name "libghostty-vt*.dylib" -exec cp -L {} artifacts/osx-${{ matrix.arch }}/native/ \; | |
| if [ -f native/ghostty-renderer-capi/zig-out/lib/libghostty-renderer-capi.dylib ]; then | |
| cp -L native/ghostty-renderer-capi/zig-out/lib/libghostty-renderer-capi.dylib artifacts/osx-${{ matrix.arch }}/native/ | |
| fi | |
| ls -la artifacts/osx-${{ matrix.arch }}/native/ | |
| - name: Verify required native artifacts (macOS) | |
| run: | | |
| set -euo pipefail | |
| artifact_dir="artifacts/osx-${{ matrix.arch }}/native" | |
| required=( | |
| "libghostty-vt.dylib" | |
| "libghostty-renderer-capi.dylib" | |
| ) | |
| for file in "${required[@]}"; do | |
| if [ ! -f "${artifact_dir}/${file}" ]; then | |
| echo "::error::Missing required macOS native artifact: ${file}" | |
| exit 1 | |
| fi | |
| done | |
| - name: Upload native library | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: native-osx-${{ matrix.arch }} | |
| path: artifacts/osx-${{ matrix.arch }}/native/ | |
| retention-days: 7 | |
| native-build-linux: | |
| name: Native Build (Linux) | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| matrix: | |
| include: | |
| - arch: x64 | |
| runner: ubuntu-latest | |
| zig-target: x86_64-linux-gnu | |
| - arch: arm64 | |
| runner: ubuntu-24.04-arm | |
| zig-target: aarch64-linux-gnu | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| pkg-config \ | |
| libbz2-dev \ | |
| libfreetype6-dev \ | |
| libharfbuzz-dev \ | |
| libfontconfig1-dev \ | |
| libpng-dev \ | |
| zlib1g-dev \ | |
| libonig-dev \ | |
| glslang-dev \ | |
| libspirv-cross-c-shared-dev | |
| multiarch="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" | |
| if [ -f "/usr/lib/${multiarch}/libbz2.so" ] && [ ! -e "/usr/lib/${multiarch}/libbzip2.so" ]; then | |
| sudo ln -s "/usr/lib/${multiarch}/libbz2.so" "/usr/lib/${multiarch}/libbzip2.so" | |
| fi | |
| if [ -f "/usr/lib/${multiarch}/libbz2.a" ] && [ ! -e "/usr/lib/${multiarch}/libbzip2.a" ]; then | |
| sudo ln -s "/usr/lib/${multiarch}/libbz2.a" "/usr/lib/${multiarch}/libbzip2.a" | |
| fi | |
| - name: Setup Zig | |
| uses: mlugg/setup-zig@v2 | |
| with: | |
| version: 0.16.0 | |
| cache-key: ${{ matrix.arch }} | |
| - name: Build libghostty-vt | |
| working-directory: external/ghostty | |
| run: | | |
| # Keep Linux native packages on a portable CPU baseline. A runner-native | |
| # Ghostty build can SIGILL during terminal/PageList startup on another | |
| # machine with the same RID. Do not force -fsys dependencies here: | |
| # explicit targets make Zig use cross-target system-library discovery. | |
| build_args=( | |
| build | |
| -Doptimize=ReleaseFast | |
| -Dapp-runtime=none | |
| -Demit-lib-vt=true | |
| -Dtarget=${{ matrix.zig-target }} | |
| -Dsimd=false | |
| ) | |
| zig "${build_args[@]}" | |
| - name: Build ghostty-renderer-capi | |
| working-directory: native/ghostty-renderer-capi | |
| run: | | |
| build_args=(build -Doptimize=ReleaseFast -Dtarget=${{ matrix.zig-target }}) | |
| zig "${build_args[@]}" | |
| - name: Collect artifacts | |
| run: | | |
| mkdir -p artifacts/linux-${{ matrix.arch }}/native | |
| find external/ghostty/zig-out -name "libghostty-vt.so*" -exec cp -L {} artifacts/linux-${{ matrix.arch }}/native/ \; | |
| find native/ghostty-renderer-capi/zig-out -name "libghostty-renderer-capi.so*" -exec cp -L {} artifacts/linux-${{ matrix.arch }}/native/ \; || true | |
| for base in libghostty-vt libghostty-renderer-capi; do | |
| if [ ! -f "artifacts/linux-${{ matrix.arch }}/native/${base}.so" ]; then | |
| candidate="$(find "artifacts/linux-${{ matrix.arch }}/native" -maxdepth 1 -type f -name "${base}.so*" | head -n1 || true)" | |
| if [ -n "${candidate}" ]; then | |
| cp -f "${candidate}" "artifacts/linux-${{ matrix.arch }}/native/${base}.so" | |
| fi | |
| fi | |
| done | |
| ls -la artifacts/linux-${{ matrix.arch }}/native/ | |
| - name: Verify required native artifacts (Linux) | |
| run: | | |
| set -euo pipefail | |
| artifact_dir="artifacts/linux-${{ matrix.arch }}/native" | |
| required=( | |
| "libghostty-vt.so" | |
| "libghostty-renderer-capi.so" | |
| ) | |
| for file in "${required[@]}"; do | |
| if [ ! -f "${artifact_dir}/${file}" ]; then | |
| echo "::error::Missing required Linux native artifact: ${file}" | |
| exit 1 | |
| fi | |
| done | |
| - name: Upload native library | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: native-linux-${{ matrix.arch }} | |
| path: artifacts/linux-${{ matrix.arch }}/native/ | |
| retention-days: 7 | |
| native-build-windows: | |
| name: Native Build (Windows ${{ matrix.arch }}) | |
| runs-on: windows-latest | |
| strategy: | |
| matrix: | |
| arch: [x64, arm64] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - name: Setup Zig | |
| uses: mlugg/setup-zig@v2 | |
| with: | |
| version: 0.16.0 | |
| cache-key: ${{ matrix.arch }} | |
| - name: Build libghostty-vt | |
| working-directory: external/ghostty | |
| shell: bash | |
| run: | | |
| target="" | |
| simd="" | |
| if [ "${{ matrix.arch }}" = "arm64" ]; then | |
| target="-Dtarget=aarch64-windows-gnu" | |
| # Zig 0.16.0's Windows ARM64 stdlib stack-trace code fails to | |
| # compile when Ghostty's vendored SIMD archive is enabled. | |
| simd="-Dsimd=false" | |
| fi | |
| zig build -Doptimize=ReleaseFast -Dapp-runtime=none -Demit-lib-vt=true ${target} ${simd} | |
| - name: Build ghostty-renderer-capi | |
| working-directory: native/ghostty-renderer-capi | |
| shell: bash | |
| run: | | |
| target="" | |
| if [ "${{ matrix.arch }}" = "arm64" ]; then | |
| target="-Dtarget=aarch64-windows-gnu" | |
| fi | |
| zig build -Doptimize=ReleaseFast ${target} | |
| - name: Collect artifacts | |
| shell: bash | |
| run: | | |
| mkdir -p artifacts/win-${{ matrix.arch }}/native | |
| find external/ghostty/zig-out \( -name "ghostty-vt.dll" -o -name "libghostty-vt.dll" \) -exec cp -L {} artifacts/win-${{ matrix.arch }}/native/ \; | |
| find native/ghostty-renderer-capi/zig-out \( -name "ghostty-renderer-capi.dll" -o -name "libghostty-renderer-capi.dll" \) -exec cp -L {} artifacts/win-${{ matrix.arch }}/native/ \; || true | |
| for base in ghostty-vt ghostty-renderer-capi; do | |
| if [ ! -f "artifacts/win-${{ matrix.arch }}/native/${base}.dll" ] && [ -f "artifacts/win-${{ matrix.arch }}/native/lib${base}.dll" ]; then | |
| cp -f "artifacts/win-${{ matrix.arch }}/native/lib${base}.dll" "artifacts/win-${{ matrix.arch }}/native/${base}.dll" | |
| fi | |
| done | |
| ls -la artifacts/win-${{ matrix.arch }}/native/ | |
| - name: Verify required native artifacts (Windows) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| artifact_dir="artifacts/win-${{ matrix.arch }}/native" | |
| required=( | |
| "ghostty-vt.dll" | |
| "ghostty-renderer-capi.dll" | |
| ) | |
| for file in "${required[@]}"; do | |
| if [ ! -f "${artifact_dir}/${file}" ]; then | |
| echo "::error::Missing required Windows native artifact: ${file}" | |
| exit 1 | |
| fi | |
| done | |
| - name: Upload native library | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: native-win-${{ matrix.arch }} | |
| path: artifacts/win-${{ matrix.arch }}/native/ | |
| retention-days: 7 | |
| integration-tests: | |
| name: Integration Tests (macOS) | |
| runs-on: macos-latest | |
| needs: build | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Download native library | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-osx-arm64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/osx-arm64/native/ | |
| - name: Stage native artifacts for managed interop (macOS) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| rid="osx-arm64" | |
| src="src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/${rid}/native" | |
| dst_interop="src/RoyalTerminal.Rendering.Interop.Ghostty/runtimes/${rid}/native" | |
| dst_fixture="native/${rid}" | |
| mkdir -p "${dst_interop}" "${dst_fixture}" | |
| cp -f "${src}"/* "${dst_interop}/" | |
| cp -f "${src}"/* "${dst_fixture}/" | |
| ls -la "${dst_interop}" | |
| - name: Run integration tests | |
| run: dotnet test tests/RoyalTerminal.IntegrationTests/RoyalTerminal.IntegrationTests.csproj -c Release --logger "trx;LogFileName=integration-results.trx" --results-directory ./test-results | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: integration-test-results | |
| path: test-results/ | |
| retention-days: 7 | |
| pack: | |
| name: Pack NuGet | |
| runs-on: ubuntu-latest | |
| needs: [build, integration-tests] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: false | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| # Download all native artifacts | |
| - name: Download macOS arm64 native | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: native-osx-arm64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/osx-arm64/native/ | |
| - name: Download macOS x64 native | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-osx-x64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/osx-x64/native/ | |
| - name: Download Linux x64 native | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-linux-x64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.Linux64/runtimes/linux-x64/native/ | |
| - name: Download Linux arm64 native | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-linux-arm64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.Linux64/runtimes/linux-arm64/native/ | |
| - name: Download Windows x64 native | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-win-x64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.Win64/runtimes/win-x64/native/ | |
| - name: Download Windows arm64 native | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: native-win-arm64 | |
| path: src/RoyalTerminal.GhosttySharp.Native.Win64/runtimes/win-arm64/native/ | |
| - name: Verify downloaded native artifacts | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| check_files() { | |
| local dir="$1" | |
| shift | |
| for file in "$@"; do | |
| if [ ! -f "${dir}/${file}" ]; then | |
| echo "::error::Missing required native artifact ${file} in ${dir}" | |
| exit 1 | |
| fi | |
| done | |
| } | |
| check_files "src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/osx-arm64/native" \ | |
| "libghostty-vt.dylib" "libghostty-renderer-capi.dylib" | |
| check_files "src/RoyalTerminal.GhosttySharp.Native.OSX/runtimes/osx-x64/native" \ | |
| "libghostty-vt.dylib" "libghostty-renderer-capi.dylib" | |
| check_files "src/RoyalTerminal.GhosttySharp.Native.Linux64/runtimes/linux-x64/native" \ | |
| "libghostty-vt.so" "libghostty-renderer-capi.so" | |
| check_files "src/RoyalTerminal.GhosttySharp.Native.Linux64/runtimes/linux-arm64/native" \ | |
| "libghostty-vt.so" "libghostty-renderer-capi.so" | |
| check_files "src/RoyalTerminal.GhosttySharp.Native.Win64/runtimes/win-x64/native" \ | |
| "ghostty-vt.dll" "ghostty-renderer-capi.dll" | |
| check_files "src/RoyalTerminal.GhosttySharp.Native.Win64/runtimes/win-arm64/native" \ | |
| "ghostty-vt.dll" "ghostty-renderer-capi.dll" | |
| - name: Pack all packable projects | |
| shell: bash | |
| run: bash scripts/pack-nuget.sh --configuration Release --output artifacts | |
| - name: List packages | |
| run: ls -la artifacts/*.nupkg | |
| - name: Upload NuGet packages | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: nuget-packages | |
| path: artifacts/*.nupkg | |
| retention-days: 30 |