mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Merge pull request #2154 from ghostty-org/synth
config: font-synthetic-style to enable/disable synthetic styles
This commit is contained in:
@ -14,6 +14,7 @@ pub const formatEntry = formatter.formatEntry;
|
|||||||
pub const ClipboardAccess = Config.ClipboardAccess;
|
pub const ClipboardAccess = Config.ClipboardAccess;
|
||||||
pub const CopyOnSelect = Config.CopyOnSelect;
|
pub const CopyOnSelect = Config.CopyOnSelect;
|
||||||
pub const CustomShaderAnimation = Config.CustomShaderAnimation;
|
pub const CustomShaderAnimation = Config.CustomShaderAnimation;
|
||||||
|
pub const FontSyntheticStyle = Config.FontSyntheticStyle;
|
||||||
pub const FontStyle = Config.FontStyle;
|
pub const FontStyle = Config.FontStyle;
|
||||||
pub const Keybinds = Config.Keybinds;
|
pub const Keybinds = Config.Keybinds;
|
||||||
pub const MouseShiftCapture = Config.MouseShiftCapture;
|
pub const MouseShiftCapture = Config.MouseShiftCapture;
|
||||||
|
@ -107,6 +107,38 @@ const c = @cImport({
|
|||||||
@"font-style-italic": FontStyle = .{ .default = {} },
|
@"font-style-italic": FontStyle = .{ .default = {} },
|
||||||
@"font-style-bold-italic": FontStyle = .{ .default = {} },
|
@"font-style-bold-italic": FontStyle = .{ .default = {} },
|
||||||
|
|
||||||
|
/// Control whether Ghostty should synthesize a style if the requested style is
|
||||||
|
/// not available in the specified font-family.
|
||||||
|
///
|
||||||
|
/// Ghostty can synthesize bold, italic, and bold italic styles if the font
|
||||||
|
/// does not have a specific style. For bold, this is done by drawing an
|
||||||
|
/// outline around the glyph of varying thickness. For italic, this is done by
|
||||||
|
/// applying a slant to the glyph. For bold italic, both of these are applied.
|
||||||
|
///
|
||||||
|
/// Synthetic styles are not perfect and will generally not look as good
|
||||||
|
/// as a font that has the style natively. However, they are useful to
|
||||||
|
/// provide styled text when the font does not have the style.
|
||||||
|
///
|
||||||
|
/// Set this to "false" or "true" to disable or enable synthetic styles
|
||||||
|
/// completely. You can disable specific styles using "no-bold", "no-italic",
|
||||||
|
/// and "no-bold-italic". You can disable multiple styles by separating them
|
||||||
|
/// with a comma. For example, "no-bold,no-italic".
|
||||||
|
///
|
||||||
|
/// Available style keys are: `bold`, `italic`, `bold-italic`.
|
||||||
|
///
|
||||||
|
/// If synthetic styles are disabled, then the regular style will be used
|
||||||
|
/// instead if the requested style is not available. If the font has the
|
||||||
|
/// requested style, then the font will be used as-is since the style is
|
||||||
|
/// not synthetic.
|
||||||
|
///
|
||||||
|
/// Warning! An easy mistake is to disable `bold` or `italic` but not
|
||||||
|
/// `bold-italic`. Disabling only `bold` or `italic` will NOT disable either
|
||||||
|
/// in the `bold-italic` style. If you want to disable `bold-italic`, you must
|
||||||
|
/// explicitly disable it. You cannot partially disable `bold-italic`.
|
||||||
|
///
|
||||||
|
/// By default, synthetic styles are enabled.
|
||||||
|
@"font-synthetic-style": FontSyntheticStyle = .{},
|
||||||
|
|
||||||
/// Apply a font feature. This can be repeated multiple times to enable multiple
|
/// Apply a font feature. This can be repeated multiple times to enable multiple
|
||||||
/// font features. You can NOT set multiple font features with a single value
|
/// font features. You can NOT set multiple font features with a single value
|
||||||
/// (yet).
|
/// (yet).
|
||||||
@ -3882,6 +3914,13 @@ pub const FontStyle = union(enum) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// See `font-synthetic-style` for documentation.
|
||||||
|
pub const FontSyntheticStyle = packed struct {
|
||||||
|
bold: bool = true,
|
||||||
|
italic: bool = true,
|
||||||
|
@"bold-italic": bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
/// See "link" for documentation.
|
/// See "link" for documentation.
|
||||||
pub const RepeatableLink = struct {
|
pub const RepeatableLink = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
@ -18,6 +18,7 @@ const Collection = @This();
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const config = @import("../config.zig");
|
||||||
const font = @import("main.zig");
|
const font = @import("main.zig");
|
||||||
const options = font.options;
|
const options = font.options;
|
||||||
const DeferredFace = font.DeferredFace;
|
const DeferredFace = font.DeferredFace;
|
||||||
@ -207,7 +208,11 @@ pub const CompleteError = Allocator.Error || error{
|
|||||||
/// This requires that a regular font face is already loaded.
|
/// This requires that a regular font face is already loaded.
|
||||||
/// This is asserted. If a font style is missing, we will synthesize
|
/// This is asserted. If a font style is missing, we will synthesize
|
||||||
/// it if possible. Otherwise, we will use the regular font style.
|
/// it if possible. Otherwise, we will use the regular font style.
|
||||||
pub fn completeStyles(self: *Collection, alloc: Allocator) CompleteError!void {
|
pub fn completeStyles(
|
||||||
|
self: *Collection,
|
||||||
|
alloc: Allocator,
|
||||||
|
synthetic_config: config.FontSyntheticStyle,
|
||||||
|
) CompleteError!void {
|
||||||
// If every style has at least one entry then we're done!
|
// If every style has at least one entry then we're done!
|
||||||
// This is the most common case.
|
// This is the most common case.
|
||||||
empty: {
|
empty: {
|
||||||
@ -262,6 +267,12 @@ pub fn completeStyles(self: *Collection, alloc: Allocator) CompleteError!void {
|
|||||||
const italic_list = self.faces.getPtr(.italic);
|
const italic_list = self.faces.getPtr(.italic);
|
||||||
const have_italic = italic_list.count() > 0;
|
const have_italic = italic_list.count() > 0;
|
||||||
if (!have_italic) italic: {
|
if (!have_italic) italic: {
|
||||||
|
if (!synthetic_config.italic) {
|
||||||
|
log.info("italic style not available and synthetic italic disabled", .{});
|
||||||
|
try italic_list.append(alloc, .{ .alias = regular_entry });
|
||||||
|
break :italic;
|
||||||
|
}
|
||||||
|
|
||||||
const synthetic = self.syntheticItalic(regular_entry) catch |err| {
|
const synthetic = self.syntheticItalic(regular_entry) catch |err| {
|
||||||
log.warn("failed to create synthetic italic, italic style will not be available err={}", .{err});
|
log.warn("failed to create synthetic italic, italic style will not be available err={}", .{err});
|
||||||
try italic_list.append(alloc, .{ .alias = regular_entry });
|
try italic_list.append(alloc, .{ .alias = regular_entry });
|
||||||
@ -276,6 +287,12 @@ pub fn completeStyles(self: *Collection, alloc: Allocator) CompleteError!void {
|
|||||||
const bold_list = self.faces.getPtr(.bold);
|
const bold_list = self.faces.getPtr(.bold);
|
||||||
const have_bold = bold_list.count() > 0;
|
const have_bold = bold_list.count() > 0;
|
||||||
if (!have_bold) bold: {
|
if (!have_bold) bold: {
|
||||||
|
if (!synthetic_config.bold) {
|
||||||
|
log.info("bold style not available and synthetic bold disabled", .{});
|
||||||
|
try bold_list.append(alloc, .{ .alias = regular_entry });
|
||||||
|
break :bold;
|
||||||
|
}
|
||||||
|
|
||||||
const synthetic = self.syntheticBold(regular_entry) catch |err| {
|
const synthetic = self.syntheticBold(regular_entry) catch |err| {
|
||||||
log.warn("failed to create synthetic bold, bold style will not be available err={}", .{err});
|
log.warn("failed to create synthetic bold, bold style will not be available err={}", .{err});
|
||||||
try bold_list.append(alloc, .{ .alias = regular_entry });
|
try bold_list.append(alloc, .{ .alias = regular_entry });
|
||||||
@ -290,6 +307,12 @@ pub fn completeStyles(self: *Collection, alloc: Allocator) CompleteError!void {
|
|||||||
// of the italic font. If we can't do that, we'll use the italic font.
|
// of the italic font. If we can't do that, we'll use the italic font.
|
||||||
const bold_italic_list = self.faces.getPtr(.bold_italic);
|
const bold_italic_list = self.faces.getPtr(.bold_italic);
|
||||||
if (bold_italic_list.count() == 0) bold_italic: {
|
if (bold_italic_list.count() == 0) bold_italic: {
|
||||||
|
if (!synthetic_config.@"bold-italic") {
|
||||||
|
log.info("bold italic style not available and synthetic bold italic disabled", .{});
|
||||||
|
try bold_italic_list.append(alloc, .{ .alias = regular_entry });
|
||||||
|
break :bold_italic;
|
||||||
|
}
|
||||||
|
|
||||||
// Prefer to synthesize on top of the face we already had. If we
|
// Prefer to synthesize on top of the face we already had. If we
|
||||||
// have bold then we try to synthesize italic on top of bold.
|
// have bold then we try to synthesize italic on top of bold.
|
||||||
if (have_bold) {
|
if (have_bold) {
|
||||||
@ -759,7 +782,7 @@ test completeStyles {
|
|||||||
try testing.expect(c.getIndex('A', .bold, .{ .any = {} }) == null);
|
try testing.expect(c.getIndex('A', .bold, .{ .any = {} }) == null);
|
||||||
try testing.expect(c.getIndex('A', .italic, .{ .any = {} }) == null);
|
try testing.expect(c.getIndex('A', .italic, .{ .any = {} }) == null);
|
||||||
try testing.expect(c.getIndex('A', .bold_italic, .{ .any = {} }) == null);
|
try testing.expect(c.getIndex('A', .bold_italic, .{ .any = {} }) == null);
|
||||||
try c.completeStyles(alloc);
|
try c.completeStyles(alloc, .{});
|
||||||
try testing.expect(c.getIndex('A', .bold, .{ .any = {} }) != null);
|
try testing.expect(c.getIndex('A', .bold, .{ .any = {} }) != null);
|
||||||
try testing.expect(c.getIndex('A', .italic, .{ .any = {} }) != null);
|
try testing.expect(c.getIndex('A', .italic, .{ .any = {} }) != null);
|
||||||
try testing.expect(c.getIndex('A', .bold_italic, .{ .any = {} }) != null);
|
try testing.expect(c.getIndex('A', .bold_italic, .{ .any = {} }) != null);
|
||||||
|
@ -128,7 +128,7 @@ pub fn ref(
|
|||||||
// Build our collection. This is the expensive operation that
|
// Build our collection. This is the expensive operation that
|
||||||
// involves finding fonts, loading them (maybe, some are deferred),
|
// involves finding fonts, loading them (maybe, some are deferred),
|
||||||
// etc.
|
// etc.
|
||||||
var c = try self.collection(&key, font_size);
|
var c = try self.collection(&key, font_size, config);
|
||||||
errdefer c.deinit(self.alloc);
|
errdefer c.deinit(self.alloc);
|
||||||
|
|
||||||
// Setup our enabled/disabled styles
|
// Setup our enabled/disabled styles
|
||||||
@ -156,6 +156,7 @@ fn collection(
|
|||||||
self: *SharedGridSet,
|
self: *SharedGridSet,
|
||||||
key: *const Key,
|
key: *const Key,
|
||||||
size: DesiredSize,
|
size: DesiredSize,
|
||||||
|
config: *const DerivedConfig,
|
||||||
) !Collection {
|
) !Collection {
|
||||||
// A quick note on memory management:
|
// A quick note on memory management:
|
||||||
// - font_lib is owned by the SharedGridSet
|
// - font_lib is owned by the SharedGridSet
|
||||||
@ -300,7 +301,7 @@ fn collection(
|
|||||||
|
|
||||||
// Complete our styles to ensure we have something to satisfy every
|
// Complete our styles to ensure we have something to satisfy every
|
||||||
// possible style request.
|
// possible style request.
|
||||||
try c.completeStyles(self.alloc);
|
try c.completeStyles(self.alloc, config.@"font-synthetic-style");
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -386,6 +387,7 @@ pub const DerivedConfig = struct {
|
|||||||
@"font-variation-italic": configpkg.RepeatableFontVariation,
|
@"font-variation-italic": configpkg.RepeatableFontVariation,
|
||||||
@"font-variation-bold-italic": configpkg.RepeatableFontVariation,
|
@"font-variation-bold-italic": configpkg.RepeatableFontVariation,
|
||||||
@"font-codepoint-map": configpkg.RepeatableCodepointMap,
|
@"font-codepoint-map": configpkg.RepeatableCodepointMap,
|
||||||
|
@"font-synthetic-style": configpkg.FontSyntheticStyle,
|
||||||
@"adjust-cell-width": ?Metrics.Modifier,
|
@"adjust-cell-width": ?Metrics.Modifier,
|
||||||
@"adjust-cell-height": ?Metrics.Modifier,
|
@"adjust-cell-height": ?Metrics.Modifier,
|
||||||
@"adjust-font-baseline": ?Metrics.Modifier,
|
@"adjust-font-baseline": ?Metrics.Modifier,
|
||||||
@ -416,6 +418,7 @@ pub const DerivedConfig = struct {
|
|||||||
.@"font-variation-italic" = try config.@"font-variation-italic".clone(alloc),
|
.@"font-variation-italic" = try config.@"font-variation-italic".clone(alloc),
|
||||||
.@"font-variation-bold-italic" = try config.@"font-variation-bold-italic".clone(alloc),
|
.@"font-variation-bold-italic" = try config.@"font-variation-bold-italic".clone(alloc),
|
||||||
.@"font-codepoint-map" = try config.@"font-codepoint-map".clone(alloc),
|
.@"font-codepoint-map" = try config.@"font-codepoint-map".clone(alloc),
|
||||||
|
.@"font-synthetic-style" = config.@"font-synthetic-style",
|
||||||
.@"adjust-cell-width" = config.@"adjust-cell-width",
|
.@"adjust-cell-width" = config.@"adjust-cell-width",
|
||||||
.@"adjust-cell-height" = config.@"adjust-cell-height",
|
.@"adjust-cell-height" = config.@"adjust-cell-height",
|
||||||
.@"adjust-font-baseline" = config.@"adjust-font-baseline",
|
.@"adjust-font-baseline" = config.@"adjust-font-baseline",
|
||||||
|
Reference in New Issue
Block a user