1#!/usr/bin/env bash
2
3set -euo pipefail
4
5SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6WEB_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
7REPO_DIR="$(cd "${WEB_DIR}/../.." && pwd)"
8CANONICAL_VENDOR_DIR="${REPO_DIR}/native/libghostty-vt"
9VENDOR_DIR="${WEB_DIR}/src/terminal/ghostty/vendor"
10
11GHOSTTY_REVISION="$(tr -d '[:space:]' < "${CANONICAL_VENDOR_DIR}/VERSION")"
12GHOSTTY_SOURCE_DIR="${GHOSTTY_SOURCE_DIR:-${HOME}/.cache/t3code/ghostty-${GHOSTTY_REVISION:0:8}}"
13GHOSTTY_ZIG_VERSION="${GHOSTTY_ZIG_VERSION:-0.15.2}"
14GHOSTTY_ZIG="${GHOSTTY_ZIG:-}"
15
16log() {
17 printf '[libghostty-vt-wasm] %s\n' "$*"
18}
19
20die() {
21 printf '[libghostty-vt-wasm] error: %s\n' "$*" >&2
22 exit 1
23}
24
25require_cmd() {
26 command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
27}
28
29ensure_zig() {
30 if [[ -n "${GHOSTTY_ZIG}" ]]; then
31 [[ -x "${GHOSTTY_ZIG}" ]] || die "GHOSTTY_ZIG is not executable: ${GHOSTTY_ZIG}"
32 return
33 fi
34 if command -v zig >/dev/null 2>&1 && [[ "$(zig version)" == "${GHOSTTY_ZIG_VERSION}" ]]; then
35 GHOSTTY_ZIG="$(command -v zig)"
36 return
37 fi
38
39 local host_os host_arch cache_dir
40 host_os="$(uname -s | tr '[:upper:]' '[:lower:]')"
41 host_arch="$(uname -m)"
42 case "${host_os}" in
43 darwin) host_os="macos" ;;
44 linux) ;;
45 *) die "unsupported host OS for Zig download: ${host_os}" ;;
46 esac
47 case "${host_arch}" in
48 arm64) host_arch="aarch64" ;;
49 aarch64 | x86_64) ;;
50 *) die "unsupported host architecture: ${host_arch}" ;;
51 esac
52
53 cache_dir="${HOME}/.cache/t3code/zig-${GHOSTTY_ZIG_VERSION}"
54 GHOSTTY_ZIG="${cache_dir}/zig"
55 if [[ -x "${GHOSTTY_ZIG}" ]]; then
56 return
57 fi
58
59 require_cmd curl
60 require_cmd tar
61 mkdir -p "${cache_dir}"
62 log "downloading Zig ${GHOSTTY_ZIG_VERSION}"
63 curl -fsSL \
64 "https://ziglang.org/download/${GHOSTTY_ZIG_VERSION}/zig-${host_arch}-${host_os}-${GHOSTTY_ZIG_VERSION}.tar.xz" \
65 | tar -xJ --strip-components=1 -C "${cache_dir}"
66}
67
68ensure_ghostty_source() {
69 require_cmd git
70 if [[ ! -d "${GHOSTTY_SOURCE_DIR}/.git" ]]; then
71 mkdir -p "$(dirname "${GHOSTTY_SOURCE_DIR}")"
72 log "cloning Ghostty ${GHOSTTY_REVISION}"
73 git clone --filter=blob:none --no-checkout https://github.com/ghostty-org/ghostty.git \
74 "${GHOSTTY_SOURCE_DIR}"
75 fi
76
77 # A cached checkout may still be on a previously pinned revision; converge on
78 # the pinned one instead of failing the rebuild.
79 local actual_revision
80 actual_revision="$(git -C "${GHOSTTY_SOURCE_DIR}" rev-parse HEAD 2>/dev/null || echo none)"
81 if [[ "${actual_revision}" != "${GHOSTTY_REVISION}" ]]; then
82 log "checking out Ghostty ${GHOSTTY_REVISION}"
83 git -C "${GHOSTTY_SOURCE_DIR}" fetch --depth=1 origin "${GHOSTTY_REVISION}"
84 git -C "${GHOSTTY_SOURCE_DIR}" checkout --detach "${GHOSTTY_REVISION}"
85 fi
86
87 actual_revision="$(git -C "${GHOSTTY_SOURCE_DIR}" rev-parse HEAD)"
88 [[ "${actual_revision}" == "${GHOSTTY_REVISION}" ]] || \
89 die "expected Ghostty ${GHOSTTY_REVISION}, found ${actual_revision}"
90}
91
92ensure_zig
93ensure_ghostty_source
94
95build_root="$(mktemp -d)"
96trap 'rm -rf "${build_root}"' EXIT
97
98log "building ${GHOSTTY_REVISION} for wasm32-freestanding"
99(
100 cd "${GHOSTTY_SOURCE_DIR}"
101 # The pinned revision rides along as semver build metadata so the artifact
102 # identifies its own provenance through ghostty_build_info(); mobile's
103 # VERSION file stays the single source of truth for the pin.
104 "${GHOSTTY_ZIG}" build \
105 -Demit-lib-vt \
106 -Dtarget=wasm32-freestanding \
107 -Doptimize=ReleaseSmall \
108 -Dstrip=true \
109 -Dlib-version-string="0.1.0-dev+${GHOSTTY_REVISION}" \
110 -p "${build_root}"
111)
112
113mkdir -p "${VENDOR_DIR}"
114cp "${build_root}/bin/ghostty-vt.wasm" "${VENDOR_DIR}/ghostty-vt.wasm"
115"${GHOSTTY_ZIG}" build-exe \
116 "${SCRIPT_DIR}/ghostty-write-pty.zig" \
117 -target wasm32-freestanding \
118 -O ReleaseSmall \
119 -fno-entry \
120 -rdynamic \
121 -femit-bin="${VENDOR_DIR}/ghostty-write-pty.wasm"
122chmod 0644 "${VENDOR_DIR}/ghostty-write-pty.wasm"
123log "wrote ${VENDOR_DIR}/ghostty-vt.wasm"