mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +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.
|
/// Thickness in pixels or percentage adjustment of box drawing characters.
|
||||||
/// See the notes about adjustments in `adjust-cell-width`.
|
/// See the notes about adjustments in `adjust-cell-width`.
|
||||||
@"adjust-box-thickness": ?MetricModifier = null,
|
@"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 method to use for calculating the cell width of a grapheme cluster.
|
||||||
/// The default value is `unicode` which uses the Unicode standard to determine
|
/// The default value is `unicode` which uses the Unicode standard to determine
|
||||||
|
@ -1072,6 +1072,7 @@ test "metrics" {
|
|||||||
.overline_thickness = 1,
|
.overline_thickness = 1,
|
||||||
.box_thickness = 1,
|
.box_thickness = 1,
|
||||||
.cursor_height = 17,
|
.cursor_height = 17,
|
||||||
|
.icon_height = 11,
|
||||||
}, c.metrics);
|
}, c.metrics);
|
||||||
|
|
||||||
// Resize should change metrics
|
// Resize should change metrics
|
||||||
@ -1088,6 +1089,7 @@ test "metrics" {
|
|||||||
.overline_thickness = 2,
|
.overline_thickness = 2,
|
||||||
.box_thickness = 2,
|
.box_thickness = 2,
|
||||||
.cursor_height = 34,
|
.cursor_height = 34,
|
||||||
|
.icon_height = 23,
|
||||||
}, c.metrics);
|
}, c.metrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +35,8 @@ cursor_thickness: u32 = 1,
|
|||||||
/// The height in pixels of the cursor sprite.
|
/// The height in pixels of the cursor sprite.
|
||||||
cursor_height: u32,
|
cursor_height: u32,
|
||||||
|
|
||||||
/// Original cell width in pixels. This is used to keep
|
/// The constraint height for nerd fonts icons.
|
||||||
/// glyphs centered if the cell width is adjusted wider.
|
icon_height: u32,
|
||||||
original_cell_width: ?u32 = null,
|
|
||||||
|
|
||||||
/// Minimum acceptable values for some fields to prevent modifiers
|
/// Minimum acceptable values for some fields to prevent modifiers
|
||||||
/// from being able to, for example, cause 0-thickness underlines.
|
/// from being able to, for example, cause 0-thickness underlines.
|
||||||
@ -50,6 +49,7 @@ const Minimums = struct {
|
|||||||
const box_thickness = 1;
|
const box_thickness = 1;
|
||||||
const cursor_thickness = 1;
|
const cursor_thickness = 1;
|
||||||
const cursor_height = 1;
|
const cursor_height = 1;
|
||||||
|
const icon_height = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Metrics extracted from a font face, based on
|
/// 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
|
// that the cell is large enough for the provided size, since we cast
|
||||||
// it to an integer later.
|
// it to an integer later.
|
||||||
const cell_width = @ceil(face.cell_width);
|
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
|
// 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
|
// 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
|
(face.strikethrough_position orelse
|
||||||
ex_height * 0.5 + strikethrough_thickness * 0.5));
|
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 = .{
|
var result: Metrics = .{
|
||||||
.cell_width = @intFromFloat(cell_width),
|
.cell_width = @intFromFloat(cell_width),
|
||||||
.cell_height = @intFromFloat(cell_height),
|
.cell_height = @intFromFloat(cell_height),
|
||||||
@ -189,6 +200,7 @@ pub fn calc(face: FaceMetrics) Metrics {
|
|||||||
.overline_thickness = @intFromFloat(underline_thickness),
|
.overline_thickness = @intFromFloat(underline_thickness),
|
||||||
.box_thickness = @intFromFloat(underline_thickness),
|
.box_thickness = @intFromFloat(underline_thickness),
|
||||||
.cursor_height = @intFromFloat(cell_height),
|
.cursor_height = @intFromFloat(cell_height),
|
||||||
|
.icon_height = @intFromFloat(icon_height),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure all metrics are within their allowable range.
|
// 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);
|
const new = @max(entry.value_ptr.apply(original), 1);
|
||||||
if (new == original) continue;
|
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
|
// Set the new value
|
||||||
@field(self, @tagName(tag)) = new;
|
@field(self, @tagName(tag)) = new;
|
||||||
|
|
||||||
@ -432,6 +439,7 @@ fn init() Metrics {
|
|||||||
.overline_thickness = 0,
|
.overline_thickness = 0,
|
||||||
.box_thickness = 0,
|
.box_thickness = 0,
|
||||||
.cursor_height = 0,
|
.cursor_height = 0,
|
||||||
|
.icon_height = 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,6 +449,7 @@ pub const DerivedConfig = struct {
|
|||||||
@"adjust-cursor-thickness": ?Metrics.Modifier,
|
@"adjust-cursor-thickness": ?Metrics.Modifier,
|
||||||
@"adjust-cursor-height": ?Metrics.Modifier,
|
@"adjust-cursor-height": ?Metrics.Modifier,
|
||||||
@"adjust-box-thickness": ?Metrics.Modifier,
|
@"adjust-box-thickness": ?Metrics.Modifier,
|
||||||
|
@"adjust-icon-height": ?Metrics.Modifier,
|
||||||
@"freetype-load-flags": font.face.FreetypeLoadFlags,
|
@"freetype-load-flags": font.face.FreetypeLoadFlags,
|
||||||
|
|
||||||
/// Initialize a DerivedConfig. The config should be either a
|
/// 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-thickness" = config.@"adjust-cursor-thickness",
|
||||||
.@"adjust-cursor-height" = config.@"adjust-cursor-height",
|
.@"adjust-cursor-height" = config.@"adjust-cursor-height",
|
||||||
.@"adjust-box-thickness" = config.@"adjust-box-thickness",
|
.@"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 {},
|
.@"freetype-load-flags" = if (font.face.FreetypeLoadFlags != void) config.@"freetype-load-flags" else {},
|
||||||
|
|
||||||
// This must be last so the arena contains all our allocations
|
// 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-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-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-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;
|
break :set set;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,6 +150,9 @@ pub const RenderOptions = struct {
|
|||||||
/// Maximum number of cells horizontally to use.
|
/// Maximum number of cells horizontally to use.
|
||||||
max_constraint_width: u2 = 2,
|
max_constraint_width: u2 = 2,
|
||||||
|
|
||||||
|
/// What to use as the height metric when constraining the glyph.
|
||||||
|
height: Height = .cell,
|
||||||
|
|
||||||
pub const Size = enum {
|
pub const Size = enum {
|
||||||
/// Don't change the size of this glyph.
|
/// Don't change the size of this glyph.
|
||||||
none,
|
none,
|
||||||
@ -176,6 +179,13 @@ pub const RenderOptions = struct {
|
|||||||
center,
|
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.
|
/// The size and position of a glyph.
|
||||||
pub const GlyphSize = struct {
|
pub const GlyphSize = struct {
|
||||||
width: f64,
|
width: f64,
|
||||||
@ -189,35 +199,35 @@ pub const RenderOptions = struct {
|
|||||||
pub fn constrain(
|
pub fn constrain(
|
||||||
self: Constraint,
|
self: Constraint,
|
||||||
glyph: GlyphSize,
|
glyph: GlyphSize,
|
||||||
/// Width of one cell.
|
metrics: Metrics,
|
||||||
cell_width: f64,
|
|
||||||
/// Height of one cell.
|
|
||||||
cell_height: f64,
|
|
||||||
/// Number of cells horizontally available for this glyph.
|
/// Number of cells horizontally available for this glyph.
|
||||||
constraint_width: u2,
|
constraint_width: u2,
|
||||||
) GlyphSize {
|
) GlyphSize {
|
||||||
var g = glyph;
|
var g = glyph;
|
||||||
|
|
||||||
const available_width =
|
const available_width: f64 = @floatFromInt(
|
||||||
cell_width * @as(f64, @floatFromInt(
|
metrics.cell_width * @min(
|
||||||
@min(
|
|
||||||
self.max_constraint_width,
|
self.max_constraint_width,
|
||||||
constraint_width,
|
constraint_width,
|
||||||
),
|
),
|
||||||
));
|
);
|
||||||
|
const available_height: f64 = @floatFromInt(switch (self.height) {
|
||||||
|
.cell => metrics.cell_height,
|
||||||
|
.icon => metrics.icon_height,
|
||||||
|
});
|
||||||
|
|
||||||
const w = available_width -
|
const w = available_width -
|
||||||
self.pad_left * available_width -
|
self.pad_left * available_width -
|
||||||
self.pad_right * available_width;
|
self.pad_right * available_width;
|
||||||
const h = cell_height -
|
const h = available_height -
|
||||||
self.pad_top * cell_height -
|
self.pad_top * available_height -
|
||||||
self.pad_bottom * cell_height;
|
self.pad_bottom * available_height;
|
||||||
|
|
||||||
// Subtract padding from the bearings so that our
|
// Subtract padding from the bearings so that our
|
||||||
// alignment and sizing code works correctly. We
|
// alignment and sizing code works correctly. We
|
||||||
// re-add before returning.
|
// re-add before returning.
|
||||||
g.x -= self.pad_left * available_width;
|
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) {
|
switch (self.size_horizontal) {
|
||||||
.none => {},
|
.none => {},
|
||||||
@ -319,7 +329,16 @@ pub const RenderOptions = struct {
|
|||||||
|
|
||||||
// Re-add our padding before returning.
|
// Re-add our padding before returning.
|
||||||
g.x += self.pad_left * available_width;
|
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;
|
return g;
|
||||||
}
|
}
|
||||||
|
@ -341,7 +341,7 @@ pub const Face = struct {
|
|||||||
|
|
||||||
const metrics = opts.grid_metrics;
|
const metrics = opts.grid_metrics;
|
||||||
const cell_width: f64 = @floatFromInt(metrics.cell_width);
|
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(
|
const glyph_size = opts.constraint.constrain(
|
||||||
.{
|
.{
|
||||||
@ -350,8 +350,7 @@ pub const Face = struct {
|
|||||||
.x = rect.origin.x,
|
.x = rect.origin.x,
|
||||||
.y = rect.origin.y + @as(f64, @floatFromInt(metrics.cell_baseline)),
|
.y = rect.origin.y + @as(f64, @floatFromInt(metrics.cell_baseline)),
|
||||||
},
|
},
|
||||||
cell_width,
|
metrics,
|
||||||
cell_height,
|
|
||||||
opts.constraint_width,
|
opts.constraint_width,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ pub const Face = struct {
|
|||||||
const metrics = opts.grid_metrics;
|
const metrics = opts.grid_metrics;
|
||||||
|
|
||||||
const cell_width: f64 = @floatFromInt(metrics.cell_width);
|
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_x: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingX);
|
||||||
const glyph_y: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingY) - glyph_height;
|
const glyph_y: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingY) - glyph_height;
|
||||||
@ -407,8 +407,7 @@ pub const Face = struct {
|
|||||||
.x = glyph_x,
|
.x = glyph_x,
|
||||||
.y = glyph_y + @as(f64, @floatFromInt(metrics.cell_baseline)),
|
.y = glyph_y + @as(f64, @floatFromInt(metrics.cell_baseline)),
|
||||||
},
|
},
|
||||||
cell_width,
|
metrics,
|
||||||
cell_height,
|
|
||||||
opts.constraint_width,
|
opts.constraint_width,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1058,6 +1057,7 @@ test "color emoji" {
|
|||||||
.overline_thickness = 0,
|
.overline_thickness = 0,
|
||||||
.box_thickness = 0,
|
.box_thickness = 0,
|
||||||
.cursor_height = 0,
|
.cursor_height = 0,
|
||||||
|
.icon_height = 0,
|
||||||
}, .constraint_width = 2, .constraint = .{
|
}, .constraint_width = 2, .constraint = .{
|
||||||
.size_horizontal = .cover,
|
.size_horizontal = .cover,
|
||||||
.size_vertical = .cover,
|
.size_vertical = .cover,
|
||||||
|
@ -25,6 +25,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
|||||||
=> .{
|
=> .{
|
||||||
.size_horizontal = .cover,
|
.size_horizontal = .cover,
|
||||||
.size_vertical = .fit,
|
.size_vertical = .fit,
|
||||||
|
.height = .icon,
|
||||||
.max_constraint_width = 1,
|
.max_constraint_width = 1,
|
||||||
.align_horizontal = .center,
|
.align_horizontal = .center,
|
||||||
.align_vertical = .center,
|
.align_vertical = .center,
|
||||||
@ -285,7 +286,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
|||||||
0xe0d0...0xe0d1,
|
0xe0d0...0xe0d1,
|
||||||
=> .{
|
=> .{
|
||||||
.size_horizontal = .cover,
|
.size_horizontal = .cover,
|
||||||
.size_vertical = .cover,
|
.size_vertical = .fit,
|
||||||
.align_horizontal = .start,
|
.align_horizontal = .start,
|
||||||
.align_vertical = .center,
|
.align_vertical = .center,
|
||||||
},
|
},
|
||||||
@ -294,7 +295,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
|||||||
0xe0d5,
|
0xe0d5,
|
||||||
=> .{
|
=> .{
|
||||||
.size_horizontal = .cover,
|
.size_horizontal = .cover,
|
||||||
.size_vertical = .cover,
|
.size_vertical = .fit,
|
||||||
.align_horizontal = .center,
|
.align_horizontal = .center,
|
||||||
.align_vertical = .center,
|
.align_vertical = .center,
|
||||||
},
|
},
|
||||||
@ -362,6 +363,7 @@ pub fn getConstraint(cp: u21) Constraint {
|
|||||||
=> .{
|
=> .{
|
||||||
.size_horizontal = .fit,
|
.size_horizontal = .fit,
|
||||||
.size_vertical = .fit,
|
.size_vertical = .fit,
|
||||||
|
.height = .icon,
|
||||||
.align_horizontal = .center,
|
.align_horizontal = .center,
|
||||||
.align_vertical = .center,
|
.align_vertical = .center,
|
||||||
},
|
},
|
||||||
|
@ -180,16 +180,19 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry)
|
|||||||
if "xy" in stretch:
|
if "xy" in stretch:
|
||||||
s += " .size_horizontal = .stretch,\n"
|
s += " .size_horizontal = .stretch,\n"
|
||||||
s += " .size_vertical = .stretch,\n"
|
s += " .size_vertical = .stretch,\n"
|
||||||
elif "!" in stretch:
|
elif "!" in stretch or "^" in stretch:
|
||||||
s += " .size_horizontal = .cover,\n"
|
s += " .size_horizontal = .cover,\n"
|
||||||
s += " .size_vertical = .fit,\n"
|
s += " .size_vertical = .fit,\n"
|
||||||
elif "^" in stretch:
|
|
||||||
s += " .size_horizontal = .cover,\n"
|
|
||||||
s += " .size_vertical = .cover,\n"
|
|
||||||
else:
|
else:
|
||||||
s += " .size_horizontal = .fit,\n"
|
s += " .size_horizontal = .fit,\n"
|
||||||
s += " .size_vertical = .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:
|
# 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 there's a `1` in the stretch mode string.
|
||||||
# - If the stretch mode is `xy` and there's not an explicit `2`.
|
# - If the stretch mode is `xy` and there's not an explicit `2`.
|
||||||
|
Reference in New Issue
Block a user