From 057f227145fcce8d92678c16591d936f54f202b8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 19 Mar 2026 13:59:48 -0700 Subject: [PATCH] terminal: convert Point to lib.Enum/lib.TaggedUnion with C header --- include/ghostty/vt/point.h | 88 ++++++++++++++++++++++++++++++++++++++ src/terminal/point.zig | 87 +++++++++++++++++++++---------------- 2 files changed, 139 insertions(+), 36 deletions(-) create mode 100644 include/ghostty/vt/point.h diff --git a/include/ghostty/vt/point.h b/include/ghostty/vt/point.h new file mode 100644 index 000000000..f152a5c46 --- /dev/null +++ b/include/ghostty/vt/point.h @@ -0,0 +1,88 @@ +/** + * @file point.h + * + * Terminal point types for referencing locations in the terminal grid. + */ + +#ifndef GHOSTTY_VT_POINT_H +#define GHOSTTY_VT_POINT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup point Point + * + * Types for referencing x/y positions in the terminal grid under + * different coordinate systems (active area, viewport, full screen, + * scrollback history). + * + * @{ + */ + +/** + * A coordinate in the terminal grid. + * + * @ingroup point + */ +typedef struct { + /** Column (0-indexed). */ + uint16_t x; + + /** Row (0-indexed). May exceed page size for screen/history tags. */ + uint32_t y; +} GhosttyPointCoordinate; + +/** + * Point reference tag. + * + * Determines which coordinate system a point uses. + * + * @ingroup point + */ +typedef enum { + /** Active area where the cursor can move. */ + GHOSTTY_POINT_TAG_ACTIVE = 0, + + /** Visible viewport (changes when scrolled). */ + GHOSTTY_POINT_TAG_VIEWPORT = 1, + + /** Full screen including scrollback. */ + GHOSTTY_POINT_TAG_SCREEN = 2, + + /** Scrollback history only (before active area). */ + GHOSTTY_POINT_TAG_HISTORY = 3, +} GhosttyPointTag; + +/** + * Point value union. + * + * @ingroup point + */ +typedef union { + /** Coordinate (used for all tag variants). */ + GhosttyPointCoordinate coordinate; + + /** Padding for ABI compatibility. Do not use. */ + uint64_t _padding[2]; +} GhosttyPointValue; + +/** + * Tagged union for a point in the terminal grid. + * + * @ingroup point + */ +typedef struct { + GhosttyPointTag tag; + GhosttyPointValue value; +} GhosttyPoint; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* GHOSTTY_VT_POINT_H */ diff --git a/src/terminal/point.zig b/src/terminal/point.zig index c5983fcbc..db834732c 100644 --- a/src/terminal/point.zig +++ b/src/terminal/point.zig @@ -1,52 +1,56 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +const build_options = @import("terminal_options"); +const lib = @import("../lib/main.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 = enum { - /// 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. - /// - /// The bottom-right of the active tag differs from all other tags - /// because it includes the full height (rows) of the screen, including - /// rows that may not be written yet. This is required because the active - /// area is fully "addressable" by the running program (see below) whereas - /// the other tags are used primarily for reading/modifying past-written - /// data so they can't address unwritten rows. - /// - /// Note for those less familiar with terminal functionality: there - /// are escape sequences to move the cursor to any position on - /// the screen, but it is limited to the size of the viewport and - /// the bottommost part of the screen. Terminal programs can't -- - /// with sequences at the time of writing this comment -- modify - /// anything in the scrollback, visible viewport (if it differs - /// from the active area), etc. - active, +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. + // + // The bottom-right of the active tag differs from all other tags + // because it includes the full height (rows) of the screen, including + // rows that may not be written yet. This is required because the active + // area is fully "addressable" by the running program (see below) whereas + // the other tags are used primarily for reading/modifying past-written + // data so they can't address unwritten rows. + // + // Note for those less familiar with terminal functionality: there + // are escape sequences to move the cursor to any position on + // the screen, but it is limited to the size of the viewport and + // the bottommost part of the screen. Terminal programs can't -- + // with sequences at the time of writing this comment -- modify + // anything in the scrollback, visible viewport (if it differs + // from the active area), etc. + "active", - /// Top-left is the visible viewport. This means that if the user - /// has scrolled in any direction, top-left changes. The bottom-right - /// is the last written row from the top-left. - viewport, + // Top-left is the visible viewport. This means that if the user + // has scrolled in any direction, top-left changes. The bottom-right + // is the last written row from the top-left. + "viewport", - /// Top-left is the furthest back in the scrollback history - /// supported by the screen and the bottom-right is the bottom-right - /// of the last written row. Note this last point is important: the - /// bottom right is NOT necessarily the same as "active" because - /// "active" always allows referencing the full rows tall of the - /// screen whereas "screen" only contains written rows. - screen, + // Top-left is the furthest back in the scrollback history + // supported by the screen and the bottom-right is the bottom-right + // of the last written row. Note this last point is important: the + // bottom right is NOT necessarily the same as "active" because + // "active" always allows referencing the full rows tall of the + // screen whereas "screen" only contains written rows. + "screen", - /// The top-left is the same as "screen" but the bottom-right is - /// the line just before the top of "active". This contains only - /// the scrollback history. - history, -}; + // The top-left is the same as "screen" but the bottom-right is + // the line just before the top of "active". This contains only + // the scrollback history. + "history", +}); /// An x/y point in the terminal for some definition of location (tag). pub const Point = union(Tag) { @@ -64,6 +68,17 @@ pub const Point = union(Tag) { => |v| v, }; } + + const c_union = lib.TaggedUnion( + lib_target, + @This(), + // Padding: largest variant is Coordinate (u16 + u32 = 6 bytes). + // Use [2]u64 (16 bytes) for future expansion. + [2]u64, + ); + pub const C = c_union.C; + pub const CValue = c_union.CValue; + pub const cval = c_union.cval; }; pub const Coordinate = extern struct {