feat(macos): port Ghostty's macOS code paths (Metal, CoreText, Darwin)

Ports the macOS-specific Zig code behind cfg(target_os = "macos"):
- renderer: a GraphicsApi trait with generic::Renderer<G>; Metal backend
  (all renderer/metal/* files, shaders.metal verbatim, runtime library
  compile, IOSurface layer, CVDisplayLink), shadertoy -> MSL via naga;
  OpenGL remains the backend elsewhere.
- font: CoreText face, shaper and discovery with build.rs backend
  selection (coretext default; coretext-freetype / coretext-harfbuzz /
  coretext-noshape features), no fontconfig/freetype/harfbuzz on Apple.
- input: KeymapDarwin via UCKeyTranslate, option-as-alt, mac keycodes.
- os: macos, mach, cf_release_thread, NSProcessInfo args and macOS
  branches; config: macOS defaults, keybinds, Application Support paths.
- termio/core: login(1) wrapping, openpty/execvpe, Darwin child exit
  handling, os_log logging.

Compile-checked for aarch64/x86_64-apple-darwin (clippy -D warnings
clean) using the cross setup in docs/rewrite/notes/macos-M1.md; cannot
run here. The embedded runtime/C API (embedded.zig) is the next step.

Also includes the cross-platform integration edits shared by the crash,
verification, Windows and macOS work (Cargo target-gating, thread
crash-context hooks, apprt-gtk surface/IME refactor, termio/os cfg
gates), a cfg fix so ghostty-config builds on wasm32, and an allow for
the intentional recursion in the crash overflow test.

Test Plan:
- cargo test --workspace (3224 passed)
- cargo clippy --workspace --all-targets -- -D warnings
- cargo check --target aarch64-apple-darwin -p ghostty-renderer (with
  the documented cross env)
This commit is contained in:
ddidderr committed 2026-10-12 06:02:39 +02:00
1 parent 3c8fae1089
commit 452b782149
124 files changed
+14936 -1242

No files matched your search

+87 -12
View File
@@ -213,16 +213,33 @@ impl Mods {
/// Return the mods to use for key translation. This handles settings
/// like macos-option-as-alt. The translation mods should be used for
/// translation but never sent back in for the key callback.
///
/// Only macOS changes anything here; this port targets Linux so the
/// mods are returned unchanged.
pub fn translation(self, _option_as_alt: OptionAsAlt) -> Mods {
self
pub fn translation(self, option_as_alt: OptionAsAlt) -> Mods {
let mut result = self;
// macos-option-as-alt for darwin
if crate::platform::is_darwin() {
// Alt has to be set only on the correct side
let applies = match option_as_alt {
OptionAsAlt::False => false,
OptionAsAlt::True => true,
OptionAsAlt::Left => self.sides.alt != ModSide::Right,
OptionAsAlt::Right => self.sides.alt != ModSide::Left,
};
// Unset alt
if applies {
result.alt = false;
}
}
result
}
/// Checks to see if super is on (MacOS) or ctrl.
pub fn ctrl_or_super(self) -> bool {
// Non-darwin target.
if crate::platform::is_darwin() {
return self.super_;
}
self.ctrl
}
}
@@ -577,12 +594,70 @@ mod tests {
#[test]
fn translation_macos_option_as_alt() {
// Darwin only upstream; on Linux it is the identity.
let mods = Mods {
alt: true,
..Default::default()
};
assert_eq!(mods.translation(OptionAsAlt::True), mods);
crate::platform::with_darwin(true, || {
// Unset
{
let mods = Mods::default();
assert_eq!(mods.translation(OptionAsAlt::True), mods);
}
// Set
{
let mods = m(|x| x.alt = true);
assert_eq!(Mods::default(), mods.translation(OptionAsAlt::True));
}
// Set but disabled
{
let mods = m(|x| x.alt = true);
assert_eq!(mods.translation(OptionAsAlt::False), mods);
}
// Set wrong side
{
let mods = m(|x| {
x.alt = true;
x.sides.alt = ModSide::Right;
});
assert_eq!(mods.translation(OptionAsAlt::Left), mods);
}
{
let mods = m(|x| {
x.alt = true;
x.sides.alt = ModSide::Left;
});
assert_eq!(mods.translation(OptionAsAlt::Right), mods);
}
// Set with other mods
{
let mods = m(|x| {
x.alt = true;
x.shift = true;
});
assert_eq!(m(|x| x.shift = true), mods.translation(OptionAsAlt::True));
}
});
// Not darwin: identity.
crate::platform::with_darwin(false, || {
let mods = m(|x| x.alt = true);
assert_eq!(mods.translation(OptionAsAlt::True), mods);
});
}
#[test]
fn ctrl_or_super_follows_platform() {
let ctrl = m(|x| x.ctrl = true);
let sup = m(|x| x.super_ = true);
crate::platform::with_darwin(true, || {
assert!(sup.ctrl_or_super());
assert!(!ctrl.ctrl_or_super());
});
crate::platform::with_darwin(false, || {
assert!(ctrl.ctrl_or_super());
assert!(!sup.ctrl_or_super());
});
}
fn left(k: &str) -> Mods {