diff --git a/src/config/Config.zig b/src/config/Config.zig index a203a32a1..7d8c7d9ff 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -412,16 +412,13 @@ pub const compatibility = std.StaticStringMap( @"adjust-box-thickness": ?MetricModifier = null, /// Height in pixels or percentage adjustment of maximum height for nerd font icons. /// -/// Increasing this value will allow nerd font icons to be larger, but won't -/// necessarily force them to be. Decreasing this value will make nerd font -/// icons smaller. +/// A positive (negative) value will increase (decrease) the maximum icon +/// height. This may not affect all icons equally: the effect depends on whether +/// the default size of the icon is height-constrained, which in turn depends on +/// the aspect ratio of both the icon and your primary font. /// -/// This value only applies to icons that are constrained to a single cell by -/// neighboring characters. An icon that is free to spread across two cells -/// can always use up to the full line height of the primary font. -/// -/// The default value is 2/3 times the height of capital letters in your primary -/// font plus 1/3 times the font's line height. +/// Certain icons designed for box drawing and terminal graphics, such as +/// Powerline symbols, are not affected by this option. /// /// See the notes about adjustments in `adjust-cell-width`. /// diff --git a/src/font/Collection.zig b/src/font/Collection.zig index 5ec076608..b587245aa 100644 --- a/src/font/Collection.zig +++ b/src/font/Collection.zig @@ -1228,7 +1228,8 @@ test "metrics" { .overline_thickness = 1, .box_thickness = 1, .cursor_height = 17, - .icon_height = 12.24, + .icon_height = 16.784, + .icon_height_single = 12.24, .face_width = 8.0, .face_height = 16.784, .face_y = -0.04, @@ -1248,7 +1249,8 @@ test "metrics" { .overline_thickness = 2, .box_thickness = 2, .cursor_height = 34, - .icon_height = 24.48, + .icon_height = 33.568, + .icon_height_single = 24.48, .face_width = 16.0, .face_height = 33.568, .face_y = -0.08, diff --git a/src/font/Metrics.zig b/src/font/Metrics.zig index 668b6f15f..ec89763ea 100644 --- a/src/font/Metrics.zig +++ b/src/font/Metrics.zig @@ -38,6 +38,9 @@ cursor_height: u32, /// The constraint height for nerd fonts icons. icon_height: f64, +/// The constraint height for nerd fonts icons limited to a single cell width. +icon_height_single: f64, + /// The unrounded face width, used in scaling calculations. face_width: f64, @@ -60,6 +63,7 @@ const Minimums = struct { const cursor_thickness = 1; const cursor_height = 1; const icon_height = 1.0; + const icon_height_single = 1.0; const face_height = 1.0; const face_width = 1.0; }; @@ -251,8 +255,11 @@ pub fn calc(face: FaceMetrics) Metrics { const underline_position = @round(top_to_baseline - face.underlinePosition()); const strikethrough_position = @round(top_to_baseline - face.strikethroughPosition()); - // Same heuristic as the font_patcher script - const icon_height = (2 * cap_height + face_height) / 3; + // Same heuristic as the font_patcher script. We store icon_height + // separately from face_height such that modifiers can apply to the former + // without affecting the latter. + const icon_height = face_height; + const icon_height_single = (2 * cap_height + face_height) / 3; var result: Metrics = .{ .cell_width = @intFromFloat(cell_width), @@ -267,6 +274,7 @@ pub fn calc(face: FaceMetrics) Metrics { .box_thickness = @intFromFloat(underline_thickness), .cursor_height = @intFromFloat(cell_height), .icon_height = icon_height, + .icon_height_single = icon_height_single, .face_width = face_width, .face_height = face_height, .face_y = face_y, @@ -328,6 +336,10 @@ pub fn apply(self: *Metrics, mods: ModifierSet) void { } } }, + inline .icon_height => { + self.icon_height = entry.value_ptr.apply(self.icon_height); + self.icon_height_single = entry.value_ptr.apply(self.icon_height_single); + }, inline else => |tag| { @field(self, @tagName(tag)) = entry.value_ptr.apply(@field(self, @tagName(tag))); @@ -529,6 +541,7 @@ fn init() Metrics { .box_thickness = 0, .cursor_height = 0, .icon_height = 0.0, + .icon_height_single = 0.0, .face_width = 0.0, .face_height = 0.0, .face_y = 0.0, @@ -609,6 +622,48 @@ test "Metrics: adjust cell height larger" { try testing.expectEqual(@as(u32, 100), m.cursor_height); } +test "Metrics: adjust icon height by percentage" { + const testing = std.testing; + const alloc = testing.allocator; + + var set: ModifierSet = .{}; + defer set.deinit(alloc); + try set.put(alloc, .icon_height, .{ .percent = 0.75 }); + + var m: Metrics = init(); + m.icon_height = 100.0; + m.icon_height_single = 80.0; + m.face_height = 100.0; + m.face_y = 1.0; + m.apply(set); + try testing.expectEqual(75.0, m.icon_height); + try testing.expectEqual(60.0, m.icon_height_single); + // Face metrics not affected + try testing.expectEqual(100.0, m.face_height); + try testing.expectEqual(1.0, m.face_y); +} + +test "Metrics: adjust icon height by absolute pixels" { + const testing = std.testing; + const alloc = testing.allocator; + + var set: ModifierSet = .{}; + defer set.deinit(alloc); + try set.put(alloc, .icon_height, .{ .absolute = -5 }); + + var m: Metrics = init(); + m.icon_height = 100.0; + m.icon_height_single = 80.0; + m.face_height = 100.0; + m.face_y = 1.0; + m.apply(set); + try testing.expectEqual(95.0, m.icon_height); + try testing.expectEqual(75.0, m.icon_height_single); + // Face metrics not affected + try testing.expectEqual(100.0, m.face_height); + try testing.expectEqual(1.0, m.face_y); +} + test "Modifier: parse absolute" { const testing = std.testing; diff --git a/src/font/face.zig b/src/font/face.zig index 586de4ad6..a1312c45a 100644 --- a/src/font/face.zig +++ b/src/font/face.zig @@ -216,11 +216,13 @@ pub const RenderOptions = struct { }; pub const Height = enum { - /// Always use the full height of the cell for constraining this glyph. + /// Use the full line height of the primary face for + /// constraining this glyph. cell, - /// When the constraint width is 1, use the "icon height" from the grid - /// metrics as the height. (When the constraint width is >1, the - /// constraint height is always the full cell height.) + /// Use the icon height from the grid metrics for + /// constraining this glyph. Unlike `cell`, the value of + /// this height depends on both the constraint width and the + /// affected by the `adjust-icon-height` config option. icon, }; @@ -346,12 +348,14 @@ pub const RenderOptions = struct { const target_width = pad_width_factor * metrics.face_width; const target_height = pad_height_factor * switch (self.height) { .cell => metrics.face_height, - // icon_height only applies with single-cell constraints. - // This mirrors font_patcher. + // Like font-patcher, the icon constraint height depends on the + // constraint width. Unlike font-patcher, the multi-cell + // icon_height may be different from face_height due to the + // `adjust-icon-height` config option. .icon => if (multi_cell) - metrics.face_height + metrics.icon_height else - metrics.icon_height, + metrics.icon_height_single, }; var width_factor = target_width / group.width; @@ -528,7 +532,8 @@ test "Constraints" { .box_thickness = 1, .cursor_thickness = 1, .cursor_height = 22, - .icon_height = 44.48 / 3.0, + .icon_height = 21.12, + .icon_height_single = 44.48 / 3.0, .face_width = 9.6, .face_height = 21.12, .face_y = 0.2,