From 1b46884e726ce063f183fbb119a6ac07fb7c7ba1 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 20 Sep 2025 20:47:37 -0700 Subject: [PATCH] terminal: add build option for oniguruma, which controls tmux cc mode --- src/build/GhosttyZig.zig | 1 + src/terminal/build_options.zig | 9 +++++++++ src/terminal/dcs.zig | 34 ++++++++++++++++++++++++++-------- src/terminal/main.zig | 3 ++- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/build/GhosttyZig.zig b/src/build/GhosttyZig.zig index e3c22bc67..571428233 100644 --- a/src/build/GhosttyZig.zig +++ b/src/build/GhosttyZig.zig @@ -23,6 +23,7 @@ pub fn init( deps.unicode_tables.addModuleImport(vt); vt_options.addOptions(b, vt, .{ .artifact = .lib, + .oniguruma = false, .slow_runtime_safety = switch (cfg.optimize) { .Debug => true, .ReleaseSafe, diff --git a/src/terminal/build_options.zig b/src/terminal/build_options.zig index 33cf7a2ef..98d9bc8fa 100644 --- a/src/terminal/build_options.zig +++ b/src/terminal/build_options.zig @@ -4,6 +4,10 @@ pub const Options = struct { /// The target artifact to build. This will gate some functionality. artifact: Artifact = .ghostty, + /// Whether Oniguruma regex support is available. If this isn't + /// available, some features will be disabled. + oniguruma: bool = true, + /// 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. @@ -26,6 +30,11 @@ pub fn addOptions( ) void { const opts = b.addOptions(); opts.addOption(Artifact, "artifact", v.artifact); + opts.addOption(bool, "oniguruma", v.oniguruma); opts.addOption(bool, "slow_runtime_safety", v.slow_runtime_safety); + + // These are synthesized based on other options. + opts.addOption(bool, "tmux_control_mode", v.oniguruma); + m.addOptions("terminal_options", opts); } diff --git a/src/terminal/dcs.zig b/src/terminal/dcs.zig index db5f95c4f..e4d0f3de2 100644 --- a/src/terminal/dcs.zig +++ b/src/terminal/dcs.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const build_options = @import("terminal_options"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const terminal = @import("main.zig"); @@ -51,6 +52,11 @@ pub const Handler = struct { 0 => switch (dcs.final) { // Tmux control mode 'p' => tmux: { + if (comptime !build_options.tmux_control_mode) { + log.debug("tmux control mode not enabled in build, ignoring", .{}); + break :tmux null; + } + // Tmux control mode must start with ESC P 1000 p if (dcs.params.len != 1 or dcs.params[0] != 1000) break :tmux null; @@ -121,9 +127,11 @@ pub const Handler = struct { .ignore, => {}, - .tmux => |*tmux| return .{ - .tmux = (try tmux.put(byte)) orelse return null, - }, + .tmux => |*tmux| if (comptime build_options.tmux_control_mode) { + return .{ + .tmux = (try tmux.put(byte)) orelse return null, + }; + } else unreachable, .xtgettcap => |*list| { if (list.items.len >= self.max_bytes) { @@ -157,10 +165,10 @@ pub const Handler = struct { .ignore, => null, - .tmux => tmux: { + .tmux => if (comptime build_options.tmux_control_mode) tmux: { self.state.deinit(); break :tmux .{ .tmux = .{ .exit = {} } }; - }, + } else unreachable, .xtgettcap => |list| xtgettcap: { for (list.items, 0..) |b, i| { @@ -203,7 +211,10 @@ pub const Command = union(enum) { decrqss: DECRQSS, /// Tmux control mode - tmux: terminal.tmux.Notification, + tmux: if (build_options.tmux_control_mode) + terminal.tmux.Notification + else + void, pub fn deinit(self: Command) void { switch (self) { @@ -269,7 +280,10 @@ const State = union(enum) { }, /// Tmux control mode: https://github.com/tmux/tmux/wiki/Control-Mode - tmux: terminal.tmux.Client, + tmux: if (build_options.tmux_control_mode) + terminal.tmux.Client + else + void, pub fn deinit(self: *State) void { switch (self.*) { @@ -279,7 +293,9 @@ const State = union(enum) { .xtgettcap => |*v| v.deinit(), .decrqss => {}, - .tmux => |*v| v.deinit(), + .tmux => |*v| if (comptime build_options.tmux_control_mode) { + v.deinit(); + } else unreachable, } } }; @@ -395,6 +411,8 @@ test "DECRQSS invalid command" { } test "tmux enter and implicit exit" { + if (comptime !build_options.tmux_control_mode) return error.SkipZigTest; + const testing = std.testing; const alloc = testing.allocator; diff --git a/src/terminal/main.zig b/src/terminal/main.zig index 74ffe6341..1fea9934e 100644 --- a/src/terminal/main.zig +++ b/src/terminal/main.zig @@ -1,4 +1,5 @@ const builtin = @import("builtin"); +const build_options = @import("terminal_options"); const charsets = @import("charsets.zig"); const sanitize = @import("sanitize.zig"); @@ -20,7 +21,7 @@ pub const page = @import("page.zig"); pub const parse_table = @import("parse_table.zig"); pub const search = @import("search.zig"); pub const size = @import("size.zig"); -pub const tmux = @import("tmux.zig"); +pub const tmux = if (build_options.tmux_control_mode) @import("tmux.zig") else struct {}; pub const x11_color = @import("x11_color.zig"); pub const Charset = charsets.Charset;