Skip to content

Commit

Permalink
font: add cursor-height metric, and adjust- config for it. (#3062)
Browse files Browse the repository at this point in the history
Subsumes #2580 (which has multiple conflicts with main due to recent
changes to metrics); I figured it'd be easier to just implement it this
way.

#2580 claimed to solve #2487 but I don't think it really does- ideally
we can think of a good way to configure each individual cursor type, but
I don't wanna just do something ad hoc and add a bunch of config keys
blindly so I limited the scope of this.
  • Loading branch information
mitchellh authored Dec 22, 2024
2 parents eb7b056 + 3b6d8f3 commit 28c40f9
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 27 deletions.
12 changes: 7 additions & 5 deletions src/config/Config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,15 @@ const c = @cImport({
/// `-100%`) can cause the terminal to be unusable. Use with caution and reason.
///
/// Some values are clamped to minimum or maximum values. This can make it
/// appear that certain values are ignored. For example, the underline position
/// is clamped to the height of a cell. If you set the underline position so
/// high that it extends beyond the bottom of the cell size, it will be clamped
/// to the bottom of the cell.
/// appear that certain values are ignored. For example, many `*-thickness`
/// adjustments cannot go below 1px.
///
/// `adjust-cell-height` has some additional behaviors to describe:
///
/// * The font will be centered vertically in the cell.
///
/// * The cursor will remain the same size as the font.
/// * The cursor will remain the same size as the font, but may be
/// adjusted separately with `adjust-cursor-height`.
///
/// * Powerline glyphs will be adjusted along with the cell height so
/// that things like status lines continue to look aligned.
Expand All @@ -276,6 +275,9 @@ const c = @cImport({
@"adjust-overline-thickness": ?MetricModifier = null,
/// Thickness in pixels of the bar cursor and outlined rect cursor.
@"adjust-cursor-thickness": ?MetricModifier = null,
/// Height in pixels of the cursor. Currently applies to all cursor types:
/// bar, rect, and outlined rect.
@"adjust-cursor-height": ?MetricModifier = null,
/// Thickness in pixels of box drawing characters.
@"adjust-box-thickness": ?MetricModifier = null,

Expand Down
3 changes: 3 additions & 0 deletions src/font/SharedGridSet.zig
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ pub const DerivedConfig = struct {
@"adjust-overline-position": ?Metrics.Modifier,
@"adjust-overline-thickness": ?Metrics.Modifier,
@"adjust-cursor-thickness": ?Metrics.Modifier,
@"adjust-cursor-height": ?Metrics.Modifier,
@"adjust-box-thickness": ?Metrics.Modifier,
@"freetype-load-flags": font.face.FreetypeLoadFlags,

Expand Down Expand Up @@ -468,6 +469,7 @@ pub const DerivedConfig = struct {
.@"adjust-overline-position" = config.@"adjust-overline-position",
.@"adjust-overline-thickness" = config.@"adjust-overline-thickness",
.@"adjust-cursor-thickness" = config.@"adjust-cursor-thickness",
.@"adjust-cursor-height" = config.@"adjust-cursor-height",
.@"adjust-box-thickness" = config.@"adjust-box-thickness",
.@"freetype-load-flags" = if (font.face.FreetypeLoadFlags != void) config.@"freetype-load-flags" else {},

Expand Down Expand Up @@ -613,6 +615,7 @@ pub const Key = struct {
if (config.@"adjust-overline-position") |m| try set.put(alloc, .overline_position, m);
if (config.@"adjust-overline-thickness") |m| try set.put(alloc, .overline_thickness, m);
if (config.@"adjust-cursor-thickness") |m| try set.put(alloc, .cursor_thickness, m);
if (config.@"adjust-cursor-height") |m| try set.put(alloc, .cursor_height, m);
if (config.@"adjust-box-thickness") |m| try set.put(alloc, .box_thickness, m);
break :set set;
};
Expand Down
22 changes: 15 additions & 7 deletions src/font/face/Metrics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ box_thickness: u32,
/// because it is not determined by fonts but rather by user configuration.
cursor_thickness: u32 = 1,

/// Original cell width and height. These are used to render the cursor
/// in the original cell size after modification.
/// The height in pixels of the cursor sprite.
cursor_height: u32,

/// Original cell width in pixels. This is used to keep
/// glyphs centered if the cell width is adjusted wider.
original_cell_width: ?u32 = null,
original_cell_height: ?u32 = null,

/// Minimum acceptable values for some fields to prevent modifiers
/// from being able to, for example, cause 0-thickness underlines.
Expand All @@ -47,6 +49,7 @@ const Minimums = struct {
const overline_thickness = 1;
const box_thickness = 1;
const cursor_thickness = 1;
const cursor_height = 1;
};

const CalcOpts = struct {
Expand Down Expand Up @@ -167,6 +170,7 @@ pub fn calc(opts: CalcOpts) Metrics {
.overline_position = 0,
.overline_thickness = @intFromFloat(underline_thickness),
.box_thickness = @intFromFloat(underline_thickness),
.cursor_height = @intFromFloat(cell_height),
};

// Ensure all metrics are within their allowable range.
Expand All @@ -192,10 +196,9 @@ pub fn apply(self: *Metrics, mods: ModifierSet) void {
const new = @max(entry.value_ptr.apply(original), 1);
if (new == original) continue;

// Preserve the original cell width and height if not set.
// Preserve the original cell width if not set.
if (self.original_cell_width == null) {
self.original_cell_width = self.cell_width;
self.original_cell_height = self.cell_height;
}

// Set the new value
Expand Down Expand Up @@ -410,6 +413,7 @@ fn init() Metrics {
.overline_position = 0,
.overline_thickness = 0,
.box_thickness = 0,
.cursor_height = 0,
};
}

Expand Down Expand Up @@ -440,12 +444,14 @@ test "Metrics: adjust cell height smaller" {
m.underline_position = 55;
m.strikethrough_position = 30;
m.cell_height = 100;
m.cursor_height = 100;
m.apply(set);
try testing.expectEqual(@as(u32, 50), m.cell_height);
try testing.expectEqual(@as(u32, 25), m.cell_baseline);
try testing.expectEqual(@as(u32, 30), m.underline_position);
try testing.expectEqual(@as(u32, 5), m.strikethrough_position);
try testing.expectEqual(@as(u32, 100), m.original_cell_height.?);
// Cursor height is separate from cell height and does not follow it.
try testing.expectEqual(@as(u32, 100), m.cursor_height);
}

test "Metrics: adjust cell height larger" {
Expand All @@ -461,12 +467,14 @@ test "Metrics: adjust cell height larger" {
m.underline_position = 55;
m.strikethrough_position = 30;
m.cell_height = 100;
m.cursor_height = 100;
m.apply(set);
try testing.expectEqual(@as(u32, 200), m.cell_height);
try testing.expectEqual(@as(u32, 100), m.cell_baseline);
try testing.expectEqual(@as(u32, 105), m.underline_position);
try testing.expectEqual(@as(u32, 80), m.strikethrough_position);
try testing.expectEqual(@as(u32, 100), m.original_cell_height.?);
// Cursor height is separate from cell height and does not follow it.
try testing.expectEqual(@as(u32, 100), m.cursor_height);
}

test "Modifier: parse absolute" {
Expand Down
2 changes: 2 additions & 0 deletions src/font/face/coretext.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,7 @@ test "coretext: metrics" {
.overline_position = 0,
.overline_thickness = 1,
.box_thickness = 1,
.cursor_height = 17,
}, ct_font.metrics);

// Resize should change metrics
Expand All @@ -1060,5 +1061,6 @@ test "coretext: metrics" {
.overline_position = 0,
.overline_thickness = 2,
.box_thickness = 2,
.cursor_height = 34,
}, ct_font.metrics);
}
3 changes: 3 additions & 0 deletions src/font/face/freetype.zig
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,7 @@ test "color emoji" {
.overline_position = 0,
.overline_thickness = 0,
.box_thickness = 0,
.cursor_height = 0,
},
});
try testing.expectEqual(@as(u32, 24), glyph.height);
Expand Down Expand Up @@ -952,6 +953,7 @@ test "metrics" {
.overline_position = 0,
.overline_thickness = 1,
.box_thickness = 1,
.cursor_height = 17,
}, ft_font.metrics);

// Resize should change metrics
Expand All @@ -967,6 +969,7 @@ test "metrics" {
.overline_position = 0,
.overline_thickness = 2,
.box_thickness = 2,
.cursor_height = 34,
}, ft_font.metrics);
}

Expand Down
21 changes: 6 additions & 15 deletions src/font/sprite/Face.zig
Original file line number Diff line number Diff line change
Expand Up @@ -126,29 +126,20 @@ pub fn renderGlyph(
},

.cursor => cursor: {
// Cursors should be drawn with the original cell height if
// it has been adjusted larger, so they don't get stretched.
const height, const dy = adjust: {
const h = metrics.cell_height;
if (metrics.original_cell_height) |original| {
if (h > original) {
break :adjust .{ original, (h - original) / 2 };
}
}
break :adjust .{ h, 0 };
};

var g = try cursor.renderGlyph(
alloc,
atlas,
@enumFromInt(cp),
width,
height,
metrics.cursor_height,
metrics.cursor_thickness,
);

// Keep the cursor centered in the cell if it's shorter.
g.offset_y += @intCast(dy);
// Cursors are drawn at their specified height
// and are centered vertically within the cell.
const cursor_height: i32 = @intCast(metrics.cursor_height);
const cell_height: i32 = @intCast(metrics.cell_height);
g.offset_y += @divTrunc(cell_height - cursor_height, 2);

break :cursor g;
},
Expand Down

0 comments on commit 28c40f9

Please sign in to comment.