mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Merge pull request #2086 from ghostty-org/split
font/shaper: split text runs on common bad ligature pairs
This commit is contained in:
@ -698,6 +698,27 @@ test "run iterator" {
|
|||||||
while (try it.next(alloc)) |_| count += 1;
|
while (try it.next(alloc)) |_| count += 1;
|
||||||
try testing.expectEqual(@as(usize, 3), count);
|
try testing.expectEqual(@as(usize, 3), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bad ligatures
|
||||||
|
for (&[_][]const u8{ "fl", "fi", "st" }) |bad| {
|
||||||
|
// Make a screen with some data
|
||||||
|
var screen = try terminal.Screen.init(alloc, 5, 3, 0);
|
||||||
|
defer screen.deinit();
|
||||||
|
try screen.testWriteString(bad);
|
||||||
|
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(
|
||||||
|
testdata.grid,
|
||||||
|
&screen,
|
||||||
|
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |_| count += 1;
|
||||||
|
try testing.expectEqual(@as(usize, 2), count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "run iterator: empty cells with background set" {
|
test "run iterator: empty cells with background set" {
|
||||||
|
@ -104,6 +104,30 @@ pub const RunIterator = struct {
|
|||||||
if (j > self.i) style: {
|
if (j > self.i) style: {
|
||||||
const prev_cell = cells[j - 1];
|
const prev_cell = cells[j - 1];
|
||||||
|
|
||||||
|
// If the prev cell and this cell are both plain
|
||||||
|
// codepoints then we check if they are commonly "bad"
|
||||||
|
// ligatures and spit the run if they are.
|
||||||
|
if (prev_cell.content_tag == .codepoint and
|
||||||
|
cell.content_tag == .codepoint)
|
||||||
|
{
|
||||||
|
const prev_cp = prev_cell.codepoint();
|
||||||
|
switch (prev_cp) {
|
||||||
|
// fl, fi
|
||||||
|
'f' => {
|
||||||
|
const cp = cell.codepoint();
|
||||||
|
if (cp == 'l' or cp == 'i') break;
|
||||||
|
},
|
||||||
|
|
||||||
|
// st
|
||||||
|
's' => {
|
||||||
|
const cp = cell.codepoint();
|
||||||
|
if (cp == 't') break;
|
||||||
|
},
|
||||||
|
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the style is exactly the change then fast path out.
|
// If the style is exactly the change then fast path out.
|
||||||
if (prev_cell.style_id == cell.style_id) break :style;
|
if (prev_cell.style_id == cell.style_id) break :style;
|
||||||
|
|
||||||
|
@ -12,21 +12,18 @@ const font = @import("font/main.zig");
|
|||||||
|
|
||||||
/// If true, the default font features should be disabled for the given face.
|
/// If true, the default font features should be disabled for the given face.
|
||||||
pub fn disableDefaultFontFeatures(face: *const font.Face) bool {
|
pub fn disableDefaultFontFeatures(face: *const font.Face) bool {
|
||||||
var buf: [64]u8 = undefined;
|
_ = face;
|
||||||
const name = face.name(&buf) catch |err| switch (err) {
|
|
||||||
// If the name doesn't fit in buf we know this will be false
|
|
||||||
// because we have no quirks fonts that are longer than buf!
|
|
||||||
error.OutOfMemory => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// CodeNewRoman, Menlo and Monaco both have a default ligature of "fi" that
|
// This function used to do something, but we integrated the logic
|
||||||
// looks really bad in terminal grids, so we want to disable ligatures
|
// we checked for directly into our shaping algorithm. It's likely
|
||||||
// by default for these faces.
|
// there are other broken fonts for other reasons so I'm keeping this
|
||||||
//
|
// around so its easy to add more checks in the future.
|
||||||
// JuliaMono has a default ligature of "st" that looks bad.
|
return false;
|
||||||
return std.mem.eql(u8, name, "CodeNewRoman") or
|
|
||||||
std.mem.eql(u8, name, "CodeNewRoman Nerd Font") or
|
// var buf: [64]u8 = undefined;
|
||||||
std.mem.eql(u8, name, "JuliaMono") or
|
// const name = face.name(&buf) catch |err| switch (err) {
|
||||||
std.mem.eql(u8, name, "Menlo") or
|
// // If the name doesn't fit in buf we know this will be false
|
||||||
std.mem.eql(u8, name, "Monaco");
|
// // because we have no quirks fonts that are longer than buf!
|
||||||
|
// error.OutOfMemory => return false,
|
||||||
|
// };
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user