diff --git a/AGENTS.md b/AGENTS.md index 7098007f5..8a5254889 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,6 +22,8 @@ A file for [guiding coding agents](https://agents.md/). - Build WASM: `zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall` - Test: `zig build test-lib-vt -Dtest-filter=` - Prefer this when the change is in a libghostty-vt file +- All C enums in `include/ghostty/vt/` must have a `_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE` + sentinel as the last entry to force int enum sizing (pre-C23 portability). ## Directory Structure diff --git a/include/ghostty/vt/build_info.h b/include/ghostty/vt/build_info.h index 19999e77f..d0aedfdc1 100644 --- a/include/ghostty/vt/build_info.h +++ b/include/ghostty/vt/build_info.h @@ -40,6 +40,7 @@ typedef enum { GHOSTTY_OPTIMIZE_RELEASE_SAFE = 1, GHOSTTY_OPTIMIZE_RELEASE_SMALL = 2, GHOSTTY_OPTIMIZE_RELEASE_FAST = 3, + GHOSTTY_OPTIMIZE_MODE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyOptimizeMode; /** @@ -122,6 +123,7 @@ typedef enum { * Output type: GhosttyString * */ GHOSTTY_BUILD_INFO_VERSION_BUILD = 10, + GHOSTTY_BUILD_INFO_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyBuildInfo; /** diff --git a/include/ghostty/vt/device.h b/include/ghostty/vt/device.h index fdf6bca7d..3b6ba3d7c 100644 --- a/include/ghostty/vt/device.h +++ b/include/ghostty/vt/device.h @@ -74,6 +74,7 @@ extern "C" { typedef enum { GHOSTTY_COLOR_SCHEME_LIGHT = 0, GHOSTTY_COLOR_SCHEME_DARK = 1, + GHOSTTY_COLOR_SCHEME_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyColorScheme; /** diff --git a/include/ghostty/vt/focus.h b/include/ghostty/vt/focus.h index 6e4c9502c..2f4954965 100644 --- a/include/ghostty/vt/focus.h +++ b/include/ghostty/vt/focus.h @@ -40,6 +40,7 @@ typedef enum { GHOSTTY_FOCUS_GAINED = 0, /** Terminal window lost focus */ GHOSTTY_FOCUS_LOST = 1, + GHOSTTY_FOCUS_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyFocusEvent; /** diff --git a/include/ghostty/vt/formatter.h b/include/ghostty/vt/formatter.h index 9eacc6409..f0fc1447d 100644 --- a/include/ghostty/vt/formatter.h +++ b/include/ghostty/vt/formatter.h @@ -46,6 +46,7 @@ typedef enum { /** HTML with inline styles. */ GHOSTTY_FORMATTER_FORMAT_HTML, + GHOSTTY_FORMATTER_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyFormatterFormat; /** diff --git a/include/ghostty/vt/key/encoder.h b/include/ghostty/vt/key/encoder.h index 9d8282cec..5d1200741 100644 --- a/include/ghostty/vt/key/encoder.h +++ b/include/ghostty/vt/key/encoder.h @@ -73,6 +73,7 @@ typedef enum { GHOSTTY_OPTION_AS_ALT_LEFT = 2, /** Only right option key is treated as alt */ GHOSTTY_OPTION_AS_ALT_RIGHT = 3, + GHOSTTY_OPTION_AS_ALT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyOptionAsAlt; /** @@ -104,6 +105,7 @@ typedef enum { /** macOS option-as-alt setting (value: GhosttyOptionAsAlt) */ GHOSTTY_KEY_ENCODER_OPT_MACOS_OPTION_AS_ALT = 6, + GHOSTTY_KEY_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKeyEncoderOption; /** diff --git a/include/ghostty/vt/key/event.h b/include/ghostty/vt/key/event.h index bcc9d8dec..39f23d7e4 100644 --- a/include/ghostty/vt/key/event.h +++ b/include/ghostty/vt/key/event.h @@ -35,6 +35,7 @@ typedef enum { GHOSTTY_KEY_ACTION_PRESS = 1, /** Key is being repeated (held down) */ GHOSTTY_KEY_ACTION_REPEAT = 2, + GHOSTTY_KEY_ACTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKeyAction; /** @@ -296,6 +297,7 @@ typedef enum { GHOSTTY_KEY_COPY, GHOSTTY_KEY_CUT, GHOSTTY_KEY_PASTE, + GHOSTTY_KEY_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKey; /** diff --git a/include/ghostty/vt/kitty_graphics.h b/include/ghostty/vt/kitty_graphics.h index 1f6884348..b9ea64eb3 100644 --- a/include/ghostty/vt/kitty_graphics.h +++ b/include/ghostty/vt/kitty_graphics.h @@ -119,6 +119,7 @@ typedef enum { * Output type: GhosttyKittyGraphicsPlacementIterator * */ GHOSTTY_KITTY_GRAPHICS_DATA_PLACEMENT_ITERATOR = 1, + GHOSTTY_KITTY_GRAPHICS_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKittyGraphicsData; /** @@ -213,6 +214,7 @@ typedef enum { * Output type: int32_t * */ GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z = 12, + GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKittyGraphicsPlacementData; /** @@ -231,6 +233,7 @@ typedef enum { GHOSTTY_KITTY_PLACEMENT_LAYER_BELOW_BG = 1, GHOSTTY_KITTY_PLACEMENT_LAYER_BELOW_TEXT = 2, GHOSTTY_KITTY_PLACEMENT_LAYER_ABOVE_TEXT = 3, + GHOSTTY_KITTY_PLACEMENT_LAYER_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKittyPlacementLayer; /** @@ -245,6 +248,7 @@ typedef enum { * Input type: GhosttyKittyPlacementLayer * */ GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_LAYER = 0, + GHOSTTY_KITTY_GRAPHICS_PLACEMENT_ITERATOR_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKittyGraphicsPlacementIteratorOption; /** @@ -258,6 +262,7 @@ typedef enum { GHOSTTY_KITTY_IMAGE_FORMAT_PNG = 2, GHOSTTY_KITTY_IMAGE_FORMAT_GRAY_ALPHA = 3, GHOSTTY_KITTY_IMAGE_FORMAT_GRAY = 4, + GHOSTTY_KITTY_IMAGE_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKittyImageFormat; /** @@ -268,6 +273,7 @@ typedef enum { typedef enum { GHOSTTY_KITTY_IMAGE_COMPRESSION_NONE = 0, GHOSTTY_KITTY_IMAGE_COMPRESSION_ZLIB_DEFLATE = 1, + GHOSTTY_KITTY_IMAGE_COMPRESSION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKittyImageCompression; /** @@ -335,6 +341,7 @@ typedef enum { * Output type: size_t * */ GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN = 8, + GHOSTTY_KITTY_IMAGE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyKittyGraphicsImageData; /** diff --git a/include/ghostty/vt/modes.h b/include/ghostty/vt/modes.h index 513aaf5a5..f8fa7c009 100644 --- a/include/ghostty/vt/modes.h +++ b/include/ghostty/vt/modes.h @@ -157,6 +157,7 @@ typedef enum { GHOSTTY_MODE_REPORT_PERMANENTLY_SET = 3, /** Mode is permanently reset */ GHOSTTY_MODE_REPORT_PERMANENTLY_RESET = 4, + GHOSTTY_MODE_REPORT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyModeReportState; /** diff --git a/include/ghostty/vt/mouse/encoder.h b/include/ghostty/vt/mouse/encoder.h index 744b99303..a82dda089 100644 --- a/include/ghostty/vt/mouse/encoder.h +++ b/include/ghostty/vt/mouse/encoder.h @@ -45,6 +45,7 @@ typedef enum { /** Any-event tracking mode. */ GHOSTTY_MOUSE_TRACKING_ANY = 4, + GHOSTTY_MOUSE_TRACKING_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyMouseTrackingMode; /** @@ -58,6 +59,7 @@ typedef enum { GHOSTTY_MOUSE_FORMAT_SGR = 2, GHOSTTY_MOUSE_FORMAT_URXVT = 3, GHOSTTY_MOUSE_FORMAT_SGR_PIXELS = 4, + GHOSTTY_MOUSE_FORMAT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyMouseFormat; /** @@ -120,6 +122,7 @@ typedef enum { /** Whether to enable motion deduplication by last cell (value: bool). */ GHOSTTY_MOUSE_ENCODER_OPT_TRACK_LAST_CELL = 4, + GHOSTTY_MOUSE_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyMouseEncoderOption; /** diff --git a/include/ghostty/vt/mouse/event.h b/include/ghostty/vt/mouse/event.h index 5b72735fc..ac71881f2 100644 --- a/include/ghostty/vt/mouse/event.h +++ b/include/ghostty/vt/mouse/event.h @@ -36,6 +36,7 @@ typedef enum { /** Mouse moved. */ GHOSTTY_MOUSE_ACTION_MOTION = 2, + GHOSTTY_MOUSE_ACTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyMouseAction; /** @@ -56,6 +57,7 @@ typedef enum { GHOSTTY_MOUSE_BUTTON_NINE = 9, GHOSTTY_MOUSE_BUTTON_TEN = 10, GHOSTTY_MOUSE_BUTTON_ELEVEN = 11, + GHOSTTY_MOUSE_BUTTON_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyMouseButton; /** diff --git a/include/ghostty/vt/osc.h b/include/ghostty/vt/osc.h index e17a8a182..43d137061 100644 --- a/include/ghostty/vt/osc.h +++ b/include/ghostty/vt/osc.h @@ -63,6 +63,7 @@ typedef enum { GHOSTTY_OSC_COMMAND_CONEMU_XTERM_EMULATION = 20, GHOSTTY_OSC_COMMAND_CONEMU_COMMENT = 21, GHOSTTY_OSC_COMMAND_KITTY_TEXT_SIZING = 22, + GHOSTTY_OSC_COMMAND_TYPE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyOscCommandType; /** @@ -88,6 +89,7 @@ typedef enum { * the same parser instance. Memory is owned by the parser. */ GHOSTTY_OSC_DATA_CHANGE_WINDOW_TITLE_STR = 1, + GHOSTTY_OSC_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyOscCommandData; /** diff --git a/include/ghostty/vt/point.h b/include/ghostty/vt/point.h index f152a5c46..c1ade0f96 100644 --- a/include/ghostty/vt/point.h +++ b/include/ghostty/vt/point.h @@ -54,7 +54,8 @@ typedef enum { /** Scrollback history only (before active area). */ GHOSTTY_POINT_TAG_HISTORY = 3, -} GhosttyPointTag; + GHOSTTY_POINT_TAG_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, + } GhosttyPointTag; /** * Point value union. diff --git a/include/ghostty/vt/render.h b/include/ghostty/vt/render.h index b15be4902..759c9354c 100644 --- a/include/ghostty/vt/render.h +++ b/include/ghostty/vt/render.h @@ -95,6 +95,7 @@ typedef enum { /** Global state changed; renderer should redraw everything. */ GHOSTTY_RENDER_STATE_DIRTY_FULL = 2, + GHOSTTY_RENDER_STATE_DIRTY_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRenderStateDirty; /** @@ -114,6 +115,7 @@ typedef enum { /** Hollow block cursor. */ GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_BLOCK_HOLLOW = 3, + GHOSTTY_RENDER_STATE_CURSOR_VISUAL_STYLE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRenderStateCursorVisualStyle; /** @@ -185,6 +187,7 @@ typedef enum { /** Whether the cursor is on the tail of a wide character (bool). * Only valid when CURSOR_VIEWPORT_HAS_VALUE is true. */ GHOSTTY_RENDER_STATE_DATA_CURSOR_VIEWPORT_WIDE_TAIL = 17, + GHOSTTY_RENDER_STATE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRenderStateData; /** @@ -195,6 +198,7 @@ typedef enum { typedef enum { /** Set dirty state (GhosttyRenderStateDirty). */ GHOSTTY_RENDER_STATE_OPTION_DIRTY = 0, + GHOSTTY_RENDER_STATE_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRenderStateOption; /** @@ -217,6 +221,7 @@ typedef enum { * valid as long as the underlying render state is not updated. * It is unsafe to use cell data after updating the render state. */ GHOSTTY_RENDER_STATE_ROW_DATA_CELLS = 3, + GHOSTTY_RENDER_STATE_ROW_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRenderStateRowData; /** @@ -227,6 +232,7 @@ typedef enum { typedef enum { /** Set dirty state for the current row (bool). */ GHOSTTY_RENDER_STATE_ROW_OPTION_DIRTY = 0, + GHOSTTY_RENDER_STATE_ROW_OPTION_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRenderStateRowOption; /** @@ -509,6 +515,7 @@ typedef enum { * color, in which case the caller should use whatever default foreground * color it wants (e.g. the terminal foreground). */ GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_FG_COLOR = 6, + GHOSTTY_RENDER_STATE_ROW_CELLS_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRenderStateRowCellsData; /** diff --git a/include/ghostty/vt/screen.h b/include/ghostty/vt/screen.h index 89b4825fe..13bb8e43b 100644 --- a/include/ghostty/vt/screen.h +++ b/include/ghostty/vt/screen.h @@ -69,6 +69,7 @@ typedef enum { /** No text; background color as RGB. */ GHOSTTY_CELL_CONTENT_BG_COLOR_RGB = 3, + GHOSTTY_CELL_CONTENT_TAG_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyCellContentTag; /** @@ -90,6 +91,7 @@ typedef enum { /** Spacer at end of soft-wrapped line for a wide character. */ GHOSTTY_CELL_WIDE_SPACER_HEAD = 3, + GHOSTTY_CELL_WIDE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyCellWide; /** @@ -109,6 +111,7 @@ typedef enum { /** Content that is part of a shell prompt. */ GHOSTTY_CELL_SEMANTIC_PROMPT = 2, + GHOSTTY_CELL_SEMANTIC_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyCellSemanticContent; /** @@ -201,6 +204,7 @@ typedef enum { * Output type: GhosttyColorRgb * */ GHOSTTY_CELL_DATA_COLOR_RGB = 11, + GHOSTTY_CELL_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyCellData; /** @@ -220,6 +224,7 @@ typedef enum { /** Prompt cells exist and this is a continuation line. */ GHOSTTY_ROW_SEMANTIC_PROMPT_CONTINUATION = 2, + GHOSTTY_ROW_SEMANTIC_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRowSemanticPrompt; /** @@ -289,6 +294,7 @@ typedef enum { * Output type: bool * */ GHOSTTY_ROW_DATA_DIRTY = 8, + GHOSTTY_ROW_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyRowData; /** diff --git a/include/ghostty/vt/sgr.h b/include/ghostty/vt/sgr.h index b093bc9ff..00849283d 100644 --- a/include/ghostty/vt/sgr.h +++ b/include/ghostty/vt/sgr.h @@ -87,6 +87,7 @@ typedef enum { GHOSTTY_SGR_ATTR_BRIGHT_FG_8 = 28, GHOSTTY_SGR_ATTR_BG_256 = 29, GHOSTTY_SGR_ATTR_FG_256 = 30, + GHOSTTY_SGR_ATTR_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttySgrAttributeTag; /** @@ -101,6 +102,7 @@ typedef enum { GHOSTTY_SGR_UNDERLINE_CURLY = 3, GHOSTTY_SGR_UNDERLINE_DOTTED = 4, GHOSTTY_SGR_UNDERLINE_DASHED = 5, + GHOSTTY_SGR_UNDERLINE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttySgrUnderline; /** diff --git a/include/ghostty/vt/size_report.h b/include/ghostty/vt/size_report.h index 98c67c5ed..d65fa95f6 100644 --- a/include/ghostty/vt/size_report.h +++ b/include/ghostty/vt/size_report.h @@ -49,6 +49,7 @@ typedef enum { GHOSTTY_SIZE_REPORT_CSI_16_T = 2, /** XTWINOPS text area size in characters: ESC [ 8 ; rows ; cols t */ GHOSTTY_SIZE_REPORT_CSI_18_T = 3, + GHOSTTY_SIZE_REPORT_STYLE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttySizeReportStyle; /** diff --git a/include/ghostty/vt/style.h b/include/ghostty/vt/style.h index ac0495600..ea1750395 100644 --- a/include/ghostty/vt/style.h +++ b/include/ghostty/vt/style.h @@ -50,7 +50,8 @@ typedef enum { GHOSTTY_STYLE_COLOR_NONE = 0, GHOSTTY_STYLE_COLOR_PALETTE = 1, GHOSTTY_STYLE_COLOR_RGB = 2, -} GhosttyStyleColorTag; + GHOSTTY_STYLE_COLOR_TAG_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, + } GhosttyStyleColorTag; /** * Style color value union. diff --git a/include/ghostty/vt/sys.h b/include/ghostty/vt/sys.h index 0634f5ac8..56e60b237 100644 --- a/include/ghostty/vt/sys.h +++ b/include/ghostty/vt/sys.h @@ -106,6 +106,7 @@ typedef enum { * Input type: GhosttySysDecodePngFn (function pointer, or NULL) */ GHOSTTY_SYS_OPT_DECODE_PNG = 1, + GHOSTTY_SYS_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttySysOption; /** diff --git a/include/ghostty/vt/terminal.h b/include/ghostty/vt/terminal.h index a229dd700..c57ba27b5 100644 --- a/include/ghostty/vt/terminal.h +++ b/include/ghostty/vt/terminal.h @@ -189,6 +189,7 @@ typedef enum { /** Scroll by a delta amount (up is negative). */ GHOSTTY_SCROLL_VIEWPORT_DELTA, + GHOSTTY_SCROLL_VIEWPORT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyTerminalScrollViewportTag; /** @@ -227,6 +228,7 @@ typedef enum { /** The alternate screen. */ GHOSTTY_TERMINAL_SCREEN_ALTERNATE = 1, + GHOSTTY_TERMINAL_SCREEN_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyTerminalScreen; /** @@ -571,6 +573,7 @@ typedef enum { * Input type: bool* */ GHOSTTY_TERMINAL_OPT_KITTY_IMAGE_MEDIUM_SHARED_MEM = 18, + GHOSTTY_TERMINAL_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyTerminalOption; /** @@ -846,6 +849,7 @@ typedef enum { * Output type: GhosttyKittyGraphics * */ GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS = 30, + GHOSTTY_TERMINAL_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyTerminalData; /** diff --git a/include/ghostty/vt/types.h b/include/ghostty/vt/types.h index 0fe37e3b2..70ac11d57 100644 --- a/include/ghostty/vt/types.h +++ b/include/ghostty/vt/types.h @@ -7,6 +7,7 @@ #ifndef GHOSTTY_VT_TYPES_H #define GHOSTTY_VT_TYPES_H +#include #include #include @@ -32,6 +33,26 @@ #endif #endif +/** + * Sentinel value for enum definitions to force max int width sizing. + * + * Pre-C23, the C standard allows compilers to choose any integer type + * that can represent all enum values (C11 ยง6.7.2.2), so small enums + * could be backed by char or short. Adding this value as the last + * entry in every enum forces the compiler to use at an `int` + * type, ensuring ABI stability across compilers and platforms. + * + * We use INT_MAX rather than a fixed constant like 0xFFFFFFFF because + * enum constants must have type int (which is signed). Values above + * INT_MAX overflow signed int and are a constraint violation in + * standard C; compilers that accept them interpret them as negative + * values via two's complement, which can collide with legitimate + * negative enum values. Using INT_MAX also ensures the enum matches + * the target's int size, which is important because the Zig side + * backs these enums with c_int for ABI compatibility. + */ +#define GHOSTTY_ENUM_MAX_VALUE INT_MAX + /** * Result codes for libghostty-vt operations. */ @@ -46,6 +67,7 @@ typedef enum { GHOSTTY_OUT_OF_SPACE = -3, /** The requested value has no value */ GHOSTTY_NO_VALUE = -4, + GHOSTTY_RESULT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyResult; /* ---- Opaque handles ---- */