mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 07:46:12 +03:00
Merge branch 'main' into ssh-integration
This commit is contained in:
@ -396,6 +396,18 @@ pub const compatibility = std.StaticStringMap(
|
||||
/// Thickness in pixels or percentage adjustment of box drawing characters.
|
||||
/// See the notes about adjustments in `adjust-cell-width`.
|
||||
@"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.
|
||||
///
|
||||
/// The default value for the icon height is 1.2 times the height of capital
|
||||
/// letters in your primary font, so something like -16.6% would make icons
|
||||
/// roughly the same height as capital letters.
|
||||
///
|
||||
/// See the notes about adjustments in `adjust-cell-width`.
|
||||
@"adjust-icon-height": ?MetricModifier = null,
|
||||
|
||||
/// The method to use for calculating the cell width of a grapheme cluster.
|
||||
/// The default value is `unicode` which uses the Unicode standard to determine
|
||||
|
@ -1072,6 +1072,7 @@ test "metrics" {
|
||||
.overline_thickness = 1,
|
||||
.box_thickness = 1,
|
||||
.cursor_height = 17,
|
||||
.icon_height = 11,
|
||||
}, c.metrics);
|
||||
|
||||
// Resize should change metrics
|
||||
@ -1088,6 +1089,7 @@ test "metrics" {
|
||||
.overline_thickness = 2,
|
||||
.box_thickness = 2,
|
||||
.cursor_height = 34,
|
||||
.icon_height = 23,
|
||||
}, c.metrics);
|
||||
}
|
||||
|
||||
|
@ -35,9 +35,8 @@ cursor_thickness: u32 = 1,
|
||||
/// 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,
|
||||
/// The constraint height for nerd fonts icons.
|
||||
icon_height: u32,
|
||||
|
||||
/// Minimum acceptable values for some fields to prevent modifiers
|
||||
/// from being able to, for example, cause 0-thickness underlines.
|
||||
@ -50,6 +49,7 @@ const Minimums = struct {
|
||||
const box_thickness = 1;
|
||||
const cursor_thickness = 1;
|
||||
const cursor_height = 1;
|
||||
const icon_height = 1;
|
||||
};
|
||||
|
||||
/// Metrics extracted from a font face, based on
|
||||
@ -133,7 +133,7 @@ pub fn calc(face: FaceMetrics) Metrics {
|
||||
// that the cell is large enough for the provided size, since we cast
|
||||
// it to an integer later.
|
||||
const cell_width = @ceil(face.cell_width);
|
||||
const cell_height = @ceil(face.ascent - face.descent + face.line_gap);
|
||||
const cell_height = @ceil(face.lineHeight());
|
||||
|
||||
// We split our line gap in two parts, and put half of it on the top
|
||||
// of the cell and the other half on the bottom, so that our text never
|
||||
@ -177,6 +177,17 @@ pub fn calc(face: FaceMetrics) Metrics {
|
||||
(face.strikethrough_position orelse
|
||||
ex_height * 0.5 + strikethrough_thickness * 0.5));
|
||||
|
||||
// The calculation for icon height in the nerd fonts patcher
|
||||
// is two thirds cap height to one third line height, but we
|
||||
// use an opinionated default of 1.2 * cap height instead.
|
||||
//
|
||||
// Doing this prevents fonts with very large line heights
|
||||
// from having excessively oversized icons, and allows fonts
|
||||
// with very small line heights to still have roomy icons.
|
||||
//
|
||||
// We do cap it at `cell_height` though for obvious reasons.
|
||||
const icon_height = @min(cell_height, cap_height * 1.2);
|
||||
|
||||
var result: Metrics = .{
|
||||
.cell_width = @intFromFloat(cell_width),
|
||||
.cell_height = @intFromFloat(cell_height),
|
||||
@ -189,6 +200,7 @@ pub fn calc(face: FaceMetrics) Metrics {
|
||||
.overline_thickness = @intFromFloat(underline_thickness),
|
||||
.box_thickness = @intFromFloat(underline_thickness),
|
||||
.cursor_height = @intFromFloat(cell_height),
|
||||
.icon_height = @intFromFloat(icon_height),
|
||||
};
|
||||
|
||||
// Ensure all metrics are within their allowable range.
|
||||
@ -214,11 +226,6 @@ 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 if not set.
|
||||
if (self.original_cell_width == null) {
|
||||
self.original_cell_width = self.cell_width;
|
||||
}
|
||||
|
||||
// Set the new value
|
||||
@field(self, @tagName(tag)) = new;
|
||||
|
||||
@ -432,6 +439,7 @@ fn init() Metrics {
|
||||
.overline_thickness = 0,
|
||||
.box_thickness = 0,
|
||||
.cursor_height = 0,
|
||||
.icon_height = 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -449,6 +449,7 @@ pub const DerivedConfig = struct {
|
||||
@"adjust-cursor-thickness": ?Metrics.Modifier,
|
||||
@"adjust-cursor-height": ?Metrics.Modifier,
|
||||
@"adjust-box-thickness": ?Metrics.Modifier,
|
||||
@"adjust-icon-height": ?Metrics.Modifier,
|
||||
@"freetype-load-flags": font.face.FreetypeLoadFlags,
|
||||
|
||||
/// Initialize a DerivedConfig. The config should be either a
|
||||
@ -488,6 +489,7 @@ pub const DerivedConfig = struct {
|
||||
.@"adjust-cursor-thickness" = config.@"adjust-cursor-thickness",
|
||||
.@"adjust-cursor-height" = config.@"adjust-cursor-height",
|
||||
.@"adjust-box-thickness" = config.@"adjust-box-thickness",
|
||||
.@"adjust-icon-height" = config.@"adjust-icon-height",
|
||||
.@"freetype-load-flags" = if (font.face.FreetypeLoadFlags != void) config.@"freetype-load-flags" else {},
|
||||
|
||||
// This must be last so the arena contains all our allocations
|
||||
@ -634,6 +636,7 @@ pub const Key = struct {
|
||||
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);
|
||||
if (config.@"adjust-icon-height") |m| try set.put(alloc, .icon_height, m);
|
||||
break :set set;
|
||||
};
|
||||
|
||||
|
@ -150,6 +150,9 @@ pub const RenderOptions = struct {
|
||||
/// Maximum number of cells horizontally to use.
|
||||
max_constraint_width: u2 = 2,
|
||||
|
||||
/// What to use as the height metric when constraining the glyph.
|
||||
height: Height = .cell,
|
||||
|
||||
pub const Size = enum {
|
||||
/// Don't change the size of this glyph.
|
||||
none,
|
||||
@ -176,6 +179,13 @@ pub const RenderOptions = struct {
|
||||
center,
|
||||
};
|
||||
|
||||
pub const Height = enum {
|
||||
/// Use the full height of the cell for constraining this glyph.
|
||||
cell,
|
||||
/// Use the "icon height" from the grid metrics as the height.
|
||||
icon,
|
||||
};
|
||||
|
||||
/// The size and position of a glyph.
|
||||
pub const GlyphSize = struct {
|
||||
width: f64,
|
||||
@ -189,35 +199,35 @@ pub const RenderOptions = struct {
|
||||
pub fn constrain(
|
||||
self: Constraint,
|
||||
glyph: GlyphSize,
|
||||
/// Width of one cell.
|
||||
cell_width: f64,
|
||||
/// Height of one cell.
|
||||
cell_height: f64,
|
||||
metrics: Metrics,
|
||||
/// Number of cells horizontally available for this glyph.
|
||||
constraint_width: u2,
|
||||
) GlyphSize {
|
||||
var g = glyph;
|
||||
|
||||
const available_width =
|
||||
cell_width * @as(f64, @floatFromInt(
|
||||
@min(
|
||||
self.max_constraint_width,
|
||||
constraint_width,
|
||||
),
|
||||
));
|
||||
const available_width: f64 = @floatFromInt(
|
||||
metrics.cell_width * @min(
|
||||
self.max_constraint_width,
|
||||
constraint_width,
|
||||
),
|
||||
);
|
||||
const available_height: f64 = @floatFromInt(switch (self.height) {
|
||||
.cell => metrics.cell_height,
|
||||
.icon => metrics.icon_height,
|
||||
});
|
||||
|
||||
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;
|
||||
const h = available_height -
|
||||
self.pad_top * available_height -
|
||||
self.pad_bottom * available_height;
|
||||
|
||||
// Subtract padding from the bearings so that our
|
||||
// alignment and sizing code works correctly. We
|
||||
// re-add before returning.
|
||||
g.x -= self.pad_left * available_width;
|
||||
g.y -= self.pad_bottom * cell_height;
|
||||
g.y -= self.pad_bottom * available_height;
|
||||
|
||||
switch (self.size_horizontal) {
|
||||
.none => {},
|
||||
@ -319,7 +329,16 @@ pub const RenderOptions = struct {
|
||||
|
||||
// Re-add our padding before returning.
|
||||
g.x += self.pad_left * available_width;
|
||||
g.y += self.pad_bottom * cell_height;
|
||||
g.y += self.pad_bottom * available_height;
|
||||
|
||||
// If the available height is less than the cell height, we
|
||||
// add half of the difference to center it in the full height.
|
||||
//
|
||||
// If necessary, in the future, we can adjust this to account
|
||||
// for alignment, but that isn't necessary with any of the nf
|
||||
// icons afaict.
|
||||
const cell_height: f64 = @floatFromInt(metrics.cell_height);
|
||||
g.y += (cell_height - available_height) / 2;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
@ -341,7 +341,7 @@ pub const Face = struct {
|
||||
|
||||
const metrics = opts.grid_metrics;
|
||||
const cell_width: f64 = @floatFromInt(metrics.cell_width);
|
||||
const cell_height: f64 = @floatFromInt(metrics.cell_height);
|
||||
// const cell_height: f64 = @floatFromInt(metrics.cell_height);
|
||||
|
||||
const glyph_size = opts.constraint.constrain(
|
||||
.{
|
||||
@ -350,8 +350,7 @@ pub const Face = struct {
|
||||
.x = rect.origin.x,
|
||||
.y = rect.origin.y + @as(f64, @floatFromInt(metrics.cell_baseline)),
|
||||
},
|
||||
cell_width,
|
||||
cell_height,
|
||||
metrics,
|
||||
opts.constraint_width,
|
||||
);
|
||||
|
||||
|
@ -395,7 +395,7 @@ pub const Face = struct {
|
||||
const metrics = opts.grid_metrics;
|
||||
|
||||
const cell_width: f64 = @floatFromInt(metrics.cell_width);
|
||||
const cell_height: f64 = @floatFromInt(metrics.cell_height);
|
||||
// const cell_height: f64 = @floatFromInt(metrics.cell_height);
|
||||
|
||||
const glyph_x: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingX);
|
||||
const glyph_y: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingY) - glyph_height;
|
||||
@ -407,8 +407,7 @@ pub const Face = struct {
|
||||
.x = glyph_x,
|
||||
.y = glyph_y + @as(f64, @floatFromInt(metrics.cell_baseline)),
|
||||
},
|
||||
cell_width,
|
||||
cell_height,
|
||||
metrics,
|
||||
opts.constraint_width,
|
||||
);
|
||||
|
||||
@ -1058,6 +1057,7 @@ test "color emoji" {
|
||||
.overline_thickness = 0,
|
||||
.box_thickness = 0,
|
||||
.cursor_height = 0,
|
||||
.icon_height = 0,
|
||||
}, .constraint_width = 2, .constraint = .{
|
||||
.size_horizontal = .cover,
|
||||
.size_vertical = .cover,
|
||||
|
@ -25,6 +25,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
||||
=> .{
|
||||
.size_horizontal = .cover,
|
||||
.size_vertical = .fit,
|
||||
.height = .icon,
|
||||
.max_constraint_width = 1,
|
||||
.align_horizontal = .center,
|
||||
.align_vertical = .center,
|
||||
@ -285,7 +286,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
||||
0xe0d0...0xe0d1,
|
||||
=> .{
|
||||
.size_horizontal = .cover,
|
||||
.size_vertical = .cover,
|
||||
.size_vertical = .fit,
|
||||
.align_horizontal = .start,
|
||||
.align_vertical = .center,
|
||||
},
|
||||
@ -294,7 +295,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
||||
0xe0d5,
|
||||
=> .{
|
||||
.size_horizontal = .cover,
|
||||
.size_vertical = .cover,
|
||||
.size_vertical = .fit,
|
||||
.align_horizontal = .center,
|
||||
.align_vertical = .center,
|
||||
},
|
||||
@ -362,6 +363,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
||||
=> .{
|
||||
.size_horizontal = .fit,
|
||||
.size_vertical = .fit,
|
||||
.height = .icon,
|
||||
.align_horizontal = .center,
|
||||
.align_vertical = .center,
|
||||
},
|
||||
|
@ -180,16 +180,19 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry)
|
||||
if "xy" in stretch:
|
||||
s += " .size_horizontal = .stretch,\n"
|
||||
s += " .size_vertical = .stretch,\n"
|
||||
elif "!" in stretch:
|
||||
elif "!" in stretch or "^" in stretch:
|
||||
s += " .size_horizontal = .cover,\n"
|
||||
s += " .size_vertical = .fit,\n"
|
||||
elif "^" in stretch:
|
||||
s += " .size_horizontal = .cover,\n"
|
||||
s += " .size_vertical = .cover,\n"
|
||||
else:
|
||||
s += " .size_horizontal = .fit,\n"
|
||||
s += " .size_vertical = .fit,\n"
|
||||
|
||||
# `^` indicates that scaling should fill
|
||||
# the whole cell, not just the icon height.
|
||||
if "^" not in stretch:
|
||||
s += " .height = .icon,\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`.
|
||||
|
Reference in New Issue
Block a user