Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/mobile/modules/t3-terminal/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,8 +26,10 @@ Vendored Ghostty revision and license details are in `THIRD_PARTY_NOTICES.md`.

## Rebuilding GhosttyKit

The checked-in `GhosttyKit.xcframework` is built from the Ghostty custom-I/O fork (https://github.com/Yash-Singh1/ghostty/tree/custom-io).
Set the directory to the cloned repository checked out on the `custom-io` branch to `GHOSTTY_SOURCE_DIR`.
The checked-in `GhosttyKit.xcframework` is built from a pinned revision of the Ghostty custom-I/O
fork. The build applies the patches in `scripts/libghostty-ios-patches`, including Ghostty's upstream
fix for display callbacks that outlive their renderer. Set `GHOSTTY_SOURCE_DIR` to use an existing
checkout; otherwise the script creates a pinned checkout under `~/.cache/t3code`.

```bash
apps/mobile/modules/t3-terminal/scripts/build-libghostty-ios16.sh
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/modules/t3-terminal/THIRD_PARTY_NOTICES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,7 @@ iOS 16 support fork. That fork was created from VVTerm's custom-I/O Ghostty fork
- Custom-I/O base fork: https://github.com/wiedymi/ghostty/tree/custom-io
- Vendored source fork: https://github.com/Yash-Singh1/ghostty/tree/custom-io
- Vendored revision: `d36c3b8dffd0d756dd5e5f4933962f774a0e6753`
- Applied renderer lifetime fix: https://github.com/ghostty-org/ghostty/commit/4b4a5b2411091ccda2cd6373631ec7ccd184c577
- Reference integration: https://github.com/vivy-company/vvterm
- License: MIT

Expand Down
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,8 +5,12 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MODULE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
VENDOR_DIR="${MODULE_DIR}/Vendor/libghostty"
PATCH_DIR="${SCRIPT_DIR}/libghostty-ios-patches"
LAYER_LIFETIME_PATCH="${PATCH_DIR}/0001-clear-display-callback-before-layer-release.patch"

GHOSTTY_SOURCE_DIR="${GHOSTTY_SOURCE_DIR:-${HOME}/ghostty}"
GHOSTTY_REVISION="d36c3b8dffd0d756dd5e5f4933962f774a0e6753"
GHOSTTY_SOURCE_DIR="${GHOSTTY_SOURCE_DIR:-${HOME}/.cache/t3code/ghostty-${GHOSTTY_REVISION:0:8}}"
GHOSTTY_REPOSITORY_URL="${GHOSTTY_REPOSITORY_URL:-https://github.com/Yash-Singh1/ghostty.git}"
GHOSTTY_ZIG_VERSION="${GHOSTTY_ZIG_VERSION:-0.15.2}"
GHOSTTY_ZIG="${GHOSTTY_ZIG:-}"

Expand DownExpand Up@@ -56,11 +60,67 @@ ensure_zig() {
| tar -xJ --strip-components=1 -C "${cache_dir}"
}

ensure_ghostty_source() {
if ! git -C "${GHOSTTY_SOURCE_DIR}" rev-parse --git-dir >/dev/null 2>&1; then
require_cmd git
log "cloning Ghostty ${GHOSTTY_REVISION}"
git clone --filter=blob:none --no-checkout "${GHOSTTY_REPOSITORY_URL}" \
"${GHOSTTY_SOURCE_DIR}"
git -C "${GHOSTTY_SOURCE_DIR}" fetch --depth=1 origin "${GHOSTTY_REVISION}"
git -C "${GHOSTTY_SOURCE_DIR}" checkout --detach "${GHOSTTY_REVISION}"
fi

local actual_revision
actual_revision="$(git -C "${GHOSTTY_SOURCE_DIR}" rev-parse HEAD)"
[[ "${actual_revision}" == "${GHOSTTY_REVISION}" ]] || \
die "expected Ghostty ${GHOSTTY_REVISION}, found ${actual_revision}"
}

apply_ghostty_patch() {
[[ -f "${LAYER_LIFETIME_PATCH}" ]] || \
die "missing required patch: ${LAYER_LIFETIME_PATCH}"

local patch_name
patch_name="$(basename "${LAYER_LIFETIME_PATCH}")"
if git -C "${GHOSTTY_SOURCE_DIR}" apply --reverse --check "${LAYER_LIFETIME_PATCH}" >/dev/null 2>&1; then
log "patch already applied: ${patch_name}"
return
fi

log "applying patch: ${patch_name}"
git -C "${GHOSTTY_SOURCE_DIR}" apply --check "${LAYER_LIFETIME_PATCH}"
git -C "${GHOSTTY_SOURCE_DIR}" apply "${LAYER_LIFETIME_PATCH}"
}

validate_ghostty_source() (
umask 077

scratch_dir="$(mktemp -d "${TMPDIR:-/tmp}/t3code-libghostty-source.XXXXXX")"
trap 'rm -rf -- "${scratch_dir}"' EXIT

export GIT_INDEX_FILE="${scratch_dir}/index"
git -C "${GHOSTTY_SOURCE_DIR}" read-tree "${GHOSTTY_REVISION}"
git -C "${GHOSTTY_SOURCE_DIR}" apply --cached "${LAYER_LIFETIME_PATCH}"

local tracked_changes
local untracked_files
tracked_changes="$(git -C "${GHOSTTY_SOURCE_DIR}" diff --name-status)"
untracked_files="$(git -C "${GHOSTTY_SOURCE_DIR}" ls-files --others --exclude-standard)"
if [[ -n "${tracked_changes}" || -n "${untracked_files}" ]]; then
[[ -z "${tracked_changes}" ]] || printf '%s\n' "${tracked_changes}" >&2
[[ -z "${untracked_files}" ]] || printf '%s\n' "${untracked_files}" >&2
die "Ghostty source contains changes beyond the required patch"
fi
)

require_cmd git
require_cmd xcodebuild
require_cmd xcrun
require_cmd rsync
ensure_zig
ensure_ghostty_source
apply_ghostty_patch
validate_ghostty_source

ghostty_ref="$(git -C "${GHOSTTY_SOURCE_DIR}" rev-parse HEAD)"
log "using Ghostty source: ${GHOSTTY_SOURCE_DIR} @ ${ghostty_ref}"
Expand All@@ -69,7 +129,7 @@ log "building GhosttyKit.xcframework"

(
cd "${GHOSTTY_SOURCE_DIR}"
PATH="$(dirname "${GHOSTTY_ZIG}"):${PATH}" "${GHOSTTY_ZIG}" build \
PATH="$(dirname "${GHOSTTY_ZIG}"):${PATH}" "${GHOSTTY_ZIG}" build -j1 \
-Dapp-runtime=none \
-Demit-xcframework=true \
-Demit-macos-app=false \
Expand DownExpand Up@@ -98,9 +158,9 @@ xcrun strip -S -x "${sim_archive}"
log "copying iOS archives into ${VENDOR_DIR}/GhosttyKit.xcframework"
cp "${ios_archive}" "${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64/libghostty-fat.a"
cp "${sim_archive}" "${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64-simulator/libghostty-fat.a"
rsync -a --delete "${xcframework}/ios-arm64/Headers/" \
rsync -a "${xcframework}/ios-arm64/Headers/" \
"${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64/Headers/"
rsync -a --delete "${xcframework}/ios-arm64-simulator/Headers/" \
rsync -a "${xcframework}/ios-arm64-simulator/Headers/" \
"${VENDOR_DIR}/GhosttyKit.xcframework/ios-arm64-simulator/Headers/"

log "done"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
diff --git a/src/renderer/metal/IOSurfaceLayer.zig b/src/renderer/metal/IOSurfaceLayer.zig
index 8e37754a0..0d0c2b9e5 100644
--- a/src/renderer/metal/IOSurfaceLayer.zig
+++ b/src/renderer/metal/IOSurfaceLayer.zig
@@ -42,3 +42,7 @@
pub fn release(self: *IOSurfaceLayer) void {
+ // The layer may be retained by the view after we release our reference.
+ // Clear the callback first so that a later display pass can't access the
+ // renderer that owned this wrapper after it has been freed.
+ self.setDisplayCallback(null, null);
self.layer.release();
}
Loading