From a42193b997b562467fd714dd3405d1eaf709951a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 20 Sep 2025 14:37:04 -0700 Subject: [PATCH] start extracting core terminal zig module --- build.zig | 47 +++++++++++++++++++++------ src/build/GhosttyZig.zig | 36 ++++++++++++++++++++ src/build/SharedDeps.zig | 15 +++++++++ src/build/UnicodeTables.zig | 14 ++++++-- src/build/main.zig | 1 + src/config/Config.zig | 11 ++++++- src/lib_vt.zig | 5 +++ src/os/TempDir.zig | 7 ++-- src/terminal/PageList.zig | 14 ++++---- src/terminal/Screen.zig | 24 +++----------- src/terminal/build_options.zig | 31 ++++++++++++++++++ src/terminal/cursor.zig | 15 +++++++++ src/terminal/kitty/graphics_image.zig | 19 +++++++---- src/terminal/mouse_shape.zig | 21 ++++++++---- src/terminal/page.zig | 24 +++++++------- 15 files changed, 215 insertions(+), 69 deletions(-) create mode 100644 src/build/GhosttyZig.zig create mode 100644 src/lib_vt.zig create mode 100644 src/terminal/build_options.zig create mode 100644 src/terminal/cursor.zig diff --git a/build.zig b/build.zig index 38cfd0e56..f651c30e4 100644 --- a/build.zig +++ b/build.zig @@ -8,12 +8,25 @@ comptime { } pub fn build(b: *std.Build) !void { - // This defines all the available build options (e.g. `-D`). + // This defines all the available build options (e.g. `-D`). If you + // want to know what options are available, you can run `--help` or + // you can read `src/build/Config.zig`. const config = try buildpkg.Config.init(b); - const test_filter = b.option( - []const u8, + const test_filters = b.option( + [][]const u8, "test-filter", "Filter for test. Only applies to Zig tests.", + ) orelse &[0][]const u8{}; + + // Ghostty dependencies used by many artifacts. + const deps = try buildpkg.SharedDeps.init(b, &config); + + // The modules exported for Zig consumers of libghostty. If you're + // writing a Zig program that uses libghostty, read this file. + const mod = try buildpkg.GhosttyZig.init( + b, + &config, + &deps, ); // All our steps which we'll hook up later. The steps are shown @@ -24,6 +37,10 @@ pub fn build(b: *std.Build) !void { "Run the app under valgrind", ); const test_step = b.step("test", "Run tests"); + const test_lib_vt_step = b.step( + "test-lib-vt", + "Run libghostty-vt tests", + ); const test_valgrind_step = b.step( "test-valgrind", "Run tests under valgrind", @@ -37,10 +54,6 @@ pub fn build(b: *std.Build) !void { const resources = try buildpkg.GhosttyResources.init(b, &config); const i18n = if (config.i18n) try buildpkg.GhosttyI18n.init(b, &config) else null; - // Ghostty dependencies used by many artifacts. - const deps = try buildpkg.SharedDeps.init(b, &config); - if (config.emit_helpgen) deps.help_strings.install(); - // Ghostty executable, the actual runnable Ghostty program. const exe = try buildpkg.GhosttyExe.init(b, &config, &deps); @@ -83,6 +96,9 @@ pub fn build(b: *std.Build) !void { &deps, ); + // Helpgen + if (config.emit_helpgen) deps.help_strings.install(); + // Runtime "none" is libghostty, anything else is an executable. if (config.app_runtime != .none) { if (config.emit_exe) { @@ -185,7 +201,7 @@ pub fn build(b: *std.Build) !void { run_step.dependOn(&macos_app_native_only.open.step); // If we have no test filters, install the tests too - if (test_filter == null) { + if (test_filters.len == 0) { macos_app_native_only.addTestStepDependencies(test_step); } } @@ -216,11 +232,23 @@ pub fn build(b: *std.Build) !void { run_valgrind_step.dependOn(&run_cmd.step); } + // Zig module tests + { + const mod_vt_test = b.addTest(.{ + .root_module = mod.vt, + .target = config.target, + .optimize = config.optimize, + .filters = test_filters, + }); + test_lib_vt_step.dependOn(&mod_vt_test.step); + } + // Tests { + // Full unit tests const test_exe = b.addTest(.{ .name = "ghostty-test", - .filters = if (test_filter) |v| &.{v} else &.{}, + .filters = test_filters, .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = config.baselineTarget(), @@ -230,7 +258,6 @@ pub fn build(b: *std.Build) !void { .unwind_tables = .sync, }), }); - if (config.emit_test_exe) b.installArtifact(test_exe); _ = try deps.add(test_exe); diff --git a/src/build/GhosttyZig.zig b/src/build/GhosttyZig.zig new file mode 100644 index 000000000..e3c22bc67 --- /dev/null +++ b/src/build/GhosttyZig.zig @@ -0,0 +1,36 @@ +//! GhosttyZig generates the Zig modules that Ghostty exports +//! for downstream usage. +const GhosttyZig = @This(); + +const std = @import("std"); +const Config = @import("Config.zig"); +const SharedDeps = @import("SharedDeps.zig"); + +const vt_options = @import("../terminal/build_options.zig"); + +vt: *std.Build.Module, + +pub fn init( + b: *std.Build, + cfg: *const Config, + deps: *const SharedDeps, +) !GhosttyZig { + const vt = b.addModule("ghostty-vt", .{ + .root_source_file = b.path("src/lib_vt.zig"), + .target = cfg.target, + .optimize = cfg.optimize, + }); + deps.unicode_tables.addModuleImport(vt); + vt_options.addOptions(b, vt, .{ + .artifact = .lib, + .slow_runtime_safety = switch (cfg.optimize) { + .Debug => true, + .ReleaseSafe, + .ReleaseSmall, + .ReleaseFast, + => false, + }, + }); + + return .{ .vt = vt }; +} diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig index ab5b0d8bf..67d416f5d 100644 --- a/src/build/SharedDeps.zig +++ b/src/build/SharedDeps.zig @@ -107,6 +107,21 @@ pub fn add( // Every exe gets build options populated step.root_module.addOptions("build_options", self.options); + // Every exe needs the terminal options + { + const vt_options = @import("../terminal/build_options.zig"); + vt_options.addOptions(b, step.root_module, .{ + .artifact = .ghostty, + .slow_runtime_safety = switch (optimize) { + .Debug => true, + .ReleaseSafe, + .ReleaseSmall, + .ReleaseFast, + => false, + }, + }); + } + // Freetype _ = b.systemIntegrationOption("freetype", .{}); // Shows it in help if (self.config.font_backend.hasFreetype()) { diff --git a/src/build/UnicodeTables.zig b/src/build/UnicodeTables.zig index 6733b5315..0f558b708 100644 --- a/src/build/UnicodeTables.zig +++ b/src/build/UnicodeTables.zig @@ -64,11 +64,19 @@ pub fn init(b: *std.Build) !UnicodeTables { /// Add the "unicode_tables" import. pub fn addImport(self: *const UnicodeTables, step: *std.Build.Step.Compile) void { self.props_output.addStepDependencies(&step.step); - step.root_module.addAnonymousImport("unicode_tables", .{ + self.symbols_output.addStepDependencies(&step.step); + self.addModuleImport(step.root_module); +} + +/// Add the "unicode_tables" import to a module. +pub fn addModuleImport( + self: *const UnicodeTables, + module: *std.Build.Module, +) void { + module.addAnonymousImport("unicode_tables", .{ .root_source_file = self.props_output, }); - self.symbols_output.addStepDependencies(&step.step); - step.root_module.addAnonymousImport("symbols_tables", .{ + module.addAnonymousImport("symbols_tables", .{ .root_source_file = self.symbols_output, }); } diff --git a/src/build/main.zig b/src/build/main.zig index af99802df..0ee41352b 100644 --- a/src/build/main.zig +++ b/src/build/main.zig @@ -18,6 +18,7 @@ pub const GhosttyI18n = @import("GhosttyI18n.zig"); pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig"); pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig"); pub const GhosttyWebdata = @import("GhosttyWebdata.zig"); +pub const GhosttyZig = @import("GhosttyZig.zig"); pub const HelpStrings = @import("HelpStrings.zig"); pub const SharedDeps = @import("SharedDeps.zig"); pub const UnicodeTables = @import("UnicodeTables.zig"); diff --git a/src/config/Config.zig b/src/config/Config.zig index 9a40dc0e4..1ef9de947 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -19,7 +19,6 @@ const ArenaAllocator = std.heap.ArenaAllocator; const global_state = &@import("../global.zig").state; const fontpkg = @import("../font/main.zig"); const inputpkg = @import("../input.zig"); -const terminal = @import("../terminal/main.zig"); const internal_os = @import("../os/main.zig"); const cli = @import("../cli.zig"); @@ -39,6 +38,16 @@ const RepeatableStringMap = @import("RepeatableStringMap.zig"); pub const Path = @import("path.zig").Path; pub const RepeatablePath = @import("path.zig").RepeatablePath; +// We do this instead of importing all of terminal/main.zig to +// limit the dependency graph. This is important because some things +// like the `ghostty-build-data` binary depend on the Config but don't +// want to include all the other stuff. +const terminal = struct { + const CursorStyle = @import("../terminal/cursor.zig").Style; + const color = @import("../terminal/color.zig"); + const x11_color = @import("../terminal/x11_color.zig"); +}; + const log = std.log.scoped(.config); /// Used on Unixes for some defaults. diff --git a/src/lib_vt.zig b/src/lib_vt.zig new file mode 100644 index 000000000..fbe524014 --- /dev/null +++ b/src/lib_vt.zig @@ -0,0 +1,5 @@ +const terminal = @import("terminal/main.zig"); + +test { + _ = terminal; +} diff --git a/src/os/TempDir.zig b/src/os/TempDir.zig index 7d3a34c84..f2e9992c4 100644 --- a/src/os/TempDir.zig +++ b/src/os/TempDir.zig @@ -6,7 +6,8 @@ const std = @import("std"); const builtin = @import("builtin"); const testing = std.testing; const Dir = std.fs.Dir; -const internal_os = @import("main.zig"); +const allocTmpDir = @import("file.zig").allocTmpDir; +const freeTmpDir = @import("file.zig").freeTmpDir; const log = std.log.scoped(.tempdir); @@ -31,8 +32,8 @@ pub fn init() !TempDir { const dir = dir: { const cwd = std.fs.cwd(); - const tmp_dir = internal_os.allocTmpDir(std.heap.page_allocator) orelse break :dir cwd; - defer internal_os.freeTmpDir(std.heap.page_allocator, tmp_dir); + const tmp_dir = allocTmpDir(std.heap.page_allocator) orelse break :dir cwd; + defer freeTmpDir(std.heap.page_allocator, tmp_dir); break :dir try cwd.openDir(tmp_dir, .{}); }; diff --git a/src/terminal/PageList.zig b/src/terminal/PageList.zig index a4136d7f3..b5d511b7f 100644 --- a/src/terminal/PageList.zig +++ b/src/terminal/PageList.zig @@ -4,7 +4,7 @@ const PageList = @This(); const std = @import("std"); -const build_config = @import("../build_config.zig"); +const build_options = @import("terminal_options"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const fastmem = @import("../fastmem.zig"); @@ -1492,7 +1492,7 @@ fn resizeWithoutReflow(self: *PageList, opts: Resize) !void { }, } - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { assert(self.totalRows() >= self.rows); } } @@ -2524,7 +2524,7 @@ pub fn pin(self: *const PageList, pt: point.Point) ?Pin { /// pin points to is removed completely, the tracked pin will be updated /// to the top-left of the screen. pub fn trackPin(self: *PageList, p: Pin) Allocator.Error!*Pin { - if (build_config.slow_runtime_safety) assert(self.pinIsValid(p)); + if (build_options.slow_runtime_safety) assert(self.pinIsValid(p)); // Create our tracked pin const tracked = try self.pool.pins.create(); @@ -2556,7 +2556,7 @@ pub fn countTrackedPins(self: *const PageList) usize { pub fn pinIsValid(self: *const PageList, p: Pin) bool { // This is very slow so we want to ensure we only ever // call this during slow runtime safety builds. - comptime assert(build_config.slow_runtime_safety); + comptime assert(build_options.slow_runtime_safety); var it = self.pages.first; while (it) |node| : (it = node.next) { @@ -3234,7 +3234,7 @@ pub fn pageIterator( else self.getBottomRight(tl_pt) orelse return .{ .row = null }; - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { assert(tl_pin.eql(bl_pin) or tl_pin.before(bl_pin)); } @@ -3510,7 +3510,7 @@ pub const Pin = struct { direction: Direction, limit: ?Pin, ) PageIterator { - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { if (limit) |l| { // Check the order according to the iteration direction. switch (direction) { @@ -3560,7 +3560,7 @@ pub const Pin = struct { // Note: this is primarily unit tested as part of the Kitty // graphics deletion code. pub fn isBetween(self: Pin, top: Pin, bottom: Pin) bool { - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { if (top.node == bottom.node) { // If top is bottom, must be ordered. assert(top.y <= bottom.y); diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 67769923f..cc7aa4a16 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -1,7 +1,7 @@ const Screen = @This(); const std = @import("std"); -const build_config = @import("../build_config.zig"); +const build_options = @import("terminal_options"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const ansi = @import("ansi.zig"); @@ -24,6 +24,8 @@ const Row = pagepkg.Row; const Cell = pagepkg.Cell; const Pin = PageList.Pin; +pub const CursorStyle = @import("cursor.zig").Style; + const log = std.log.scoped(.screen); /// The general purpose allocator to use for all memory allocations. @@ -141,22 +143,6 @@ pub const Cursor = struct { } }; -/// The visual style of the cursor. Whether or not it blinks -/// is determined by mode 12 (modes.zig). This mode is synchronized -/// with CSI q, the same as xterm. -pub const CursorStyle = enum { - bar, // DECSCUSR 5, 6 - block, // DECSCUSR 1, 2 - underline, // DECSCUSR 3, 4 - - /// The cursor styles below aren't known by DESCUSR and are custom - /// implemented in Ghostty. They are reported as some standard style - /// if requested, though. - /// Hollow block cursor. This is a block cursor with the center empty. - /// Reported as DECSCUSR 1 or 2 (block). - block_hollow, -}; - /// Saved cursor state. pub const SavedCursor = struct { x: size.CellCountInt, @@ -232,7 +218,7 @@ pub fn deinit(self: *Screen) void { /// tests. This only asserts the screen specific data so callers should /// ensure they're also calling page integrity checks if necessary. pub fn assertIntegrity(self: *const Screen) void { - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { // We don't run integrity checks on Valgrind because its soooooo slow, // Valgrind is our integrity checker, and we run these during unit // tests (non-Valgrind) anyways so we're verifying anyways. @@ -772,7 +758,7 @@ pub fn cursorDownScroll(self: *Screen) !void { // These assertions help catch some pagelist math errors. Our // x/y should be unchanged after the grow. - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { const active = self.pages.pointFromPin( .active, page_pin, diff --git a/src/terminal/build_options.zig b/src/terminal/build_options.zig new file mode 100644 index 000000000..33cf7a2ef --- /dev/null +++ b/src/terminal/build_options.zig @@ -0,0 +1,31 @@ +const std = @import("std"); + +pub const Options = struct { + /// The target artifact to build. This will gate some functionality. + artifact: Artifact = .ghostty, + + /// True if we should enable the "slow" runtime safety checks. These + /// are runtime safety checks that are slower than typical and should + /// generally be disabled in production builds. + slow_runtime_safety: bool = false, +}; + +pub const Artifact = enum { + /// Ghostty application + ghostty, + + /// libghostty-vt, Zig module + lib, +}; + +/// Add the required build options for the terminal module. +pub fn addOptions( + b: *std.Build, + m: *std.Build.Module, + v: Options, +) void { + const opts = b.addOptions(); + opts.addOption(Artifact, "artifact", v.artifact); + opts.addOption(bool, "slow_runtime_safety", v.slow_runtime_safety); + m.addOptions("terminal_options", opts); +} diff --git a/src/terminal/cursor.zig b/src/terminal/cursor.zig new file mode 100644 index 000000000..136ee085a --- /dev/null +++ b/src/terminal/cursor.zig @@ -0,0 +1,15 @@ +/// The visual style of the cursor. Whether or not it blinks +/// is determined by mode 12 (modes.zig). This mode is synchronized +/// with CSI q, the same as xterm. +pub const Style = enum { + bar, // DECSCUSR 5, 6 + block, // DECSCUSR 1, 2 + underline, // DECSCUSR 3, 4 + + /// The cursor styles below aren't known by DESCUSR and are custom + /// implemented in Ghostty. They are reported as some standard style + /// if requested, though. + /// Hollow block cursor. This is a block cursor with the center empty. + /// Reported as DECSCUSR 1 or 2 (block). + block_hollow, +}; diff --git a/src/terminal/kitty/graphics_image.zig b/src/terminal/kitty/graphics_image.zig index 54ed1b934..f32b70be2 100644 --- a/src/terminal/kitty/graphics_image.zig +++ b/src/terminal/kitty/graphics_image.zig @@ -9,9 +9,14 @@ const fastmem = @import("../../fastmem.zig"); const command = @import("graphics_command.zig"); const point = @import("../point.zig"); const PageList = @import("../PageList.zig"); -const internal_os = @import("../../os/main.zig"); const wuffs = @import("wuffs"); +const temp_dir = struct { + const TempDir = @import("../../os/TempDir.zig"); + const allocTmpDir = @import("../../os/file.zig").allocTmpDir; + const freeTmpDir = @import("../../os/file.zig").freeTmpDir; +}; + const log = std.log.scoped(.kitty_gfx); /// Maximum width or height of an image. Taken directly from Kitty. @@ -276,8 +281,8 @@ pub const LoadingImage = struct { fn isPathInTempDir(path: []const u8) bool { if (std.mem.startsWith(u8, path, "/tmp")) return true; if (std.mem.startsWith(u8, path, "/dev/shm")) return true; - if (internal_os.allocTmpDir(std.heap.page_allocator)) |dir| { - defer internal_os.freeTmpDir(std.heap.page_allocator, dir); + if (temp_dir.allocTmpDir(std.heap.page_allocator)) |dir| { + defer temp_dir.freeTmpDir(std.heap.page_allocator, dir); if (std.mem.startsWith(u8, path, dir)) return true; // The temporary dir is sometimes a symlink. On macOS for @@ -690,7 +695,7 @@ test "image load: temporary file without correct path" { const testing = std.testing; const alloc = testing.allocator; - var tmp_dir = try internal_os.TempDir.init(); + var tmp_dir = try temp_dir.TempDir.init(); defer tmp_dir.deinit(); const data = @embedFile("testdata/image-rgb-none-20x15-2147483647-raw.data"); try tmp_dir.dir.writeFile(.{ @@ -723,7 +728,7 @@ test "image load: rgb, not compressed, temporary file" { const testing = std.testing; const alloc = testing.allocator; - var tmp_dir = try internal_os.TempDir.init(); + var tmp_dir = try temp_dir.TempDir.init(); defer tmp_dir.deinit(); const data = @embedFile("testdata/image-rgb-none-20x15-2147483647-raw.data"); try tmp_dir.dir.writeFile(.{ @@ -760,7 +765,7 @@ test "image load: rgb, not compressed, regular file" { const testing = std.testing; const alloc = testing.allocator; - var tmp_dir = try internal_os.TempDir.init(); + var tmp_dir = try temp_dir.TempDir.init(); defer tmp_dir.deinit(); const data = @embedFile("testdata/image-rgb-none-20x15-2147483647-raw.data"); try tmp_dir.dir.writeFile(.{ @@ -795,7 +800,7 @@ test "image load: png, not compressed, regular file" { const testing = std.testing; const alloc = testing.allocator; - var tmp_dir = try internal_os.TempDir.init(); + var tmp_dir = try temp_dir.TempDir.init(); defer tmp_dir.deinit(); const data = @embedFile("testdata/image-png-none-50x76-2147483647-raw.data"); try tmp_dir.dir.writeFile(.{ diff --git a/src/terminal/mouse_shape.zig b/src/terminal/mouse_shape.zig index 23ab215d6..3694ba8ec 100644 --- a/src/terminal/mouse_shape.zig +++ b/src/terminal/mouse_shape.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const build_config = @import("../build_config.zig"); +const build_options = @import("terminal_options"); /// The possible cursor shapes. Not all app runtimes support these shapes. /// The shapes are always based on the W3C supported cursor styles so we @@ -48,13 +48,20 @@ pub const MouseShape = enum(c_int) { } /// Make this a valid gobject if we're in a GTK environment. - pub const getGObjectType = switch (build_config.app_runtime) { - .gtk => @import("gobject").ext.defineEnum( - MouseShape, - .{ .name = "GhosttyMouseShape" }, - ), + pub const getGObjectType = gtk: { + switch (build_options.artifact) { + .ghostty => break :gtk void, + .lib => {}, + } - .none => void, + break :gtk switch (@import("../build_config.zig").app_runtime) { + .gtk => @import("gobject").ext.defineEnum( + MouseShape, + .{ .name = "GhosttyMouseShape" }, + ), + + .none => void, + }; }; }; diff --git a/src/terminal/page.zig b/src/terminal/page.zig index d870bd160..f5ee1de71 100644 --- a/src/terminal/page.zig +++ b/src/terminal/page.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const build_config = @import("../build_config.zig"); +const build_options = @import("terminal_options"); const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const assert = std.debug.assert; @@ -182,8 +182,8 @@ pub const Page = struct { /// If this is true then verifyIntegrity will do nothing. This is /// only present with runtime safety enabled. - pause_integrity_checks: if (build_config.slow_runtime_safety) usize else void = - if (build_config.slow_runtime_safety) 0 else {}, + pause_integrity_checks: if (build_options.slow_runtime_safety) usize else void = + if (build_options.slow_runtime_safety) 0 else {}, /// Initialize a new page, allocating the required backing memory. /// The size of the initialized page defaults to the full capacity. @@ -307,7 +307,7 @@ pub const Page = struct { /// doing a lot of operations that would trigger integrity check /// violations but you know the page will end up in a consistent state. pub fn pauseIntegrityChecks(self: *Page, v: bool) void { - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { if (v) { self.pause_integrity_checks += 1; } else { @@ -320,7 +320,7 @@ pub const Page = struct { /// when runtime safety is enabled. This is a no-op when runtime /// safety is disabled. This uses the libc allocator. pub fn assertIntegrity(self: *const Page) void { - if (comptime build_config.slow_runtime_safety) { + if (comptime build_options.slow_runtime_safety) { self.verifyIntegrity(std.heap.c_allocator) catch |err| { log.err("page integrity violation, crashing. err={}", .{err}); @panic("page integrity violation"); @@ -351,7 +351,7 @@ pub const Page = struct { // tests (non-Valgrind) anyways so we're verifying anyways. if (std.valgrind.runningOnValgrind() > 0) return; - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { if (self.pause_integrity_checks > 0) return; } @@ -760,7 +760,7 @@ pub const Page = struct { // This is an integrity check: if the row claims it doesn't // have managed memory then all cells must also not have // managed memory. - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { for (other_cells) |cell| { assert(!cell.hasGrapheme()); assert(!cell.hyperlink); @@ -787,7 +787,7 @@ pub const Page = struct { if (src_cell.hasGrapheme()) { // To prevent integrity checks flipping. This will // get fixed up when we check the style id below. - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { dst_cell.style_id = style.default_id; } @@ -914,7 +914,7 @@ pub const Page = struct { /// Get the cells for a row. pub fn getCells(self: *const Page, row: *Row) []Cell { - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { const rows = self.rows.ptr(self.memory); const cells = self.cells.ptr(self.memory); assert(@intFromPtr(row) >= @intFromPtr(rows)); @@ -1363,7 +1363,7 @@ pub const Page = struct { pub fn appendGrapheme(self: *Page, row: *Row, cell: *Cell, cp: u21) Allocator.Error!void { defer self.assertIntegrity(); - if (build_config.slow_runtime_safety) assert(cell.codepoint() != 0); + if (build_options.slow_runtime_safety) assert(cell.codepoint() != 0); const cell_offset = getOffset(Cell, self.memory, cell); var map = self.grapheme_map.map(self.memory); @@ -1436,7 +1436,7 @@ pub const Page = struct { /// there are scenarios where we want to move graphemes without changing /// the content tag. Callers beware but assertIntegrity should catch this. fn moveGrapheme(self: *Page, src: *Cell, dst: *Cell) void { - if (build_config.slow_runtime_safety) { + if (build_options.slow_runtime_safety) { assert(src.hasGrapheme()); assert(!dst.hasGrapheme()); } @@ -1453,7 +1453,7 @@ pub const Page = struct { /// Clear the graphemes for a given cell. pub fn clearGrapheme(self: *Page, row: *Row, cell: *Cell) void { defer self.assertIntegrity(); - if (build_config.slow_runtime_safety) assert(cell.hasGrapheme()); + if (build_options.slow_runtime_safety) assert(cell.hasGrapheme()); // Get our entry in the map, which must exist const cell_offset = getOffset(Cell, self.memory, cell);