aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/pkg/harfbuzz
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-10 21:51:57 +0300
committerGitHub <noreply@github.com>2026-09-10 21:51:57 +0300
commit425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch)
treee52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/pkg/harfbuzz
parent90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff)
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/pkg/harfbuzz')
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/blob.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/buffer.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/build.zig287
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/build.zig.zon6
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/c.zig8
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/common.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/coretext.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/face.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/font.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/freetype.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/main.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/shape.zig2
-rw-r--r--vendor/libghostty-vt/pkg/harfbuzz/version.zig2
13 files changed, 242 insertions, 79 deletions
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/blob.zig b/vendor/libghostty-vt/pkg/harfbuzz/blob.zig
index 9472e4c7..94a6b5c9 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/blob.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/blob.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
const Error = @import("errors.zig").Error;
/// Data type holding the memory modes available to client programs.
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/buffer.zig b/vendor/libghostty-vt/pkg/harfbuzz/buffer.zig
index b97c1bef..ea70bbca 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/buffer.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/buffer.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
const common = @import("common.zig");
const Error = @import("errors.zig").Error;
const Direction = common.Direction;
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/build.zig b/vendor/libghostty-vt/pkg/harfbuzz/build.zig
index b482bc8a..5c78b262 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/build.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/build.zig
@@ -1,6 +1,8 @@
const std = @import("std");
const apple_sdk = @import("apple_sdk");
+const root_build_container = @This();
+
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
@@ -8,22 +10,51 @@ pub fn build(b: *std.Build) !void {
const coretext_enabled = b.option(bool, "enable-coretext", "Build coretext") orelse false;
const freetype_enabled = b.option(bool, "enable-freetype", "Build freetype") orelse true;
+ // For dynamic linking, we prefer dynamic linking and to search by
+ // mode first. Mode first will search all paths for a dynamic library
+ // before falling back to static.
+ const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
+ .preferred_link_mode = .dynamic,
+ .search_strategy = .mode_first,
+ };
+
const freetype = b.dependency("freetype", .{
.target = target,
.optimize = optimize,
.@"enable-libpng" = true,
});
- const macos = b.dependency("macos", .{ .target = target, .optimize = optimize });
const module = harfbuzz: {
const module = b.addModule("harfbuzz", .{
.root_source_file = b.path("main.zig"),
.target = target,
.optimize = optimize,
- .imports = &.{
- .{ .name = "freetype", .module = freetype.module("freetype") },
- .{ .name = "macos", .module = macos.module("macos") },
- },
+ .imports = if (target.result.os.tag.isDarwin())
+ &.{
+ .{ .name = "freetype", .module = freetype.module("freetype") },
+ .{
+ .name = "macos",
+ .module = b.dependency("macos", .{ .target = target, .optimize = optimize })
+ .module("macos"),
+ },
+ }
+ else
+ &.{
+ .{ .name = "freetype", .module = freetype.module("freetype") },
+ },
+ });
+
+ try HarfBuzzC.addImportToModule(b, module, .{
+ .target = target,
+ .optimize = optimize,
+ .harfbuzz = if (b.systemIntegrationOption("harfbuzz", .{})) .{ .dynamic = dynamic_link_opts } else .static,
+ .coretext = coretext_enabled,
+ .freetype = if (freetype_enabled) ft: {
+ break :ft if (b.systemIntegrationOption("freetype", .{}))
+ .{ .dynamic = dynamic_link_opts }
+ else
+ .static;
+ } else null,
});
const options = b.addOptions();
@@ -33,41 +64,17 @@ pub fn build(b: *std.Build) !void {
break :harfbuzz module;
};
- // For dynamic linking, we prefer dynamic linking and to search by
- // mode first. Mode first will search all paths for a dynamic library
- // before falling back to static.
- const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
- .preferred_link_mode = .dynamic,
- .search_strategy = .mode_first,
- };
-
const test_exe = b.addTest(.{
.name = "test",
- .root_module = b.createModule(.{
- .root_source_file = b.path("main.zig"),
- .target = target,
- .optimize = optimize,
- }),
+ .root_module = module,
});
- {
- var it = module.import_table.iterator();
- while (it.next()) |entry| test_exe.root_module.addImport(entry.key_ptr.*, entry.value_ptr.*);
- if (b.systemIntegrationOption("freetype", .{})) {
- test_exe.linkSystemLibrary2("freetype2", dynamic_link_opts);
- } else {
- test_exe.linkLibrary(freetype.artifact("freetype"));
- }
- const tests_run = b.addRunArtifact(test_exe);
- const test_step = b.step("test", "Run tests");
- test_step.dependOn(&tests_run.step);
- }
+ const tests_run = b.addRunArtifact(test_exe);
+ const test_step = b.step("test", "Run tests");
+ test_step.dependOn(&tests_run.step);
- if (b.systemIntegrationOption("harfbuzz", .{})) {
- module.linkSystemLibrary("harfbuzz", dynamic_link_opts);
- test_exe.linkSystemLibrary2("harfbuzz", dynamic_link_opts);
- } else {
- const lib = try buildLib(b, module, .{
+ if (!b.systemIntegrationOption("harfbuzz", .{})) {
+ const lib = try buildLib(b, .{
.target = target,
.optimize = optimize,
@@ -77,11 +84,11 @@ pub fn build(b: *std.Build) !void {
.dynamic_link_opts = dynamic_link_opts,
});
- test_exe.linkLibrary(lib);
+ test_exe.root_module.linkLibrary(lib);
}
}
-fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Build.Step.Compile {
+fn buildLib(b: *std.Build, options: anytype) !*std.Build.Step.Compile {
const target = options.target;
const optimize = options.optimize;
@@ -99,18 +106,16 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
+ .link_libc = true,
+ // On MSVC, we must not use linkLibCpp because Zig unconditionally
+ // passes -nostdinc++ and then adds its bundled libc++/libc++abi
+ // include paths, which conflict with MSVC's own C++ runtime
+ // headers. The MSVC SDK include directories (added via linkLibC)
+ // contain both C and C++ headers, so linkLibCpp is not needed.
+ .link_libcpp = target.result.abi != .msvc,
}),
.linkage = .static,
});
- lib.linkLibC();
- // On MSVC, we must not use linkLibCpp because Zig unconditionally
- // passes -nostdinc++ and then adds its bundled libc++/libc++abi
- // include paths, which conflict with MSVC's own C++ runtime headers.
- // The MSVC SDK include directories (added via linkLibC) contain
- // both C and C++ headers, so linkLibCpp is not needed.
- if (target.result.abi != .msvc) {
- lib.linkLibCpp();
- }
if (target.result.os.tag.isDarwin()) {
try apple_sdk.addPaths(b, lib);
@@ -154,30 +159,20 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
});
if (b.systemIntegrationOption("freetype", .{})) {
- lib.linkSystemLibrary2("freetype2", dynamic_link_opts);
- module.linkSystemLibrary("freetype2", dynamic_link_opts);
+ lib.root_module.linkSystemLibrary("freetype2", dynamic_link_opts);
} else {
- lib.linkLibrary(freetype.artifact("freetype"));
-
- if (freetype.builder.lazyDependency(
- "freetype",
- .{},
- )) |freetype_dep| {
- module.addIncludePath(freetype_dep.path("include"));
- }
+ lib.root_module.linkLibrary(freetype.artifact("freetype"));
}
}
if (coretext_enabled) {
try flags.appendSlice(b.allocator, &.{"-DHAVE_CORETEXT=1"});
- lib.linkFramework("CoreText");
- module.linkFramework("CoreText", .{});
+ lib.root_module.linkFramework("CoreText", .{});
}
if (b.lazyDependency("harfbuzz", .{})) |upstream| {
- lib.addIncludePath(upstream.path("src"));
- module.addIncludePath(upstream.path("src"));
- lib.addCSourceFile(.{
+ lib.root_module.addIncludePath(upstream.path("src"));
+ lib.root_module.addCSourceFile(.{
.file = upstream.path("src/harfbuzz.cc"),
.flags = flags.items,
});
@@ -192,3 +187,173 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
return lib;
}
+
+const HarfBuzzC = struct {
+ const AddImportToModuleOptions = struct {
+ const LinkMode = union(enum) {
+ static,
+ dynamic: std.Build.Module.LinkSystemLibraryOptions,
+ };
+
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+ harfbuzz: LinkMode,
+ coretext: bool,
+ freetype: ?LinkMode,
+ };
+
+ fn fmtInclude(w: *std.Io.Writer, name: []const u8, mode: AddImportToModuleOptions.LinkMode) !void {
+ if (mode == .dynamic) {
+ try w.print("#include <{s}>\n", .{name});
+ } else {
+ try w.print("#include \"{s}\"\n", .{name});
+ }
+ }
+
+ fn addImportToModule(
+ b: *std.Build,
+ module: *std.Build.Module,
+ options: AddImportToModuleOptions,
+ ) !void {
+ // TODO: There's a decent amount of duplication here right now.
+ // Basically we want to mirror what we're passing in buildLib to make
+ // sure that the translation is generated as correct as possible.
+ // Eventually, we want to try and unravel this as much as we can, to
+ // the point that ultimately all C flags and even link options are
+ // self-contained in the translation artifact.
+ //
+ // This is a bit tricky right now as there are situations where we
+ // provide a static library built straight off of the C file, hence the
+ // duplication.
+ //
+ // NOTE: This function de-allocates nothing as b.allocator is an arena
+ // (unfortunately not documented, but a cursory search in various
+ // communities or the issue trackers should turn up confirmation).
+
+ const translate_c = b.lazyImport(root_build_container, "translate_c") orelse return;
+ const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse return;
+
+ const c_source = c_source: {
+ var source_builder: std.Io.Writer.Allocating = .init(b.allocator);
+ try fmtInclude(&source_builder.writer, "hb.h", options.harfbuzz);
+
+ if (options.coretext) {
+ try fmtInclude(&source_builder.writer, "hb-coretext.h", options.harfbuzz);
+ }
+
+ if (options.freetype != null) {
+ try fmtInclude(&source_builder.writer, "hb-ft.h", options.harfbuzz);
+ }
+
+ break :c_source source_builder.written();
+ };
+
+ // Assemble system libs
+ const system_libs = libs: {
+ var libs_builder: std.ArrayList(translate_c.Translator.LinkSystemLib) = .empty;
+ if (options.harfbuzz == .dynamic)
+ try libs_builder.append(b.allocator, .{ .name = "harfbuzz", .options = options.harfbuzz.dynamic });
+ if (options.freetype) |ft| {
+ if (ft == .dynamic)
+ try libs_builder.append(b.allocator, .{ .name = "freetype2", .options = ft.dynamic });
+ }
+
+ break :libs libs_builder.items;
+ };
+
+ // Assemble flags
+ const flags = flags: {
+ var flag_builder: std.ArrayList([]const u8) = .empty;
+ try flag_builder.appendSlice(b.allocator, &.{
+ "-DHAVE_STDBOOL_H",
+ });
+ // Disable ubsan for MSVC: Zig's ubsan runtime cannot be bundled
+ // on Windows (LNK4229), leaving __ubsan_handle_* unresolved when
+ // the static archive is consumed by an external linker.
+ if (options.target.result.abi == .msvc) {
+ try flag_builder.appendSlice(b.allocator, &.{
+ "-fno-sanitize=undefined",
+ "-fno-sanitize-trap=undefined",
+ });
+ }
+ if (options.target.result.os.tag != .windows) {
+ try flag_builder.appendSlice(b.allocator, &.{
+ "-DHAVE_UNISTD_H",
+ "-DHAVE_SYS_MMAN_H",
+ "-DHAVE_PTHREAD=1",
+ });
+ }
+
+ // Freetype flags/non-system include paths
+ if (options.freetype != null) {
+ try flag_builder.appendSlice(b.allocator, &.{
+ "-DHAVE_FREETYPE=1",
+
+ // Let's just assume a new freetype
+ "-DHAVE_FT_GET_VAR_BLEND_COORDINATES=1",
+ "-DHAVE_FT_SET_VAR_BLEND_COORDINATES=1",
+ "-DHAVE_FT_DONE_MM_VAR=1",
+ "-DHAVE_FT_GET_TRANSFORM=1",
+ });
+ }
+
+ // Coretext
+ if (options.coretext) {
+ try flag_builder.appendSlice(b.allocator, &.{"-DHAVE_CORETEXT=1"});
+ try flag_builder.appendSlice(b.allocator, &.{"-fblocks"});
+ }
+
+ break :flags flag_builder.items;
+ };
+
+ const hb_c: translate_c.Translator = .init(translate_c_dep, .{
+ .c_source_file = b.addWriteFiles().add(
+ "hb_c.h",
+ c_source,
+ ),
+ .target = options.target,
+ .optimize = options.optimize,
+ .link_libc = true,
+ .link_system_libs = system_libs,
+ .libc_file = if (options.target.result.os.tag.isDarwin()) libc_file: {
+ switch (try @import("apple_sdk").pathsForTarget(b, options.target.result)) {
+ inline else => |paths| break :libc_file paths.libc,
+ }
+ } else null,
+ .extra_args = flags,
+ });
+
+ if (options.harfbuzz == .static) {
+ if (b.lazyDependency("harfbuzz", .{})) |upstream| {
+ hb_c.addIncludePath(upstream.path("src"));
+ }
+ }
+
+ // Freetype non-system include paths
+ if (options.freetype) |freetype_enabled| {
+ if (freetype_enabled == .static) {
+ const ft_dep = b.dependency("freetype", .{
+ .target = options.target,
+ .optimize = options.optimize,
+ .@"enable-libpng" = true,
+ });
+
+ if (ft_dep.builder.lazyDependency(
+ "freetype",
+ .{},
+ )) |freetype_lazy_dep| {
+ hb_c.addIncludePath(freetype_lazy_dep.path("include"));
+ }
+ }
+ }
+
+ // Coretext
+ if (options.coretext) {
+ // NOTE: We should not necessarily need to add this directly to C
+ // translation, so we just add it to the module.
+ hb_c.mod.linkFramework("CoreText", .{});
+ }
+
+ module.addImport("hb_c", hb_c.mod);
+ }
+};
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/build.zig.zon b/vendor/libghostty-vt/pkg/harfbuzz/build.zig.zon
index b7d155e9..b3f3c238 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/build.zig.zon
+++ b/vendor/libghostty-vt/pkg/harfbuzz/build.zig.zon
@@ -4,6 +4,12 @@
.fingerprint = 0xbd60917cd18865d8,
.paths = .{""},
.dependencies = .{
+ .translate_c = .{
+ .url = "https://codeberg.org/vancluever/translate-c/archive/4e879eb8aba615de112eabd1231ea6e01920cead.tar.gz",
+ .hash = "translate_c-0.0.0-Q_BUWhVNBwDOEcIqub4VFPJPB6D9dgwzUMHTX5KWr8Xr",
+ .lazy = true,
+ },
+
// harfbuzz/harfbuzz
.harfbuzz = .{
.url = "https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz",
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/c.zig b/vendor/libghostty-vt/pkg/harfbuzz/c.zig
deleted file mode 100644
index 49e87dce..00000000
--- a/vendor/libghostty-vt/pkg/harfbuzz/c.zig
+++ /dev/null
@@ -1,8 +0,0 @@
-const builtin = @import("builtin");
-const build_options = @import("build_options");
-
-pub const c = @cImport({
- @cInclude("hb.h");
- if (build_options.freetype) @cInclude("hb-ft.h");
- if (build_options.coretext) @cInclude("hb-coretext.h");
-});
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/common.zig b/vendor/libghostty-vt/pkg/harfbuzz/common.zig
index 840ff586..01955907 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/common.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/common.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
/// The direction of a text segment or buffer.
///
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/coretext.zig b/vendor/libghostty-vt/pkg/harfbuzz/coretext.zig
index 73042624..72dfd53b 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/coretext.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/coretext.zig
@@ -1,6 +1,6 @@
const macos = @import("macos");
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
const Face = @import("face.zig").Face;
const Font = @import("font.zig").Font;
const Error = @import("errors.zig").Error;
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/face.zig b/vendor/libghostty-vt/pkg/harfbuzz/face.zig
index 5ffad5d3..942894b9 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/face.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/face.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
/// A font face is an object that represents a single face from within a font family.
///
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/font.zig b/vendor/libghostty-vt/pkg/harfbuzz/font.zig
index 13544fb9..4202ca4d 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/font.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/font.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
const Face = @import("face.zig").Face;
const Error = @import("errors.zig").Error;
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/freetype.zig b/vendor/libghostty-vt/pkg/harfbuzz/freetype.zig
index d90d3f83..65419a6e 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/freetype.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/freetype.zig
@@ -1,6 +1,6 @@
const freetype = @import("freetype");
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
const Face = @import("face.zig").Face;
const Font = @import("font.zig").Font;
const Error = @import("errors.zig").Error;
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/main.zig b/vendor/libghostty-vt/pkg/harfbuzz/main.zig
index 08a4f9c2..6e46eb42 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/main.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/main.zig
@@ -7,7 +7,7 @@ const font = @import("font.zig");
const shapepkg = @import("shape.zig");
const versionpkg = @import("version.zig");
-pub const c = @import("c.zig").c;
+pub const c = @import("hb_c");
pub const freetype = @import("freetype.zig");
pub const coretext = @import("coretext.zig");
pub const MemoryMode = blob.MemoryMode;
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/shape.zig b/vendor/libghostty-vt/pkg/harfbuzz/shape.zig
index b49020c3..38f56c4a 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/shape.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/shape.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
const Font = @import("font.zig").Font;
const Buffer = @import("buffer.zig").Buffer;
const Feature = @import("common.zig").Feature;
diff --git a/vendor/libghostty-vt/pkg/harfbuzz/version.zig b/vendor/libghostty-vt/pkg/harfbuzz/version.zig
index dbe25b52..5546ca37 100644
--- a/vendor/libghostty-vt/pkg/harfbuzz/version.zig
+++ b/vendor/libghostty-vt/pkg/harfbuzz/version.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const c = @import("c.zig").c;
+const c = @import("hb_c");
pub const Version = struct {
major: u32,