mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-24 20:56:08 +03:00
160 lines
5.5 KiB
Zig
160 lines
5.5 KiB
Zig
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) {
|
|
const stderr = std.io.getStdErr().writer();
|
|
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.
|
|
,
|
|
.{},
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
const stdout = std.io.getStdOut().writer();
|
|
|
|
// 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).init(alloc);
|
|
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(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", .{});
|
|
}
|
|
|
|
return 0;
|
|
}
|