From 79685f87c420ca7a9d73fee5865bb5046b7df74b Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Wed, 24 Sep 2025 16:33:18 -0500 Subject: [PATCH] use comptime to make C String interface nicer --- src/config/CApi.zig | 2 +- src/main_c.zig | 31 ++++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/config/CApi.zig b/src/config/CApi.zig index f90b0ca24..154cc0c9c 100644 --- a/src/config/CApi.zig +++ b/src/config/CApi.zig @@ -131,7 +131,7 @@ export fn ghostty_config_open_path() c.String { }; // Capacity is len + 1 due to sentinel - return .fromSlice(path, path.len + 1); + return .fromSlice(path); } /// Sync with ghostty_diagnostic_s diff --git a/src/main_c.zig b/src/main_c.zig index 1212e0b07..a72d82a3e 100644 --- a/src/main_c.zig +++ b/src/main_c.zig @@ -63,21 +63,42 @@ const Info = extern struct { pub const String = extern struct { ptr: ?[*]const u8, len: usize, - cap: usize, + sentinel: bool, pub const empty: String = .{ .ptr = null, .len = 0, - .cap = 0, + .sentinel = false, }; - pub fn fromSlice(slice: []const u8, cap: usize) String { + pub fn fromSlice(slice: anytype) String { return .{ .ptr = slice.ptr, .len = slice.len, - .cap = cap, + .sentinel = sentinel: { + const info = @typeInfo(@TypeOf(slice)); + switch (info) { + .pointer => |p| { + if (p.size != .slice) @compileError("only slices supported"); + if (p.child != u8) @compileError("only u8 slices supported"); + const sentinel_ = p.sentinel(); + if (sentinel_) |sentinel| if (sentinel != 0) @compileError("only 0 is supported for sentinels"); + break :sentinel sentinel_ != null; + }, + else => @compileError("only []const u8 and [:0]const u8"), + } + }, }; } + + pub fn deinit(self: *const String) void { + const ptr = self.ptr orelse return; + if (self.sentinel) { + state.alloc.free(ptr[0..self.len :0]); + } else { + state.alloc.free(ptr[0..self.len]); + } + } }; /// Initialize ghostty global state. @@ -132,5 +153,5 @@ pub export fn ghostty_translate(msgid: [*:0]const u8) [*:0]const u8 { /// Free a string allocated by Ghostty. pub export fn ghostty_string_free(str: String) void { - state.alloc.free(str.ptr.?[0..str.cap]); + str.deinit(); }