summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMitchell Hashimoto <m@mitchellh.com>2024-08-26 20:46:14 -0700
committerMitchell Hashimoto <m@mitchellh.com>2024-08-26 20:52:34 -0700
commitbdcc21942d0ab073248fbdfda79fc22cf69e0e9f (patch)
tree0eef7b70fafed81847f5a4fbd1da9ccc7b241f26 /src
parent80327402b8250d0bd13c34281e8540c31334257d (diff)
config: font-synthetic-style to enable/disable synthetic styles
This adds a new configuration "font-synthetic-style" to enable or disable synthetic styles. This is different from "font-style-*" which specifies a named style or disables a style completely. Instead, "font-synthetic-style" will disable only the creation of synthetic styles in the case a font does not support a given style. This is useful for users who want to obviously know when a font doesn't support a given style or a user who wants to explicitly only use the styles that were designed by the font designer. The default value is to enable all synthetic styles.
Diffstat (limited to 'src')
-rw-r--r--src/config.zig1
-rw-r--r--src/config/Config.zig39
-rw-r--r--src/font/Collection.zig27
-rw-r--r--src/font/SharedGridSet.zig7
4 files changed, 70 insertions, 4 deletions
diff --git a/src/config.zig b/src/config.zig
index 3be645cc3..082c842c9 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -14,6 +14,7 @@ pub const formatEntry = formatter.formatEntry;
pub const ClipboardAccess = Config.ClipboardAccess;
pub const CopyOnSelect = Config.CopyOnSelect;
pub const CustomShaderAnimation = Config.CustomShaderAnimation;
+pub const FontSyntheticStyle = Config.FontSyntheticStyle;
pub const FontStyle = Config.FontStyle;
pub const Keybinds = Config.Keybinds;
pub const MouseShiftCapture = Config.MouseShiftCapture;
diff --git a/src/config/Config.zig b/src/config/Config.zig
index 6a9e9b3b3..3d2f881df 100644
--- a/src/config/Config.zig
+++ b/src/config/Config.zig
@@ -107,6 +107,38 @@ const c = @cImport({
@"font-style-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
/// font features. You can NOT set multiple font features with a single value
/// (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.
pub const RepeatableLink = struct {
const Self = @This();
diff --git a/src/font/Collection.zig b/src/font/Collection.zig
index 842867930..4601a012e 100644
--- a/src/font/Collection.zig
+++ b/src/font/Collection.zig
@@ -18,6 +18,7 @@ const Collection = @This();
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
+const config = @import("../config.zig");
const font = @import("main.zig");
const options = font.options;
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 is asserted. If a font style is missing, we will synthesize
/// 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!
// This is the most common case.
empty: {
@@ -262,6 +267,12 @@ pub fn completeStyles(self: *Collection, alloc: Allocator) CompleteError!void {
const italic_list = self.faces.getPtr(.italic);
const have_italic = italic_list.count() > 0;
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| {
log.warn("failed to create synthetic italic, italic style will not be available err={}", .{err});
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 have_bold = bold_list.count() > 0;
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| {
log.warn("failed to create synthetic bold, bold style will not be available err={}", .{err});
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.
const bold_italic_list = self.faces.getPtr(.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
// have bold then we try to synthesize italic on top of 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', .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', .italic, .{ .any = {} }) != null);
try testing.expect(c.getIndex('A', .bold_italic, .{ .any = {} }) != null);
diff --git a/src/font/SharedGridSet.zig b/src/font/SharedGridSet.zig
index ef8feebc3..25d1f0410 100644
--- a/src/font/SharedGridSet.zig
+++ b/src/font/SharedGridSet.zig
@@ -128,7 +128,7 @@ pub fn ref(
// Build our collection. This is the expensive operation that
// involves finding fonts, loading them (maybe, some are deferred),
// etc.
- var c = try self.collection(&key, font_size);
+ var c = try self.collection(&key, font_size, config);
errdefer c.deinit(self.alloc);
// Setup our enabled/disabled styles
@@ -156,6 +156,7 @@ fn collection(
self: *SharedGridSet,
key: *const Key,
size: DesiredSize,
+ config: *const DerivedConfig,
) !Collection {
// A quick note on memory management:
// - font_lib is owned by the SharedGridSet
@@ -300,7 +301,7 @@ fn collection(
// Complete our styles to ensure we have something to satisfy every
// possible style request.
- try c.completeStyles(self.alloc);
+ try c.completeStyles(self.alloc, config.@"font-synthetic-style");
return c;
}
@@ -386,6 +387,7 @@ pub const DerivedConfig = struct {
@"font-variation-italic": configpkg.RepeatableFontVariation,
@"font-variation-bold-italic": configpkg.RepeatableFontVariation,
@"font-codepoint-map": configpkg.RepeatableCodepointMap,
+ @"font-synthetic-style": configpkg.FontSyntheticStyle,
@"adjust-cell-width": ?Metrics.Modifier,
@"adjust-cell-height": ?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-bold-italic" = try config.@"font-variation-bold-italic".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-height" = config.@"adjust-cell-height",
.@"adjust-font-baseline" = config.@"adjust-font-baseline",