font: Apply `adjust-icon-height` to both large and small icons (#9160)
As pointed out in #9156, an unintended consequence of all the work to get icon sizing right is that `adjust-icon-height` now only applies to the small icons you get when the next cell is not whitespace. Large icons are unaffected. With this PR, `adjust-icon-height` affects the maximum height of every symbol specifying the `.icon` constraint height, regardless of constraint width. This includes most Nerd Font icons, but excludes emoji and other unicode symbols, and also excludes terminal graphics-oriented Nerd Font symbols such as Powerline symbols. In the following screenshots, **Baseline** is without `adjust-icon-height`, while **Before** and **After** are with `adjust-icon-height = -25%`. **Baseline** <img width="711" height="95" alt="Screenshot 2025-10-11 at 23 28 20" src="https://github.com/user-attachments/assets/7499db4d-75a4-4dbd-b107-8cb5849e31a3" /> **Before** (only small icons affected) <img width="711" height="95" alt="Screenshot 2025-10-11 at 23 20 12" src="https://github.com/user-attachments/assets/9afd9fbf-ef25-44cc-9d8e-c39a69875163" /> **After** (both small and large icons affected, but not emoji) <img width="711" height="95" alt="Screenshot 2025-10-11 at 23 21 05" src="https://github.com/user-attachments/assets/90999f59-3b43-4684-9c8e-2c3c1edd6d18" />pull/9168/head
parent
47a8f8083d
commit
65f73f5d20
|
|
@ -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`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue