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/fontconfig/pattern.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/pkg/fontconfig/pattern.zig')
| -rw-r--r-- | vendor/libghostty-vt/pkg/fontconfig/pattern.zig | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/pkg/fontconfig/pattern.zig b/vendor/libghostty-vt/pkg/fontconfig/pattern.zig new file mode 100644 index 00000000..3a623e22 --- /dev/null +++ b/vendor/libghostty-vt/pkg/fontconfig/pattern.zig @@ -0,0 +1,168 @@ +const std = @import("std"); +const assert = std.debug.assert; +const c = @import("c.zig").c; +const Error = @import("main.zig").Error; +const ObjectSet = @import("main.zig").ObjectSet; +const Property = @import("main.zig").Property; +const Result = @import("main.zig").Result; +const Value = @import("main.zig").Value; +const ValueBinding = @import("main.zig").ValueBinding; +const Weight = @import("main.zig").Weight; + +pub const Pattern = opaque { + pub fn create() *Pattern { + return @ptrCast(c.FcPatternCreate()); + } + + pub fn parse(str: [:0]const u8) *Pattern { + return @ptrCast(c.FcNameParse(str.ptr)); + } + + pub fn destroy(self: *Pattern) void { + c.FcPatternDestroy(self.cval()); + } + + pub fn defaultSubstitute(self: *Pattern) void { + c.FcDefaultSubstitute(self.cval()); + } + + pub fn add(self: *Pattern, prop: Property, value: Value, append: bool) bool { + return c.FcPatternAdd( + self.cval(), + prop.cval().ptr, + value.cval(), + if (append) c.FcTrue else c.FcFalse, + ) == c.FcTrue; + } + + pub fn get(self: *Pattern, prop: Property, id: u32) Error!Value { + var val: c.struct__FcValue = undefined; + try @as(Result, @enumFromInt(c.FcPatternGet( + self.cval(), + prop.cval().ptr, + @intCast(id), + &val, + ))).toError(); + + return .init(&val); + } + + pub fn delete(self: *Pattern, prop: Property) bool { + return c.FcPatternDel(self.cval(), prop.cval()) == c.FcTrue; + } + + pub fn filter(self: *Pattern, os: *const ObjectSet) *Pattern { + return @ptrCast(c.FcPatternFilter(self.cval(), os.cval())); + } + + pub fn objectIterator(self: *Pattern) ObjectIterator { + return .{ .pat = self.cval(), .iter = null }; + } + + pub fn print(self: *Pattern) void { + c.FcPatternPrint(self.cval()); + } + + pub inline fn cval(self: *Pattern) *c.struct__FcPattern { + return @ptrCast(self); + } + + pub const ObjectIterator = struct { + pat: *c.struct__FcPattern, + iter: ?c.struct__FcPatternIter, + + /// Move to the next object, returns true if there is another + /// object and false otherwise. If this is the first call, this + /// will be the first object. + pub fn next(self: *ObjectIterator) bool { + // Null means our first iterator + if (self.iter == null) { + // If we have no objects, do not create iterator + if (c.FcPatternObjectCount(self.pat) == 0) return false; + + var iter: c.struct__FcPatternIter = undefined; + c.FcPatternIterStart( + self.pat, + &iter, + ); + assert(c.FcPatternIterIsValid(self.pat, &iter) == c.FcTrue); + self.iter = iter; + + // Return right away because the fontconfig iterator pattern + // is do/while. + return true; + } + + return c.FcPatternIterNext(self.pat, @ptrCast(&self.iter)) == c.FcTrue; + } + + pub fn object(self: *ObjectIterator) []const u8 { + return std.mem.sliceTo(c.FcPatternIterGetObject( + self.pat, + &self.iter.?, + ), 0); + } + + pub fn valueLen(self: *ObjectIterator) usize { + return @intCast(c.FcPatternIterValueCount(self.pat, &self.iter.?)); + } + + pub fn valueIterator(self: *ObjectIterator) ValueIterator { + return .{ + .pat = self.pat, + .iter = &self.iter.?, + .max = c.FcPatternIterValueCount(self.pat, &self.iter.?), + }; + } + }; + + pub const ValueIterator = struct { + pat: *c.struct__FcPattern, + iter: *c.struct__FcPatternIter, + max: c_int, + id: c_int = 0, + + pub const Entry = struct { + result: Result, + value: Value, + binding: ValueBinding, + }; + + pub fn next(self: *ValueIterator) ?Entry { + if (self.id >= self.max) return null; + var value: c.struct__FcValue = undefined; + var binding: c.FcValueBinding = undefined; + const result = c.FcPatternIterGetValue(self.pat, self.iter, self.id, &value, &binding); + self.id += 1; + + return Entry{ + .result = @enumFromInt(result), + .binding = @enumFromInt(binding), + .value = .init(&value), + }; + } + }; +}; + +test "create" { + const testing = std.testing; + + var pat = Pattern.create(); + defer pat.destroy(); + + try testing.expect(pat.add(.family, .{ .string = "monospace" }, false)); + try testing.expect(pat.add(.weight, .{ .integer = @intFromEnum(Weight.bold) }, false)); + + { + const val = try pat.get(.family, 0); + try testing.expect(val == .string); + try testing.expectEqualStrings("monospace", val.string); + } +} + +test "name parse" { + var pat = Pattern.parse(":monospace"); + defer pat.destroy(); + + pat.defaultSubstitute(); +} |
