From 7de4d569b0c9483c5945f277f616ef40a821e82f Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 6 Jul 2025 10:49:00 -0600 Subject: [PATCH 1/3] Revert "rely on stdin/stdout instead of hardcoded paths" This reverts commit 2fca0477bc7f3c955daf40a0d4663d63ef3d76a1. The idea of using stdin and stdout was the integrate it in to the build script, but since we don't want to do that because it contains an eval, it just makes it more annoying to use. --- src/font/nerd_font_codegen.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/font/nerd_font_codegen.py b/src/font/nerd_font_codegen.py index 52d70ac01..99915c9f2 100644 --- a/src/font/nerd_font_codegen.py +++ b/src/font/nerd_font_codegen.py @@ -10,9 +10,9 @@ be safe and not malicious or anything. import ast import math -import sys from collections import defaultdict from contextlib import suppress +from pathlib import Path from types import SimpleNamespace from typing import Literal, TypedDict, cast @@ -236,9 +236,16 @@ def generate_zig_switch_arms(patch_sets: list[PatchSet]) -> str: if __name__ == "__main__": - source = sys.stdin.read() + project_root = Path(__file__).resolve().parents[2] + + patcher_path = project_root / "vendor" / "nerd-fonts" / "font-patcher.py" + source = patcher_path.read_text(encoding="utf-8") patch_set = extract_patch_set_values(source) - print("""//! This is a generated file, produced by nerd_font_codegen.py + + out_path = project_root / "src" / "font" / "nerd_font_attributes.zig" + + with out_path.open("w", encoding="utf-8") as f: + f.write("""//! This is a generated file, produced by nerd_font_codegen.py //! DO NOT EDIT BY HAND! //! //! This file provides info extracted from the nerd fonts patcher script, @@ -248,6 +255,7 @@ const Constraint = @import("face.zig").RenderOptions.Constraint; /// Get the a constraints for the provided codepoint. pub fn getConstraint(cp: u21) Constraint { - return switch (cp) {""") - print(generate_zig_switch_arms(patch_set)) - print(" else => .none,\n };\n}") + return switch (cp) { +""") + f.write(generate_zig_switch_arms(patch_set)) + f.write("\n else => .none,\n };\n}\n") From 8f989f6bfd44b60cfe492031b3ba247be89dd041 Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 6 Jul 2025 11:02:00 -0600 Subject: [PATCH 2/3] font: fix nerd font codegen to handle ypadding properly Previously `ypadding` was effectively ignored, since it's mutually exclusive with `overlap`. This had a noticeable effect on the heavy bracket characters U+276C...U+2771, which were much taller than they should have been. I also fixed the vertical overlap limit, since negative `overlap` values are used in the nerd font attributes to create padding on all sides of the cell, so we don't want to limit the magnitude of the overlap for vertical padding, we only want to limit it if the value is positive. That change fixed the vertical padding for a handful of ranges, which should give more consistent results. --- src/font/nerd_font_attributes.zig | 22 ++++++++++++---------- src/font/nerd_font_codegen.py | 11 ++++++++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/font/nerd_font_attributes.zig b/src/font/nerd_font_attributes.zig index dfb11c5a5..a82699b0e 100644 --- a/src/font/nerd_font_attributes.zig +++ b/src/font/nerd_font_attributes.zig @@ -28,8 +28,8 @@ pub fn getConstraint(cp: u21) Constraint { .align_vertical = .center, .pad_left = 0.1, .pad_right = 0.1, - .pad_top = 0.01, - .pad_bottom = 0.01, + .pad_top = 0.1, + .pad_bottom = 0.1, }, 0x276c...0x2771, => .{ @@ -37,6 +37,8 @@ pub fn getConstraint(cp: u21) Constraint { .size_vertical = .fit, .align_horizontal = .center, .align_vertical = .center, + .pad_top = 0.3, + .pad_bottom = 0.3, }, 0xe0b0, => .{ @@ -204,8 +206,8 @@ pub fn getConstraint(cp: u21) Constraint { .align_vertical = .center, .pad_left = 0.03, .pad_right = 0.03, - .pad_top = 0.01, - .pad_bottom = 0.01, + .pad_top = 0.03, + .pad_bottom = 0.03, .max_xy_ratio = 0.86, }, 0xe0c5, @@ -216,8 +218,8 @@ pub fn getConstraint(cp: u21) Constraint { .align_vertical = .center, .pad_left = 0.03, .pad_right = 0.03, - .pad_top = 0.01, - .pad_bottom = 0.01, + .pad_top = 0.03, + .pad_bottom = 0.03, .max_xy_ratio = 0.86, }, 0xe0c6, @@ -228,8 +230,8 @@ pub fn getConstraint(cp: u21) Constraint { .align_vertical = .center, .pad_left = 0.03, .pad_right = 0.03, - .pad_top = 0.01, - .pad_bottom = 0.01, + .pad_top = 0.03, + .pad_bottom = 0.03, .max_xy_ratio = 0.78, }, 0xe0c7, @@ -240,8 +242,8 @@ pub fn getConstraint(cp: u21) Constraint { .align_vertical = .center, .pad_left = 0.03, .pad_right = 0.03, - .pad_top = 0.01, - .pad_bottom = 0.01, + .pad_top = 0.03, + .pad_bottom = 0.03, .max_xy_ratio = 0.78, }, 0xe0cc, diff --git a/src/font/nerd_font_codegen.py b/src/font/nerd_font_codegen.py index 99915c9f2..b62768cc5 100644 --- a/src/font/nerd_font_codegen.py +++ b/src/font/nerd_font_codegen.py @@ -6,6 +6,8 @@ attributes and scaling rules. This does include an `eval` call! This is spooky, but we trust the nerd fonts code to be safe and not malicious or anything. + +This script requires Python 3.12 or greater. """ import ast @@ -193,13 +195,20 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry) if valign is not None: s += f" .align_vertical = {valign},\n" + # `overlap` and `ypadding` are mutually exclusive, + # this is asserted in the nerd fonts patcher itself. if overlap: pad = -overlap s += f" .pad_left = {pad},\n" s += f" .pad_right = {pad},\n" - v_pad = y_padding - math.copysign(min(0.01, abs(overlap)), overlap) + # In the nerd fonts patcher, overlap values + # are capped at 0.01 in the vertical direction. + v_pad = -min(0.01, overlap) s += f" .pad_top = {v_pad},\n" s += f" .pad_bottom = {v_pad},\n" + elif y_padding: + s += f" .pad_top = {y_padding},\n" + s += f" .pad_bottom = {y_padding},\n" if xy_ratio > 0: s += f" .max_xy_ratio = {xy_ratio},\n" From c7e65b0c1c75c1512bab068a0c37a22f417bd0e4 Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 6 Jul 2025 11:23:49 -0600 Subject: [PATCH 3/3] font: respect cell width attributes in nerd font constraints This mostly applies to powerline glyphs, but is also relevant for heavy bracket characters, which need to always be 1 wide otherwise they look silly because they misalign depending on if there's a space after them or not. --- src/font/face.zig | 27 ++++++++++++++++++++------- src/font/face/coretext.zig | 3 ++- src/font/face/freetype.zig | 3 ++- src/font/nerd_font_attributes.zig | 19 +++++++++++++++++++ src/font/nerd_font_codegen.py | 6 ++++++ 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/font/face.zig b/src/font/face.zig index 363576ff0..245edcf4b 100644 --- a/src/font/face.zig +++ b/src/font/face.zig @@ -147,6 +147,9 @@ pub const RenderOptions = struct { /// Maximum ratio of width to height when resizing. max_xy_ratio: ?f64 = null, + /// Maximum number of cells horizontally to use. + max_constraint_width: u2 = 2, + pub const Size = enum { /// Don't change the size of this glyph. none, @@ -186,16 +189,26 @@ pub const RenderOptions = struct { pub fn constrain( self: Constraint, glyph: GlyphSize, - /// Available width + /// Width of one cell. cell_width: f64, - /// Available height + /// Height of one cell. cell_height: f64, + /// Number of cells horizontally available for this glyph. + constraint_width: u2, ) GlyphSize { var g = glyph; - const w = cell_width - - self.pad_left * cell_width - - self.pad_right * cell_width; + const available_width = + cell_width * @as(f64, @floatFromInt( + @min( + self.max_constraint_width, + constraint_width, + ), + )); + + const w = available_width - + self.pad_left * available_width - + self.pad_right * available_width; const h = cell_height - self.pad_top * cell_height - self.pad_bottom * cell_height; @@ -203,7 +216,7 @@ pub const RenderOptions = struct { // Subtract padding from the bearings so that our // alignment and sizing code works correctly. We // re-add before returning. - g.x -= self.pad_left * cell_width; + g.x -= self.pad_left * available_width; g.y -= self.pad_bottom * cell_height; switch (self.size_horizontal) { @@ -305,7 +318,7 @@ pub const RenderOptions = struct { } // Re-add our padding before returning. - g.x += self.pad_left * cell_width; + g.x += self.pad_left * available_width; g.y += self.pad_bottom * cell_height; return g; diff --git a/src/font/face/coretext.zig b/src/font/face/coretext.zig index 89d771d95..5c9c259d2 100644 --- a/src/font/face/coretext.zig +++ b/src/font/face/coretext.zig @@ -337,7 +337,7 @@ pub const Face = struct { }; const metrics = opts.grid_metrics; - const cell_width: f64 = @floatFromInt(metrics.cell_width * opts.constraint_width); + const cell_width: f64 = @floatFromInt(metrics.cell_width); const cell_height: f64 = @floatFromInt(metrics.cell_height); const glyph_size = opts.constraint.constrain( @@ -349,6 +349,7 @@ pub const Face = struct { }, cell_width, cell_height, + opts.constraint_width, ); const width = glyph_size.width; diff --git a/src/font/face/freetype.zig b/src/font/face/freetype.zig index 585d21c5b..b27b28ab8 100644 --- a/src/font/face/freetype.zig +++ b/src/font/face/freetype.zig @@ -390,7 +390,7 @@ pub const Face = struct { // Next we need to apply any constraints. const metrics = opts.grid_metrics; - const cell_width: f64 = @floatFromInt(metrics.cell_width * opts.constraint_width); + const cell_width: f64 = @floatFromInt(metrics.cell_width); const cell_height: f64 = @floatFromInt(metrics.cell_height); const glyph_x: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingX); @@ -405,6 +405,7 @@ pub const Face = struct { }, cell_width, cell_height, + opts.constraint_width, ); const width = glyph_size.width; diff --git a/src/font/nerd_font_attributes.zig b/src/font/nerd_font_attributes.zig index a82699b0e..817d838f8 100644 --- a/src/font/nerd_font_attributes.zig +++ b/src/font/nerd_font_attributes.zig @@ -13,6 +13,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .center, .align_vertical = .center, .pad_left = -0.02, @@ -24,6 +25,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .cover, .size_vertical = .fit, + .max_constraint_width = 1, .align_horizontal = .center, .align_vertical = .center, .pad_left = 0.1, @@ -35,6 +37,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .cover, .size_vertical = .fit, + .max_constraint_width = 1, .align_horizontal = .center, .align_vertical = .center, .pad_top = 0.3, @@ -44,6 +47,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, .pad_left = -0.06, @@ -56,6 +60,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, .max_xy_ratio = 0.7, @@ -64,6 +69,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, .pad_left = -0.06, @@ -76,6 +82,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, .max_xy_ratio = 0.7, @@ -84,6 +91,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, .pad_left = -0.06, @@ -96,6 +104,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, .max_xy_ratio = 0.5, @@ -104,6 +113,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, .pad_left = -0.06, @@ -116,6 +126,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, .max_xy_ratio = 0.5, @@ -125,6 +136,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, .pad_left = -0.05, @@ -137,6 +149,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, }, @@ -145,6 +158,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, .pad_left = -0.05, @@ -157,6 +171,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, }, @@ -287,6 +302,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, .pad_left = -0.02, @@ -299,6 +315,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, .pad_left = -0.02, @@ -311,6 +328,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .start, .align_vertical = .center, .pad_left = -0.05, @@ -323,6 +341,7 @@ pub fn getConstraint(cp: u21) Constraint { => .{ .size_horizontal = .stretch, .size_vertical = .stretch, + .max_constraint_width = 1, .align_horizontal = .end, .align_vertical = .center, .pad_left = -0.05, diff --git a/src/font/nerd_font_codegen.py b/src/font/nerd_font_codegen.py index b62768cc5..f8ff7caa6 100644 --- a/src/font/nerd_font_codegen.py +++ b/src/font/nerd_font_codegen.py @@ -190,6 +190,12 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry) s += " .size_horizontal = .fit,\n" s += " .size_vertical = .fit,\n" + # There are two cases where we want to limit the constraint width to 1: + # - If there's a `1` in the stretch mode string. + # - If the stretch mode is `xy` and there's not an explicit `2`. + if "1" in stretch or ("xy" in stretch and "2" not in stretch): + s += " .max_constraint_width = 1,\n" + if align is not None: s += f" .align_horizontal = {align},\n" if valign is not None: