mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-24 16:11:43 +00:00
libghostty: minor C/C++ compatibility fixes (#13801)
Minor things as I was just auditing the state of our headers: * Make sure all subheaders like `point.h` can be included standalone * Support Clang/GCC extensions for typed enums if we can detect it * Add missing structs to the `ghostty_type_json` function * Fix `GHOSTTY_INIT_SIZED` for C++ mode
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <ghostty/vt/types.h>
|
||||
|
||||
/* DA1 conformance levels (Pp parameter). */
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT100 1
|
||||
#define GHOSTTY_DA_CONFORMANCE_VT101 1
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <ghostty/vt/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -39,18 +39,21 @@
|
||||
* The Zig side backs all C enums with c_int, so the C declarations
|
||||
* must use int as their underlying type to maintain ABI compatibility.
|
||||
*
|
||||
* C23 (detected via __STDC_VERSION__ >= 202311L) supports explicit
|
||||
* enum underlying types with `enum : int { ... }`. For pre-C23
|
||||
* compilers, which are free to choose any type that can represent
|
||||
* all values (C11 §6.7.2.2), we add an INT_MAX sentinel as the last
|
||||
* entry to force the compiler to use int.
|
||||
* C++11 and C23 support explicit enum underlying types with
|
||||
* `enum : int { ... }`. Clang and GCC 13+ also support this syntax as
|
||||
* an extension in older C language modes, so use it when available.
|
||||
*
|
||||
* Other pre-C23 C compilers are free to choose any type that can
|
||||
* represent all values (C11 §6.7.2.2). For those compilers, we add an
|
||||
* INT_MAX sentinel as the last entry so the compatible type must be
|
||||
* able to represent INT_MAX. The exact compatible type and its
|
||||
* signedness remain implementation-defined in this fallback.
|
||||
*
|
||||
* INT_MAX is used 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.
|
||||
* because enum constants must have type int in pre-C23 C. Values above
|
||||
* INT_MAX are a constraint violation there; compilers that accept them
|
||||
* may interpret them as negative values via two's complement, which can
|
||||
* collide with legitimate negative enum values.
|
||||
*
|
||||
* Usage:
|
||||
* @code
|
||||
@@ -61,7 +64,18 @@
|
||||
* } Foo;
|
||||
* @endcode
|
||||
*/
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
|
||||
#if defined(__cplusplus) && \
|
||||
(__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700))
|
||||
#define GHOSTTY_ENUM_TYPED : int
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
|
||||
#define GHOSTTY_ENUM_TYPED : int
|
||||
#elif defined(__clang__)
|
||||
#if __has_extension(c_fixed_enum)
|
||||
#define GHOSTTY_ENUM_TYPED : int
|
||||
#else
|
||||
#define GHOSTTY_ENUM_TYPED
|
||||
#endif
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 13
|
||||
#define GHOSTTY_ENUM_TYPED : int
|
||||
#else
|
||||
#define GHOSTTY_ENUM_TYPED
|
||||
@@ -305,8 +319,17 @@ typedef struct {
|
||||
* opts.trim = true;
|
||||
* @endcode
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#define GHOSTTY_INIT_SIZED(type) \
|
||||
([]() noexcept { \
|
||||
type value{}; \
|
||||
value.size = sizeof(value); \
|
||||
return value; \
|
||||
}())
|
||||
#else
|
||||
#define GHOSTTY_INIT_SIZED(type) \
|
||||
((type){ .size = sizeof(type) })
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return a pointer to a null-terminated JSON string describing the
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
const std = @import("std");
|
||||
const lib = @import("../lib.zig");
|
||||
const color = @import("../color.zig");
|
||||
const sgr = @import("../sgr.zig");
|
||||
const color_c = @import("color.zig");
|
||||
const mouse_event = @import("mouse_event.zig");
|
||||
const point = @import("../point.zig");
|
||||
@@ -18,9 +19,11 @@ const selection = @import("selection.zig");
|
||||
const selection_gesture = @import("selection_gesture.zig");
|
||||
const render = @import("render.zig");
|
||||
const style_c = @import("style.zig");
|
||||
const kitty_graphics = @import("kitty_graphics.zig");
|
||||
const mouse_encode = @import("mouse_encode.zig");
|
||||
const grid_ref = @import("grid_ref.zig");
|
||||
const io = @import("io.zig");
|
||||
const sys = @import("sys.zig");
|
||||
|
||||
/// C: GhosttySurfacePosition
|
||||
pub const SurfacePosition = extern struct {
|
||||
@@ -38,6 +41,8 @@ pub const Codepoints = extern struct {
|
||||
pub const structs: std.StaticStringMap(StructInfo) = structs: {
|
||||
@setEvalBranchQuota(10_000);
|
||||
break :structs .initComptime(.{
|
||||
.{ "GhosttyAllocator", StructInfo.init(lib.alloc.Allocator) },
|
||||
.{ "GhosttyAllocatorVtable", StructInfo.init(lib.alloc.VTable) },
|
||||
.{ "GhosttyBuffer", StructInfo.init(lib.Buffer) },
|
||||
.{ "GhosttyClipboardContent", StructInfo.init(terminal.ClipboardContent) },
|
||||
.{ "GhosttyClipboardWrite", StructInfo.init(terminal.ClipboardWrite) },
|
||||
@@ -54,22 +59,28 @@ pub const structs: std.StaticStringMap(StructInfo) = structs: {
|
||||
.{ "GhosttyTerminalSelectWordOptions", StructInfo.init(selection.SelectWordOptions) },
|
||||
.{ "GhosttyTerminalSelectWordBetweenOptions", StructInfo.init(selection.SelectWordBetweenOptions) },
|
||||
.{ "GhosttyTerminalSelectLineOptions", StructInfo.init(selection.SelectLineOptions) },
|
||||
.{ "GhosttyTerminalSelectionFormatOptions", StructInfo.init(selection.FormatOptions) },
|
||||
.{ "GhosttyFormatterTerminalExtra", StructInfo.init(formatter.TerminalOptions.Extra) },
|
||||
.{ "GhosttyFormatterScreenExtra", StructInfo.init(formatter.ScreenOptions.Extra) },
|
||||
.{ "GhosttyGridRef", StructInfo.init(grid_ref.CGridRef) },
|
||||
.{ "GhosttyKittyGraphicsPlacementRenderInfo", StructInfo.init(kitty_graphics.PlacementRenderInfo) },
|
||||
.{ "GhosttyMouseEncoderSize", StructInfo.init(mouse_encode.Size) },
|
||||
.{ "GhosttyMousePosition", StructInfo.init(mouse_event.Position) },
|
||||
.{ "GhosttyPoint", StructInfo.init(point.Point.C) },
|
||||
.{ "GhosttyPointCoordinate", StructInfo.init(point.Coordinate) },
|
||||
.{ "GhosttyReader", StructInfo.init(io.Reader) },
|
||||
.{ "GhosttyRenderStateColors", StructInfo.init(render.Colors) },
|
||||
.{ "GhosttyRenderStateRowSelection", StructInfo.init(render.RowSelection) },
|
||||
.{ "GhosttySelectionGestureBehaviors", StructInfo.init(selection_gesture.Behaviors) },
|
||||
.{ "GhosttySelectionGestureGeometry", StructInfo.init(selection_gesture.Geometry) },
|
||||
.{ "GhosttySgrAttribute", StructInfo.init(sgr.Attribute.C) },
|
||||
.{ "GhosttySgrUnknown", StructInfo.init(sgr.Attribute.Unknown.C) },
|
||||
.{ "GhosttySizeReportSize", StructInfo.init(size_report.Size) },
|
||||
.{ "GhosttyString", StructInfo.init(lib.String) },
|
||||
.{ "GhosttySurfacePosition", StructInfo.init(SurfacePosition) },
|
||||
.{ "GhosttyStyle", StructInfo.init(style_c.Style) },
|
||||
.{ "GhosttyStyleColor", StructInfo.init(style_c.Color) },
|
||||
.{ "GhosttySysImage", StructInfo.init(sys.Image) },
|
||||
.{ "GhosttyTerminalDesktopNotification", StructInfo.init(terminal.DesktopNotification) },
|
||||
.{ "GhosttyTerminalModeConfig", StructInfo.init(terminal.ModeConfig) },
|
||||
.{ "GhosttyTerminalProgressReport", StructInfo.init(terminal.ProgressReport) },
|
||||
@@ -220,15 +231,61 @@ test "json parses" {
|
||||
|
||||
const root = parsed.value.object;
|
||||
|
||||
// Verify we have all expected structs
|
||||
try std.testing.expect(root.contains("GhosttyClipboardContent"));
|
||||
try std.testing.expect(root.contains("GhosttyClipboardWrite"));
|
||||
try std.testing.expect(root.contains("GhosttyFormatterTerminalOptions"));
|
||||
try std.testing.expect(root.contains("GhosttyTerminalModeConfig"));
|
||||
try std.testing.expect(root.contains("GhosttyTerminalUnknownSequence"));
|
||||
try std.testing.expect(root.contains("GhosttyTerminalUnknownStringSequence"));
|
||||
try std.testing.expect(root.contains("GhosttyReader"));
|
||||
try std.testing.expect(root.contains("GhosttyWriter"));
|
||||
// Verify we have every public struct declared by the C API headers.
|
||||
const expected_structs = [_][]const u8{
|
||||
"GhosttyAllocator",
|
||||
"GhosttyAllocatorVtable",
|
||||
"GhosttyBuffer",
|
||||
"GhosttyClipboardContent",
|
||||
"GhosttyClipboardWrite",
|
||||
"GhosttyCodepoints",
|
||||
"GhosttyColorPaletteMask",
|
||||
"GhosttyColorRgb",
|
||||
"GhosttyColorX11Entry",
|
||||
"GhosttyDeviceAttributes",
|
||||
"GhosttyDeviceAttributesPrimary",
|
||||
"GhosttyDeviceAttributesSecondary",
|
||||
"GhosttyDeviceAttributesTertiary",
|
||||
"GhosttyFormatterScreenExtra",
|
||||
"GhosttyFormatterTerminalExtra",
|
||||
"GhosttyFormatterTerminalOptions",
|
||||
"GhosttyGridRef",
|
||||
"GhosttyKittyGraphicsPlacementRenderInfo",
|
||||
"GhosttyMouseEncoderSize",
|
||||
"GhosttyMousePosition",
|
||||
"GhosttyPoint",
|
||||
"GhosttyPointCoordinate",
|
||||
"GhosttyReader",
|
||||
"GhosttyRenderStateColors",
|
||||
"GhosttyRenderStateRowSelection",
|
||||
"GhosttySelection",
|
||||
"GhosttySelectionGestureBehaviors",
|
||||
"GhosttySelectionGestureGeometry",
|
||||
"GhosttySgrAttribute",
|
||||
"GhosttySgrUnknown",
|
||||
"GhosttySizeReportSize",
|
||||
"GhosttyString",
|
||||
"GhosttyStyle",
|
||||
"GhosttyStyleColor",
|
||||
"GhosttySurfacePosition",
|
||||
"GhosttySysImage",
|
||||
"GhosttyTerminalDesktopNotification",
|
||||
"GhosttyTerminalModeConfig",
|
||||
"GhosttyTerminalProgressReport",
|
||||
"GhosttyTerminalScrollbar",
|
||||
"GhosttyTerminalScrollViewport",
|
||||
"GhosttyTerminalSelectLineOptions",
|
||||
"GhosttyTerminalSelectWordBetweenOptions",
|
||||
"GhosttyTerminalSelectWordOptions",
|
||||
"GhosttyTerminalSelectionFormatOptions",
|
||||
"GhosttyTerminalUnknownSequence",
|
||||
"GhosttyTerminalUnknownStringSequence",
|
||||
"GhosttyWriter",
|
||||
};
|
||||
try std.testing.expectEqual(expected_structs.len, root.count());
|
||||
for (expected_structs) |name| {
|
||||
try std.testing.expect(root.contains(name));
|
||||
}
|
||||
|
||||
const clipboard_content = root.get("GhosttyClipboardContent").?.object;
|
||||
const clipboard_content_fields = clipboard_content.get("fields").?.object;
|
||||
|
||||
Reference in New Issue
Block a user