terminal: add lib.zig to centralize lib target and re-exports

Previously every file in the terminal package independently imported
build_options and ../lib/main.zig, then computed the same
lib_target constant. This was repetitive and meant each file needed
both imports just to get the target.

Introduce src/terminal/lib.zig which computes the target once and
re-exports the commonly used lib types (Enum, TaggedUnion, Struct,
String, checkGhosttyHEnum, structSizedFieldFits). All terminal
package files now import lib.zig and use lib.target instead of the
local lib_target constant, removing the per-file boilerplate.
This commit is contained in:
Mitchell Hashimoto
2026-03-25 07:22:02 -07:00
parent bebca84668
commit f50aa90ced
19 changed files with 69 additions and 78 deletions

View File

@@ -9,16 +9,13 @@ const ScreenSet = @This();
const std = @import("std");
const assert = @import("../quirks.zig").inlineAssert;
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib = @import("lib.zig");
const testing = std.testing;
const Allocator = std.mem.Allocator;
const Screen = @import("Screen.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
/// The possible keys for screens in the screen set.
pub const Key = lib.Enum(lib_target, &.{
pub const Key = lib.Enum(lib.target, &.{
"primary",
"alternate",
});

View File

@@ -5,7 +5,7 @@ const Terminal = @This();
const std = @import("std");
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib = @import("lib.zig");
const assert = @import("../quirks.zig").inlineAssert;
const testing = std.testing;
const Allocator = std.mem.Allocator;
@@ -35,8 +35,6 @@ const Page = pagepkg.Page;
const Cell = pagepkg.Cell;
const Row = pagepkg.Row;
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const log = std.log.scoped(.terminal);
/// Default tabstop interval
@@ -1706,14 +1704,14 @@ pub const ScrollViewport = union(Tag) {
/// Scroll by some delta amount, up is negative.
delta: isize,
pub const Tag = lib.Enum(lib_target, &.{
pub const Tag = lib.Enum(lib.target, &.{
"top",
"bottom",
"delta",
});
const c_union = lib.TaggedUnion(
lib_target,
lib.target,
@This(),
// Padding: largest variant is isize (8 bytes on 64-bit).
// Use [2]u64 (16 bytes) for future expansion.

View File

@@ -1,6 +1,4 @@
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
/// C0 (7-bit) control characters from ANSI.
///
@@ -54,7 +52,7 @@ pub const RenditionAspect = enum(u16) {
/// Possible cursor styles (ESC [ q)
pub const CursorStyle = lib.Enum(
lib_target,
lib.target,
&.{
"default",
"blinking_block",
@@ -78,7 +76,7 @@ pub const StatusLineType = enum(u16) {
/// The display to target for status updates (DECSASD).
pub const StatusDisplay = lib.Enum(
lib_target,
lib.target,
&.{
"main",
"status_line",
@@ -88,7 +86,7 @@ pub const StatusDisplay = lib.Enum(
/// The possible modify key formats to ESC[>{a};{b}m
/// Note: this is not complete, we should add more as we support more
pub const ModifyKeyFormat = lib.Enum(
lib_target,
lib.target,
&.{
"legacy",
"cursor_keys",

View File

@@ -1,7 +1,7 @@
const std = @import("std");
const testing = std.testing;
const Allocator = std.mem.Allocator;
const lib = @import("../../lib/main.zig");
const lib = @import("../lib.zig");
const lib_alloc = @import("../../lib/allocator.zig");
const CAllocator = lib_alloc.Allocator;
const colorpkg = @import("../color.zig");

View File

@@ -1,6 +1,6 @@
const std = @import("std");
const testing = std.testing;
const lib = @import("../../lib/main.zig");
const lib = @import("../lib.zig");
const lib_alloc = @import("../../lib/allocator.zig");
const CAllocator = lib_alloc.Allocator;
const ZigTerminal = @import("../Terminal.zig");

View File

@@ -1,6 +1,4 @@
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
/// Modes for the ED CSI command.
pub const EraseDisplay = enum(u8) {
@@ -38,7 +36,7 @@ pub const TabClear = enum(u8) {
/// Style formats for terminal size reports.
pub const SizeReportStyle = lib.Enum(
lib_target,
lib.target,
&.{
// XTWINOPS
"csi_14_t",

View File

@@ -1,11 +1,9 @@
const std = @import("std");
const testing = std.testing;
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
/// The device attribute request type (CSI c).
pub const Req = lib.Enum(lib_target, &.{
pub const Req = lib.Enum(lib.target, &.{
"primary", // Blank
"secondary", // >
"tertiary", // =

View File

@@ -1,10 +1,8 @@
const std = @import("std");
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
/// The color scheme reported in response to a CSI ? 996 n query.
pub const ColorScheme = lib.Enum(lib_target, &.{
pub const ColorScheme = lib.Enum(lib.target, &.{
"light",
"dark",
});

View File

@@ -1,7 +1,5 @@
const std = @import("std");
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
/// Maximum number of bytes that `encode` will write. Any users of this
/// should be resilient to this changing, so this is always a specific
@@ -10,7 +8,7 @@ pub const max_encode_size = 3;
/// A focus event that can be reported to the application running in the
/// terminal when focus reporting mode (mode 1004) is enabled.
pub const Event = lib.Enum(lib_target, &.{
pub const Event = lib.Enum(lib.target, &.{
"gained",
"lost",
});

View File

@@ -1,8 +1,6 @@
const std = @import("std");
const build_options = @import("terminal_options");
const assert = @import("../quirks.zig").inlineAssert;
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
const Allocator = std.mem.Allocator;
const color = @import("color.zig");
const size = @import("size.zig");
@@ -22,7 +20,7 @@ const Selection = @import("Selection.zig");
const Style = @import("style.zig").Style;
/// Formats available.
pub const Format = lib.Enum(lib_target, &.{
pub const Format = lib.Enum(lib.target, &.{
// Plain text.
"plain",

23
src/terminal/lib.zig Normal file
View File

@@ -0,0 +1,23 @@
const std = @import("std");
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
/// The target for the terminal lib in particular.
pub const target: lib.Target = if (build_options.c_abi) .c else .zig;
/// The calling convention to use for C APIs. If we're not building for
/// C ABI then we use auto which allows our C APIs to be cleanly called
/// by Zig. This is required because we modify our struct layouts based
/// on C ABI too.
pub const calling_conv: std.builtin.CallingConvention = if (build_options.c_abi)
.c
else
.auto;
/// Forwarded decls from lib that are used.
pub const Enum = lib.Enum;
pub const TaggedUnion = lib.TaggedUnion;
pub const Struct = lib.Struct;
pub const String = lib.String;
pub const checkGhosttyHEnum = lib.checkGhosttyHEnum;
pub const structSizedFieldFits = lib.structSizedFieldFits;

View File

@@ -1,11 +1,10 @@
const std = @import("std");
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
/// The event types that can be reported for mouse-related activities.
/// These are all mutually exclusive (hence in a single enum).
pub const Event = lib.Enum(lib_target, &.{
pub const Event = lib.Enum(lib.target, &.{
"none",
"x10", // 9
"normal", // 1000
@@ -20,7 +19,7 @@ pub fn eventSendsMotion(event: Event) bool {
/// The format of mouse events when enabled.
/// These are all mutually exclusive (hence in a single enum).
pub const Format = lib.Enum(lib_target, &.{
pub const Format = lib.Enum(lib.target, &.{
"x10",
"utf8", // 1005
"sgr", // 1006

View File

@@ -11,11 +11,11 @@ const build_options = @import("terminal_options");
const mem = std.mem;
const assert = @import("../quirks.zig").inlineAssert;
const Allocator = mem.Allocator;
const LibEnum = @import("../lib/enum.zig").Enum;
const lib = @import("lib.zig");
const LibEnum = lib.Enum;
const kitty_color = @import("kitty/color.zig");
const parsers = @import("osc/parsers.zig");
const encoding = @import("osc/encoding.zig");
const lib = @import("../lib/main.zig");
pub const color = parsers.color;
pub const semantic_prompt = parsers.semantic_prompt;
@@ -165,7 +165,7 @@ pub const Command = union(Key) {
pub const KittyClipboardProtocol = parsers.kitty_clipboard_protocol.OSC;
pub const Key = LibEnum(
if (build_options.c_abi) .c else .zig,
lib.target,
// NOTE: Order matters, see LibEnum documentation.
&.{
"invalid",

View File

@@ -2,27 +2,25 @@
//! Specification: https://sw.kovidgoyal.net/kitty/text-sizing-protocol/
const std = @import("std");
const build_options = @import("terminal_options");
const assert = @import("../../../quirks.zig").inlineAssert;
const Parser = @import("../../osc.zig").Parser;
const Command = @import("../../osc.zig").Command;
const encoding = @import("../encoding.zig");
const lib = @import("../../../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("../../lib.zig");
const log = std.log.scoped(.kitty_text_sizing);
pub const max_payload_length = 4096;
pub const VAlign = lib.Enum(lib_target, &.{
pub const VAlign = lib.Enum(lib.target, &.{
"top",
"bottom",
"center",
});
pub const HAlign = lib.Enum(lib_target, &.{
pub const HAlign = lib.Enum(lib.target, &.{
"left",
"right",
"center",

View File

@@ -1,18 +1,15 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib = @import("lib.zig");
const size = @import("size.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
/// The possible reference locations for a point. When someone says "(42, 80)"
/// in the context of a terminal, that could mean multiple things: it is in the
/// current visible viewport? the current active area of the screen where the
/// cursor is? the entire scrollback history? etc.
///
/// This tag is used to differentiate those cases.
pub const Tag = lib.Enum(lib_target, &.{
pub const Tag = lib.Enum(lib.target, &.{
// Top-left is part of the active area where a running program can
// jump the cursor and make changes. The active area is the "editable"
// part of the screen.
@@ -70,7 +67,7 @@ pub const Point = union(Tag) {
}
const c_union = lib.TaggedUnion(
lib_target,
lib.target,
@This(),
// Padding: largest variant is Coordinate (u16 + u32 = 6 bytes).
// Use [2]u64 (16 bytes) for future expansion.

View File

@@ -1,11 +1,9 @@
const std = @import("std");
const build_options = @import("terminal_options");
const assert = @import("../quirks.zig").inlineAssert;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const fastmem = @import("../fastmem.zig");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
const color = @import("color.zig");
const cursor = @import("cursor.zig");
const highlight = @import("highlight.zig");
@@ -226,7 +224,7 @@ pub const RenderState = struct {
};
// Dirty state.
pub const Dirty = lib.Enum(lib_target, &.{
pub const Dirty = lib.Enum(lib.target, &.{
// Not dirty at all. Can skip rendering if prior state was
// already rendered.
"false",

View File

@@ -1,15 +1,12 @@
//! SGR (Select Graphic Rendition) attrinvbute parsing and types.
const std = @import("std");
const build_options = @import("terminal_options");
const assert = @import("../quirks.zig").inlineAssert;
const testing = std.testing;
const lib = @import("../lib/main.zig");
const lib = @import("lib.zig");
const color = @import("color.zig");
const SepList = @import("Parser.zig").Action.CSI.SepList;
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
/// Attribute type for SGR
pub const Attribute = union(Tag) {
/// Unset all attributes
@@ -81,7 +78,7 @@ pub const Attribute = union(Tag) {
@"256_fg": u8,
pub const Tag = lib.Enum(
lib_target,
lib.target,
&.{
"unset",
"unknown",
@@ -158,7 +155,7 @@ pub const Attribute = union(Tag) {
/// C ABI functions.
const c_union = lib.TaggedUnion(
lib_target,
lib.target,
@This(),
// Padding size for C ABI compatibility.
// Largest variant is Unknown.C: 2 pointers + 2 usize = 32 bytes on 64-bit.

View File

@@ -1,11 +1,9 @@
const std = @import("std");
const build_options = @import("terminal_options");
const lib = @import("../lib/main.zig");
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
const lib = @import("lib.zig");
const CellCountInt = @import("size.zig").CellCountInt;
/// Output formats for terminal size reports written to the PTY.
pub const Style = lib.Enum(lib_target, &.{
pub const Style = lib.Enum(lib.target, &.{
// In-band size reports (mode 2048)
"mode_2048",
// XTWINOPS: report text area size in pixels
@@ -17,7 +15,7 @@ pub const Style = lib.Enum(lib_target, &.{
});
/// Runtime size values used to encode terminal size reports.
pub const Size = lib.Struct(lib_target, struct {
pub const Size = lib.Struct(lib.target, struct {
/// Terminal row count in cells.
rows: CellCountInt,

View File

@@ -5,7 +5,7 @@ const assert = @import("../quirks.zig").inlineAssert;
const testing = std.testing;
const Allocator = std.mem.Allocator;
const simd = @import("../simd/main.zig");
const lib = @import("../lib/main.zig");
const lib = @import("lib.zig");
const Parser = @import("Parser.zig");
const ansi = @import("ansi.zig");
const charsets = @import("charsets.zig");
@@ -29,8 +29,6 @@ const log = std.log.scoped(.stream);
/// do something else.
const debug = false;
const lib_target: lib.Target = if (build_options.c_abi) .c else .zig;
/// The possible actions that can be emitted by the Stream
/// function for handling.
pub const Action = union(Key) {
@@ -129,7 +127,7 @@ pub const Action = union(Key) {
semantic_prompt: SemanticPrompt,
pub const Key = lib.Enum(
lib_target,
lib.target,
&.{
"print",
"print_repeat",
@@ -229,7 +227,7 @@ pub const Action = union(Key) {
/// C ABI functions.
const c_union = lib.TaggedUnion(
lib_target,
lib.target,
@This(),
// TODO: Before shipping an ABI-compatible libghostty, verify this.
// This was just arbitrarily chosen for now.
@@ -254,7 +252,7 @@ pub const Action = union(Key) {
}
};
pub const InvokeCharset = lib.Struct(lib_target, struct {
pub const InvokeCharset = lib.Struct(lib.target, struct {
bank: charsets.ActiveSlot,
charset: charsets.Slots,
locking: bool,
@@ -384,7 +382,7 @@ pub const Action = union(Key) {
}
};
pub const ConfigureCharset = lib.Struct(lib_target, struct {
pub const ConfigureCharset = lib.Struct(lib.target, struct {
slot: charsets.Slots,
charset: charsets.Charset,
});