diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/pkg/macos/foundation/string.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/pkg/macos/foundation/string.zig')
| -rw-r--r-- | vendor/libghostty-vt/pkg/macos/foundation/string.zig | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/pkg/macos/foundation/string.zig b/vendor/libghostty-vt/pkg/macos/foundation/string.zig new file mode 100644 index 00000000..2f679fef --- /dev/null +++ b/vendor/libghostty-vt/pkg/macos/foundation/string.zig @@ -0,0 +1,174 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const foundation = @import("../foundation.zig"); +const c = @import("c.zig").c; + +pub const String = opaque { + pub fn createWithBytes( + bs: []const u8, + encoding: StringEncoding, + external: bool, + ) Allocator.Error!*String { + return @as(?*String, @ptrFromInt(@intFromPtr(c.CFStringCreateWithBytes( + null, + bs.ptr, + @intCast(bs.len), + @intFromEnum(encoding), + @intFromBool(external), + )))) orelse Allocator.Error.OutOfMemory; + } + + pub fn createWithCharactersNoCopy( + unichars: []const u16, + ) *String { + return @as(*String, @ptrFromInt(@intFromPtr(c.CFStringCreateWithCharactersNoCopy( + null, + @ptrCast(unichars.ptr), + @intCast(unichars.len), + foundation.c.kCFAllocatorNull, + )))); + } + + pub fn release(self: *String) void { + c.CFRelease(self); + } + + pub fn getLength(self: *String) usize { + return @intCast(c.CFStringGetLength(@ptrCast(self))); + } + + pub fn hasPrefix(self: *String, prefix: *String) bool { + return c.CFStringHasPrefix( + @ptrCast(self), + @ptrCast(prefix), + ) == 1; + } + + pub fn compare( + self: *String, + other: *String, + options: StringComparison, + ) foundation.ComparisonResult { + return @enumFromInt(c.CFStringCompare( + @ptrCast(self), + @ptrCast(other), + @intCast(@as(c_int, @bitCast(options))), + )); + } + + pub fn cstring(self: *String, buf: []u8, encoding: StringEncoding) ?[]const u8 { + if (c.CFStringGetCString( + @ptrCast(self), + buf.ptr, + @intCast(buf.len), + @intFromEnum(encoding), + ) == 0) return null; + return std.mem.sliceTo(buf, 0); + } + + pub fn cstringPtr(self: *String, encoding: StringEncoding) ?[:0]const u8 { + const ptr = c.CFStringGetCStringPtr( + @ptrCast(self), + @intFromEnum(encoding), + ); + if (ptr == null) return null; + return std.mem.sliceTo(ptr, 0); + } +}; + +pub const MutableString = opaque { + pub fn create(cap: usize) !*MutableString { + return @ptrCast(c.CFStringCreateMutable( + null, + @intCast(cap), + ) orelse return Allocator.Error.OutOfMemory); + } + + pub fn release(self: *MutableString) void { + foundation.CFRelease(self); + } + + pub fn string(self: *MutableString) *String { + return @ptrCast(self); + } + + pub fn appendCharacters(self: *MutableString, chars: []const u16) void { + c.CFStringAppendCharacters( + @ptrCast(self), + chars.ptr, + @intCast(chars.len), + ); + } +}; + +pub const StringComparison = packed struct { + case_insensitive: bool = false, + _unused_2: bool = false, + backwards: bool = false, + anchored: bool = false, + nonliteral: bool = false, + localized: bool = false, + numerically: bool = false, + diacritic_insensitive: bool = false, + width_insensitive: bool = false, + forced_ordering: bool = false, + _padding: u22 = 0, + + test { + try std.testing.expectEqual(@bitSizeOf(c_int), @bitSizeOf(StringComparison)); + } +}; + +/// https://developer.apple.com/documentation/corefoundation/cfstringencoding?language=objc +pub const StringEncoding = enum(u32) { + invalid = 0xffffffff, + mac_roman = 0, + windows_latin1 = 0x0500, + iso_latin1 = 0x0201, + nextstep_latin = 0x0B01, + ascii = 0x0600, + unicode = 0x0100, + utf8 = 0x08000100, + non_lossy_ascii = 0x0BFF, + utf16_be = 0x10000100, + utf16_le = 0x14000100, + utf32 = 0x0c000100, + utf32_be = 0x18000100, + utf32_le = 0x1c000100, +}; + +pub fn stringGetSurrogatePairForLongCharacter( + ch: u32, + surrogates: []u16, +) bool { + assert(surrogates.len >= 2); + return c.CFStringGetSurrogatePairForLongCharacter(ch, surrogates.ptr) == 1; +} + +test "string" { + const testing = std.testing; + + const str = try String.createWithBytes("hello world", .ascii, false); + defer str.release(); + + const prefix = try String.createWithBytes("hello", .ascii, false); + defer prefix.release(); + + try testing.expect(str.hasPrefix(prefix)); + try testing.expectEqual(foundation.ComparisonResult.equal, str.compare(str, .{})); + try testing.expectEqualStrings("hello world", str.cstringPtr(.ascii).?); + + { + var buf: [128]u8 = undefined; + const cstr = str.cstring(&buf, .ascii).?; + try testing.expectEqualStrings("hello world", cstr); + } +} + +test "unichar" { + const testing = std.testing; + + var unichars: [2]u16 = undefined; + try testing.expect(!stringGetSurrogatePairForLongCharacter('A', &unichars)); +} |
