aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/cli/list_fonts.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/cli/list_fonts.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/cli/list_fonts.zig')
-rw-r--r--vendor/libghostty-vt/src/cli/list_fonts.zig165
1 files changed, 165 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/cli/list_fonts.zig b/vendor/libghostty-vt/src/cli/list_fonts.zig
new file mode 100644
index 00000000..396c4e8a
--- /dev/null
+++ b/vendor/libghostty-vt/src/cli/list_fonts.zig
@@ -0,0 +1,165 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const ArenaAllocator = std.heap.ArenaAllocator;
+const Action = @import("ghostty.zig").Action;
+const args = @import("args.zig");
+const font = @import("../font/main.zig");
+
+const log = std.log.scoped(.list_fonts);
+
+pub const Options = struct {
+ /// This is set by the CLI parser for deinit.
+ _arena: ?ArenaAllocator = null,
+
+ /// The font family to search for. If this is set, then only fonts
+ /// matching this family will be listed.
+ family: ?[:0]const u8 = null,
+
+ /// The style name to search for.
+ style: ?[:0]const u8 = null,
+
+ /// Font styles to search for. If this is set, then only fonts that
+ /// match the given styles will be listed.
+ bold: bool = false,
+ italic: bool = false,
+
+ pub fn deinit(self: *Options) void {
+ if (self._arena) |arena| arena.deinit();
+ self.* = undefined;
+ }
+
+ /// Enables "-h" and "--help" to work.
+ pub fn help(self: Options) !void {
+ _ = self;
+ return Action.help_error;
+ }
+};
+
+/// The `list-fonts` command is used to list all the available fonts for
+/// Ghostty. This uses the exact same font discovery mechanism Ghostty uses to
+/// find fonts to use.
+///
+/// When executed with no arguments, this will list all available fonts, sorted
+/// by family name, then font name. If a family name is given with `--family`,
+/// the sorting will be disabled and the results instead will be shown in the
+/// same priority order Ghostty would use to pick a font.
+///
+/// Flags:
+///
+/// * `--bold`: Filter results to specific bold styles. It is not guaranteed
+/// that only those styles are returned. They are only prioritized.
+///
+/// * `--italic`: Filter results to specific italic styles. It is not guaranteed
+/// that only those styles are returned. They are only prioritized.
+///
+/// * `--style`: Filter results based on the style string advertised by a font.
+/// It is not guaranteed that only those styles are returned. They are only
+/// prioritized.
+///
+/// * `--family`: Filter results to a specific font family. The family handling
+/// is identical to the `font-family` set of Ghostty configuration values, so
+/// this can be used to debug why your desired font may not be loading.
+pub fn run(alloc: Allocator) !u8 {
+ var iter = try args.argsIterator(alloc);
+ defer iter.deinit();
+ return try runArgs(alloc, &iter);
+}
+
+fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
+ var config: Options = .{};
+ defer config.deinit();
+ try args.parse(Options, alloc_gpa, &config, argsIter);
+
+ // Use an arena for all our memory allocs
+ var arena = ArenaAllocator.init(alloc_gpa);
+ defer arena.deinit();
+ const alloc = arena.allocator();
+
+ // Its possible to build Ghostty without font discovery!
+ if (comptime font.Discover == void) {
+ var buffer: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&buffer);
+ const stderr = &stderr_writer.interface;
+ try stderr.print(
+ \\Ghostty was built without a font discovery mechanism. This is a compile-time
+ \\option. Please review how Ghostty was built from source, contact the
+ \\maintainer to enable a font discovery mechanism, and try again.
+ ,
+ .{},
+ );
+ try stderr.flush();
+ return 1;
+ }
+
+ var buffer: [2048]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ const stdout = &stdout_writer.interface;
+
+ // We'll be putting our fonts into a list categorized by family
+ // so it is easier to read the output.
+ var families: std.ArrayList([]const u8) = .empty;
+ var map: std.StringHashMap(std.ArrayListUnmanaged([]const u8)) = .init(alloc);
+
+ // Look up all available fonts
+ var disco = font.Discover.init();
+ defer disco.deinit();
+ var disco_it = try disco.discover(alloc, .{
+ .family = config.family,
+ .style = config.style,
+ .bold = config.bold,
+ .italic = config.italic,
+ .monospace = config.family == null,
+ });
+ defer disco_it.deinit();
+ while (try disco_it.next()) |face| {
+ var buf: [1024]u8 = undefined;
+
+ const family_buf = face.familyName(&buf) catch |err| {
+ log.err("failed to get font family name: {}", .{err});
+ continue;
+ };
+ const family = try alloc.dupe(u8, family_buf);
+
+ const full_name_buf = face.name(&buf) catch |err| {
+ log.err("failed to get font name: {}", .{err});
+ continue;
+ };
+ const full_name = try alloc.dupe(u8, full_name_buf);
+
+ const gop = try map.getOrPut(family);
+ if (!gop.found_existing) {
+ try families.append(alloc, family);
+ gop.value_ptr.* = .{};
+ }
+ try gop.value_ptr.append(alloc, full_name);
+ }
+
+ // Sort our keys.
+ if (config.family == null) {
+ std.mem.sortUnstable([]const u8, families.items, {}, struct {
+ fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool {
+ return std.mem.order(u8, lhs, rhs) == .lt;
+ }
+ }.lessThan);
+ }
+
+ // Output each
+ for (families.items) |family| {
+ const list = map.get(family) orelse continue;
+ if (list.items.len == 0) continue;
+ if (config.family == null) {
+ std.mem.sortUnstable([]const u8, list.items, {}, struct {
+ fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool {
+ return std.mem.order(u8, lhs, rhs) == .lt;
+ }
+ }.lessThan);
+ }
+
+ try stdout.print("{s}\n", .{family});
+ for (list.items) |item| try stdout.print(" {s}\n", .{item});
+ try stdout.print("\n", .{});
+ }
+
+ try stdout.flush();
+ return 0;
+}