Introduce `font-shaping-break` config option (#5374)
Adds the config option as described in #4515. Plumbed it into the `RunIterator` and updated all the tests that rely on that, adding additional cases to the cursor boundary tests where I found them. Closes #4515pull/4422/head
commit
ffcd633c01
|
|
@ -20,6 +20,7 @@ pub const ConfirmCloseSurface = Config.ConfirmCloseSurface;
|
||||||
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 FontSyntheticStyle = Config.FontSyntheticStyle;
|
||||||
|
pub const FontShapingBreak = Config.FontShapingBreak;
|
||||||
pub const FontStyle = Config.FontStyle;
|
pub const FontStyle = Config.FontStyle;
|
||||||
pub const FreetypeLoadFlags = Config.FreetypeLoadFlags;
|
pub const FreetypeLoadFlags = Config.FreetypeLoadFlags;
|
||||||
pub const Keybinds = Config.Keybinds;
|
pub const Keybinds = Config.Keybinds;
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,32 @@ pub const compatibility = std.StaticStringMap(
|
||||||
/// This is currently only supported on macOS.
|
/// This is currently only supported on macOS.
|
||||||
@"font-thicken-strength": u8 = 255,
|
@"font-thicken-strength": u8 = 255,
|
||||||
|
|
||||||
|
/// Locations to break font shaping into multiple runs.
|
||||||
|
///
|
||||||
|
/// A "run" is a contiguous segment of text that is shaped together. "Shaping"
|
||||||
|
/// is the process of converting text (codepoints) into glyphs (renderable
|
||||||
|
/// characters). This is how ligatures are formed, among other things.
|
||||||
|
/// For example, if a coding font turns "!=" into a single glyph, then it
|
||||||
|
/// must see "!" and "=" next to each other in a single run. When a run
|
||||||
|
/// is broken, the text is shaped separately. To continue our example, if
|
||||||
|
/// "!" is at the end of one run and "=" is at the start of the next run,
|
||||||
|
/// then the ligature will not be formed.
|
||||||
|
///
|
||||||
|
/// Ghostty breaks runs at certain points to improve readability or usability.
|
||||||
|
/// For example, Ghostty by default will break runs under the cursor so that
|
||||||
|
/// text editing can see the individual characters rather than a ligature.
|
||||||
|
/// This configuration lets you configure this behavior.
|
||||||
|
///
|
||||||
|
/// Combine values with a comma to set multiple options. Prefix an
|
||||||
|
/// option with "no-" to disable it. Enabling and disabling options
|
||||||
|
/// can be done at the same time.
|
||||||
|
///
|
||||||
|
/// Available options:
|
||||||
|
///
|
||||||
|
/// * `cursor` - Break runs under the cursor.
|
||||||
|
///
|
||||||
|
@"font-shaping-break": FontShapingBreak = .{},
|
||||||
|
|
||||||
/// What color space to use when performing alpha blending.
|
/// What color space to use when performing alpha blending.
|
||||||
///
|
///
|
||||||
/// This affects the appearance of text and of any images with transparency.
|
/// This affects the appearance of text and of any images with transparency.
|
||||||
|
|
@ -6214,6 +6240,11 @@ pub const FontSyntheticStyle = packed struct {
|
||||||
@"bold-italic": bool = true,
|
@"bold-italic": bool = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// See "font-shaping-break" for documentation
|
||||||
|
pub const FontShapingBreak = packed struct {
|
||||||
|
cursor: bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
/// See "link" for documentation.
|
/// See "link" for documentation.
|
||||||
pub const RepeatableLink = struct {
|
pub const RepeatableLink = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ const builtin = @import("builtin");
|
||||||
const options = @import("main.zig").options;
|
const options = @import("main.zig").options;
|
||||||
const run = @import("shaper/run.zig");
|
const run = @import("shaper/run.zig");
|
||||||
const feature = @import("shaper/feature.zig");
|
const feature = @import("shaper/feature.zig");
|
||||||
|
const configpkg = @import("../config.zig");
|
||||||
|
const terminal = @import("../terminal/main.zig");
|
||||||
|
const SharedGrid = @import("main.zig").SharedGrid;
|
||||||
pub const noop = @import("shaper/noop.zig");
|
pub const noop = @import("shaper/noop.zig");
|
||||||
pub const harfbuzz = @import("shaper/harfbuzz.zig");
|
pub const harfbuzz = @import("shaper/harfbuzz.zig");
|
||||||
pub const coretext = @import("shaper/coretext.zig");
|
pub const coretext = @import("shaper/coretext.zig");
|
||||||
|
|
@ -61,6 +64,38 @@ pub const Options = struct {
|
||||||
features: []const []const u8 = &.{},
|
features: []const []const u8 = &.{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Options for runIterator.
|
||||||
|
pub const RunOptions = struct {
|
||||||
|
/// The font state for the terminal screen. This is mutable because
|
||||||
|
/// cached values may be updated during shaping.
|
||||||
|
grid: *SharedGrid,
|
||||||
|
|
||||||
|
/// The terminal screen to shape.
|
||||||
|
screen: *const terminal.Screen,
|
||||||
|
|
||||||
|
/// The row within the screen to shape. This row must exist within
|
||||||
|
/// screen; it is not validated.
|
||||||
|
row: terminal.Pin,
|
||||||
|
|
||||||
|
/// The selection boundaries. This is used to break shaping on
|
||||||
|
/// selection boundaries. This can be disabled by setting this to
|
||||||
|
/// null.
|
||||||
|
selection: ?terminal.Selection = null,
|
||||||
|
|
||||||
|
/// The cursor position within this row. This is used to break shaping
|
||||||
|
/// on cursor boundaries. This can be disabled by setting this to
|
||||||
|
/// null.
|
||||||
|
cursor_x: ?usize = null,
|
||||||
|
|
||||||
|
/// Apply the font break configuration to the run.
|
||||||
|
pub fn applyBreakConfig(
|
||||||
|
self: *RunOptions,
|
||||||
|
config: configpkg.FontShapingBreak,
|
||||||
|
) void {
|
||||||
|
if (!config.cursor) self.cursor_x = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = Cache;
|
_ = Cache;
|
||||||
_ = Shaper;
|
_ = Shaper;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ const trace = @import("tracy").trace;
|
||||||
const font = @import("../main.zig");
|
const font = @import("../main.zig");
|
||||||
const os = @import("../../os/main.zig");
|
const os = @import("../../os/main.zig");
|
||||||
const terminal = @import("../../terminal/main.zig");
|
const terminal = @import("../../terminal/main.zig");
|
||||||
|
const config = @import("../../config.zig");
|
||||||
const Feature = font.shape.Feature;
|
const Feature = font.shape.Feature;
|
||||||
const FeatureList = font.shape.FeatureList;
|
const FeatureList = font.shape.FeatureList;
|
||||||
const default_features = font.shape.default_features;
|
const default_features = font.shape.default_features;
|
||||||
|
|
@ -288,19 +289,11 @@ pub const Shaper = struct {
|
||||||
|
|
||||||
pub fn runIterator(
|
pub fn runIterator(
|
||||||
self: *Shaper,
|
self: *Shaper,
|
||||||
grid: *SharedGrid,
|
opts: font.shape.RunOptions,
|
||||||
screen: *const terminal.Screen,
|
|
||||||
row: terminal.Pin,
|
|
||||||
selection: ?terminal.Selection,
|
|
||||||
cursor_x: ?usize,
|
|
||||||
) font.shape.RunIterator {
|
) font.shape.RunIterator {
|
||||||
return .{
|
return .{
|
||||||
.hooks = .{ .shaper = self },
|
.hooks = .{ .shaper = self },
|
||||||
.grid = grid,
|
.opts = opts,
|
||||||
.screen = screen,
|
|
||||||
.row = row,
|
|
||||||
.selection = selection,
|
|
||||||
.cursor_x = cursor_x,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -594,13 +587,11 @@ test "run iterator" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |_| count += 1;
|
while (try it.next(alloc)) |_| count += 1;
|
||||||
try testing.expectEqual(@as(usize, 1), count);
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
|
@ -613,13 +604,11 @@ test "run iterator" {
|
||||||
try screen.testWriteString("ABCD EFG");
|
try screen.testWriteString("ABCD EFG");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |_| count += 1;
|
while (try it.next(alloc)) |_| count += 1;
|
||||||
try testing.expectEqual(@as(usize, 1), count);
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
|
@ -633,13 +622,11 @@ test "run iterator" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
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);
|
||||||
|
|
@ -654,13 +641,11 @@ test "run iterator" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |_| count += 1;
|
while (try it.next(alloc)) |_| count += 1;
|
||||||
try testing.expectEqual(@as(usize, 2), count);
|
try testing.expectEqual(@as(usize, 2), count);
|
||||||
|
|
@ -701,13 +686,11 @@ test "run iterator: empty cells with background set" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
{
|
{
|
||||||
const run = (try it.next(alloc)).?;
|
const run = (try it.next(alloc)).?;
|
||||||
const cells = try shaper.shape(run);
|
const cells = try shaper.shape(run);
|
||||||
|
|
@ -737,13 +720,11 @@ test "shape" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -772,13 +753,11 @@ test "shape nerd fonts" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -800,13 +779,11 @@ test "shape inconsolata ligs" {
|
||||||
try screen.testWriteString(">=");
|
try screen.testWriteString(">=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -825,13 +802,11 @@ test "shape inconsolata ligs" {
|
||||||
try screen.testWriteString("===");
|
try screen.testWriteString("===");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -858,13 +833,11 @@ test "shape monaspace ligs" {
|
||||||
try screen.testWriteString("===");
|
try screen.testWriteString("===");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -892,13 +865,11 @@ test "shape left-replaced lig in last run" {
|
||||||
try screen.testWriteString("!==");
|
try screen.testWriteString("!==");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -926,13 +897,11 @@ test "shape left-replaced lig in early run" {
|
||||||
try screen.testWriteString("!==X");
|
try screen.testWriteString("!==X");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
const run = (try it.next(alloc)).?;
|
const run = (try it.next(alloc)).?;
|
||||||
|
|
||||||
|
|
@ -957,13 +926,11 @@ test "shape U+3C9 with JB Mono" {
|
||||||
try screen.testWriteString("\u{03C9} foo");
|
try screen.testWriteString("\u{03C9} foo");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
var run_count: usize = 0;
|
var run_count: usize = 0;
|
||||||
var cell_count: usize = 0;
|
var cell_count: usize = 0;
|
||||||
|
|
@ -990,13 +957,11 @@ test "shape emoji width" {
|
||||||
try screen.testWriteString("👍");
|
try screen.testWriteString("👍");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1040,13 +1005,11 @@ test "shape emoji width long" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 1 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 1 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1076,13 +1039,11 @@ test "shape variation selector VS15" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1111,13 +1072,11 @@ test "shape variation selector VS16" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1143,13 +1102,11 @@ test "shape with empty cells in between" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1181,13 +1138,11 @@ test "shape Chinese characters" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1221,13 +1176,11 @@ test "shape box glyphs" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1257,17 +1210,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1280,17 +1232,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 2, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 2, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1303,17 +1254,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1326,17 +1276,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1349,17 +1298,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1385,13 +1333,11 @@ test "shape cursor boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1400,61 +1346,111 @@ test "shape cursor boundary" {
|
||||||
try testing.expectEqual(@as(usize, 1), count);
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor at index 0 is two runs
|
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Cursor at index 0 is two runs
|
||||||
var shaper = &testdata.shaper;
|
{
|
||||||
var it = shaper.runIterator(
|
// Get our run iterator
|
||||||
testdata.grid,
|
var shaper = &testdata.shaper;
|
||||||
&screen,
|
var it = shaper.runIterator(.{
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.grid = testdata.grid,
|
||||||
null,
|
.screen = &screen,
|
||||||
0,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
);
|
.cursor_x = 0,
|
||||||
var count: usize = 0;
|
});
|
||||||
while (try it.next(alloc)) |run| {
|
var count: usize = 0;
|
||||||
count += 1;
|
while (try it.next(alloc)) |run| {
|
||||||
_ = try shaper.shape(run);
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 2), count);
|
||||||
|
}
|
||||||
|
// And without cursor splitting remains one
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
try testing.expectEqual(@as(usize, 2), count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor at index 1 is three runs
|
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Cursor at index 1 is three runs
|
||||||
var shaper = &testdata.shaper;
|
{
|
||||||
var it = shaper.runIterator(
|
// Get our run iterator
|
||||||
testdata.grid,
|
var shaper = &testdata.shaper;
|
||||||
&screen,
|
var it = shaper.runIterator(.{
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.grid = testdata.grid,
|
||||||
null,
|
.screen = &screen,
|
||||||
1,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
);
|
.cursor_x = 1,
|
||||||
var count: usize = 0;
|
});
|
||||||
while (try it.next(alloc)) |run| {
|
var count: usize = 0;
|
||||||
count += 1;
|
while (try it.next(alloc)) |run| {
|
||||||
_ = try shaper.shape(run);
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 3), count);
|
||||||
|
}
|
||||||
|
// And without cursor splitting remains one
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
try testing.expectEqual(@as(usize, 3), count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor at last col is two runs
|
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Cursor at last col is two runs
|
||||||
var shaper = &testdata.shaper;
|
{
|
||||||
var it = shaper.runIterator(
|
// Get our run iterator
|
||||||
testdata.grid,
|
var shaper = &testdata.shaper;
|
||||||
&screen,
|
var it = shaper.runIterator(.{
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.grid = testdata.grid,
|
||||||
null,
|
.screen = &screen,
|
||||||
9,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
);
|
.cursor_x = 9,
|
||||||
var count: usize = 0;
|
});
|
||||||
while (try it.next(alloc)) |run| {
|
var count: usize = 0;
|
||||||
count += 1;
|
while (try it.next(alloc)) |run| {
|
||||||
_ = try shaper.shape(run);
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 2), count);
|
||||||
|
}
|
||||||
|
// And without cursor splitting remains one
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
try testing.expectEqual(@as(usize, 2), count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1474,13 +1470,11 @@ test "shape cursor boundary and colored emoji" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1493,13 +1487,12 @@ test "shape cursor boundary and colored emoji" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
.cursor_x = 0,
|
||||||
0,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1510,13 +1503,42 @@ test "shape cursor boundary and colored emoji" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
1,
|
var count: usize = 0;
|
||||||
);
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
.cursor_x = 1,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1540,13 +1562,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString(">=");
|
try screen.testWriteString(">=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1564,13 +1584,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1589,13 +1607,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1614,13 +1630,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1638,13 +1652,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1678,13 +1690,11 @@ test "shape high plane sprite font codepoint" {
|
||||||
try screen.testWriteString("\u{1FB70}");
|
try screen.testWriteString("\u{1FB70}");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
// We should get one run
|
// We should get one run
|
||||||
const run = (try it.next(alloc)).?;
|
const run = (try it.next(alloc)).?;
|
||||||
// The run state should have the UTF-16 encoding of the character.
|
// The run state should have the UTF-16 encoding of the character.
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
|
||||||
const harfbuzz = @import("harfbuzz");
|
const harfbuzz = @import("harfbuzz");
|
||||||
const font = @import("../main.zig");
|
const font = @import("../main.zig");
|
||||||
const terminal = @import("../../terminal/main.zig");
|
const terminal = @import("../../terminal/main.zig");
|
||||||
|
const config = @import("../../config.zig");
|
||||||
const Feature = font.shape.Feature;
|
const Feature = font.shape.Feature;
|
||||||
const FeatureList = font.shape.FeatureList;
|
const FeatureList = font.shape.FeatureList;
|
||||||
const default_features = font.shape.default_features;
|
const default_features = font.shape.default_features;
|
||||||
|
|
@ -89,19 +90,11 @@ pub const Shaper = struct {
|
||||||
/// and assume the y value matches.
|
/// and assume the y value matches.
|
||||||
pub fn runIterator(
|
pub fn runIterator(
|
||||||
self: *Shaper,
|
self: *Shaper,
|
||||||
grid: *SharedGrid,
|
opts: font.shape.RunOptions,
|
||||||
screen: *const terminal.Screen,
|
|
||||||
row: terminal.Pin,
|
|
||||||
selection: ?terminal.Selection,
|
|
||||||
cursor_x: ?usize,
|
|
||||||
) font.shape.RunIterator {
|
) font.shape.RunIterator {
|
||||||
return .{
|
return .{
|
||||||
.hooks = .{ .shaper = self },
|
.hooks = .{ .shaper = self },
|
||||||
.grid = grid,
|
.opts = opts,
|
||||||
.screen = screen,
|
|
||||||
.row = row,
|
|
||||||
.selection = selection,
|
|
||||||
.cursor_x = cursor_x,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,13 +218,11 @@ test "run iterator" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |_| count += 1;
|
while (try it.next(alloc)) |_| count += 1;
|
||||||
try testing.expectEqual(@as(usize, 1), count);
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
|
@ -244,13 +235,11 @@ test "run iterator" {
|
||||||
try screen.testWriteString("ABCD EFG");
|
try screen.testWriteString("ABCD EFG");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |_| count += 1;
|
while (try it.next(alloc)) |_| count += 1;
|
||||||
try testing.expectEqual(@as(usize, 1), count);
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
|
@ -264,13 +253,11 @@ test "run iterator" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |_| {
|
while (try it.next(alloc)) |_| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -316,13 +303,11 @@ test "run iterator: empty cells with background set" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
{
|
{
|
||||||
const run = (try it.next(alloc)).?;
|
const run = (try it.next(alloc)).?;
|
||||||
try testing.expectEqual(@as(u32, 3), shaper.hb_buf.getLength());
|
try testing.expectEqual(@as(u32, 3), shaper.hb_buf.getLength());
|
||||||
|
|
@ -353,13 +338,11 @@ test "shape" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -382,13 +365,11 @@ test "shape inconsolata ligs" {
|
||||||
try screen.testWriteString(">=");
|
try screen.testWriteString(">=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -407,13 +388,11 @@ test "shape inconsolata ligs" {
|
||||||
try screen.testWriteString("===");
|
try screen.testWriteString("===");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -440,13 +419,11 @@ test "shape monaspace ligs" {
|
||||||
try screen.testWriteString("===");
|
try screen.testWriteString("===");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -476,13 +453,11 @@ test "shape arabic forced LTR" {
|
||||||
try screen.testWriteString(@embedFile("testdata/arabic.txt"));
|
try screen.testWriteString(@embedFile("testdata/arabic.txt"));
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -513,13 +488,11 @@ test "shape emoji width" {
|
||||||
try screen.testWriteString("👍");
|
try screen.testWriteString("👍");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -565,13 +538,11 @@ test "shape emoji width long" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 1 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 1 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -603,13 +574,11 @@ test "shape variation selector VS15" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -640,13 +609,11 @@ test "shape variation selector VS16" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -674,13 +641,11 @@ test "shape with empty cells in between" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -712,13 +677,11 @@ test "shape Chinese characters" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -752,13 +715,11 @@ test "shape box glyphs" {
|
||||||
|
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -789,17 +750,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -812,17 +772,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 2, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 2, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = screen.pages.cols - 1, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -835,17 +794,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 0, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -858,17 +816,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 3, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -881,17 +838,16 @@ test "shape selection boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
terminal.Selection.init(
|
.selection = terminal.Selection.init(
|
||||||
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
||||||
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
screen.pages.pin(.{ .active = .{ .x = 1, .y = 0 } }).?,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
null,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -917,13 +873,11 @@ test "shape cursor boundary" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -932,61 +886,111 @@ test "shape cursor boundary" {
|
||||||
try testing.expectEqual(@as(usize, 1), count);
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor at index 0 is two runs
|
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Cursor at index 0 is two runs
|
||||||
var shaper = &testdata.shaper;
|
{
|
||||||
var it = shaper.runIterator(
|
// Get our run iterator
|
||||||
testdata.grid,
|
var shaper = &testdata.shaper;
|
||||||
&screen,
|
var it = shaper.runIterator(.{
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.grid = testdata.grid,
|
||||||
null,
|
.screen = &screen,
|
||||||
0,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
);
|
.cursor_x = 0,
|
||||||
var count: usize = 0;
|
});
|
||||||
while (try it.next(alloc)) |run| {
|
var count: usize = 0;
|
||||||
count += 1;
|
while (try it.next(alloc)) |run| {
|
||||||
_ = try shaper.shape(run);
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 2), count);
|
||||||
|
}
|
||||||
|
// And without cursor splitting remains one
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
try testing.expectEqual(@as(usize, 2), count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor at index 1 is three runs
|
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Cursor at index 1 is three runs
|
||||||
var shaper = &testdata.shaper;
|
{
|
||||||
var it = shaper.runIterator(
|
// Get our run iterator
|
||||||
testdata.grid,
|
var shaper = &testdata.shaper;
|
||||||
&screen,
|
var it = shaper.runIterator(.{
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.grid = testdata.grid,
|
||||||
null,
|
.screen = &screen,
|
||||||
1,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
);
|
.cursor_x = 1,
|
||||||
var count: usize = 0;
|
});
|
||||||
while (try it.next(alloc)) |run| {
|
var count: usize = 0;
|
||||||
count += 1;
|
while (try it.next(alloc)) |run| {
|
||||||
_ = try shaper.shape(run);
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 3), count);
|
||||||
|
}
|
||||||
|
// And without cursor splitting remains one
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
try testing.expectEqual(@as(usize, 3), count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor at last col is two runs
|
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Cursor at last col is two runs
|
||||||
var shaper = &testdata.shaper;
|
{
|
||||||
var it = shaper.runIterator(
|
// Get our run iterator
|
||||||
testdata.grid,
|
var shaper = &testdata.shaper;
|
||||||
&screen,
|
var it = shaper.runIterator(.{
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.grid = testdata.grid,
|
||||||
null,
|
.screen = &screen,
|
||||||
9,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
);
|
.cursor_x = 9,
|
||||||
var count: usize = 0;
|
});
|
||||||
while (try it.next(alloc)) |run| {
|
var count: usize = 0;
|
||||||
count += 1;
|
while (try it.next(alloc)) |run| {
|
||||||
_ = try shaper.shape(run);
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 2), count);
|
||||||
|
}
|
||||||
|
// And without cursor splitting remains one
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
}
|
}
|
||||||
try testing.expectEqual(@as(usize, 2), count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1006,13 +1010,11 @@ test "shape cursor boundary and colored emoji" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1025,13 +1027,12 @@ test "shape cursor boundary and colored emoji" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
.cursor_x = 0,
|
||||||
0,
|
});
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1042,13 +1043,42 @@ test "shape cursor boundary and colored emoji" {
|
||||||
{
|
{
|
||||||
// Get our run iterator
|
// Get our run iterator
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
1,
|
var count: usize = 0;
|
||||||
);
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
.cursor_x = 1,
|
||||||
|
});
|
||||||
|
var count: usize = 0;
|
||||||
|
while (try it.next(alloc)) |run| {
|
||||||
|
count += 1;
|
||||||
|
_ = try shaper.shape(run);
|
||||||
|
}
|
||||||
|
try testing.expectEqual(@as(usize, 1), count);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Get our run iterator
|
||||||
|
var shaper = &testdata.shaper;
|
||||||
|
var it = shaper.runIterator(.{
|
||||||
|
.grid = testdata.grid,
|
||||||
|
.screen = &screen,
|
||||||
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
|
});
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1072,13 +1102,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString(">=");
|
try screen.testWriteString(">=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1096,13 +1124,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1121,13 +1147,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1146,13 +1170,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
@ -1170,13 +1192,11 @@ test "shape cell attribute change" {
|
||||||
try screen.testWriteString("=");
|
try screen.testWriteString("=");
|
||||||
|
|
||||||
var shaper = &testdata.shaper;
|
var shaper = &testdata.shaper;
|
||||||
var it = shaper.runIterator(
|
var it = shaper.runIterator(.{
|
||||||
testdata.grid,
|
.grid = testdata.grid,
|
||||||
&screen,
|
.screen = &screen,
|
||||||
screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
.row = screen.pages.pin(.{ .screen = .{ .y = 0 } }).?,
|
||||||
null,
|
});
|
||||||
null,
|
|
||||||
);
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (try it.next(alloc)) |run| {
|
while (try it.next(alloc)) |run| {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
|
||||||
|
|
@ -70,19 +70,11 @@ pub const Shaper = struct {
|
||||||
|
|
||||||
pub fn runIterator(
|
pub fn runIterator(
|
||||||
self: *Shaper,
|
self: *Shaper,
|
||||||
grid: *SharedGrid,
|
opts: font.shape.RunOptions,
|
||||||
screen: *const terminal.Screen,
|
|
||||||
row: terminal.Pin,
|
|
||||||
selection: ?terminal.Selection,
|
|
||||||
cursor_x: ?usize,
|
|
||||||
) font.shape.RunIterator {
|
) font.shape.RunIterator {
|
||||||
return .{
|
return .{
|
||||||
.hooks = .{ .shaper = self },
|
.hooks = .{ .shaper = self },
|
||||||
.grid = grid,
|
.opts = opts,
|
||||||
.screen = screen,
|
|
||||||
.row = row,
|
|
||||||
.selection = selection,
|
|
||||||
.cursor_x = cursor_x,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,15 +35,11 @@ pub const TextRun = struct {
|
||||||
/// RunIterator is an iterator that yields text runs.
|
/// RunIterator is an iterator that yields text runs.
|
||||||
pub const RunIterator = struct {
|
pub const RunIterator = struct {
|
||||||
hooks: font.Shaper.RunIteratorHook,
|
hooks: font.Shaper.RunIteratorHook,
|
||||||
grid: *font.SharedGrid,
|
opts: shape.RunOptions,
|
||||||
screen: *const terminal.Screen,
|
|
||||||
row: terminal.Pin,
|
|
||||||
selection: ?terminal.Selection = null,
|
|
||||||
cursor_x: ?usize = null,
|
|
||||||
i: usize = 0,
|
i: usize = 0,
|
||||||
|
|
||||||
pub fn next(self: *RunIterator, alloc: Allocator) !?TextRun {
|
pub fn next(self: *RunIterator, alloc: Allocator) !?TextRun {
|
||||||
const cells = self.row.cells(.all);
|
const cells = self.opts.row.cells(.all);
|
||||||
|
|
||||||
// Trim the right side of a row that might be empty
|
// Trim the right side of a row that might be empty
|
||||||
const max: usize = max: {
|
const max: usize = max: {
|
||||||
|
|
@ -58,7 +54,7 @@ pub const RunIterator = struct {
|
||||||
// Invisible cells don't have any glyphs rendered,
|
// Invisible cells don't have any glyphs rendered,
|
||||||
// so we explicitly skip them in the shaping process.
|
// so we explicitly skip them in the shaping process.
|
||||||
while (self.i < max and
|
while (self.i < max and
|
||||||
self.row.style(&cells[self.i]).flags.invisible)
|
self.opts.row.style(&cells[self.i]).flags.invisible)
|
||||||
{
|
{
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +72,7 @@ pub const RunIterator = struct {
|
||||||
var hasher = Hasher.init(0);
|
var hasher = Hasher.init(0);
|
||||||
|
|
||||||
// Let's get our style that we'll expect for the run.
|
// Let's get our style that we'll expect for the run.
|
||||||
const style = self.row.style(&cells[self.i]);
|
const style = self.opts.row.style(&cells[self.i]);
|
||||||
|
|
||||||
// Go through cell by cell and accumulate while we build our run.
|
// Go through cell by cell and accumulate while we build our run.
|
||||||
var j: usize = self.i;
|
var j: usize = self.i;
|
||||||
|
|
@ -86,9 +82,9 @@ pub const RunIterator = struct {
|
||||||
|
|
||||||
// If we have a selection and we're at a boundary point, then
|
// If we have a selection and we're at a boundary point, then
|
||||||
// we break the run here.
|
// we break the run here.
|
||||||
if (self.selection) |unordered_sel| {
|
if (self.opts.selection) |unordered_sel| {
|
||||||
if (j > self.i) {
|
if (j > self.i) {
|
||||||
const sel = unordered_sel.ordered(self.screen, .forward);
|
const sel = unordered_sel.ordered(self.opts.screen, .forward);
|
||||||
const start_x = sel.start().x;
|
const start_x = sel.start().x;
|
||||||
const end_x = sel.end().x;
|
const end_x = sel.end().x;
|
||||||
|
|
||||||
|
|
@ -142,7 +138,7 @@ pub const RunIterator = struct {
|
||||||
// The style is different. We allow differing background
|
// The style is different. We allow differing background
|
||||||
// styles but any other change results in a new run.
|
// styles but any other change results in a new run.
|
||||||
const c1 = comparableStyle(style);
|
const c1 = comparableStyle(style);
|
||||||
const c2 = comparableStyle(self.row.style(&cells[j]));
|
const c2 = comparableStyle(self.opts.row.style(&cells[j]));
|
||||||
if (!c1.eql(c2)) break;
|
if (!c1.eql(c2)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,7 +158,7 @@ pub const RunIterator = struct {
|
||||||
const presentation: ?font.Presentation = if (cell.hasGrapheme()) p: {
|
const presentation: ?font.Presentation = if (cell.hasGrapheme()) p: {
|
||||||
// We only check the FIRST codepoint because I believe the
|
// We only check the FIRST codepoint because I believe the
|
||||||
// presentation format must be directly adjacent to the codepoint.
|
// presentation format must be directly adjacent to the codepoint.
|
||||||
const cps = self.row.grapheme(cell) orelse break :p null;
|
const cps = self.opts.row.grapheme(cell) orelse break :p null;
|
||||||
assert(cps.len > 0);
|
assert(cps.len > 0);
|
||||||
if (cps[0] == 0xFE0E) break :p .text;
|
if (cps[0] == 0xFE0E) break :p .text;
|
||||||
if (cps[0] == 0xFE0F) break :p .emoji;
|
if (cps[0] == 0xFE0F) break :p .emoji;
|
||||||
|
|
@ -186,7 +182,7 @@ pub const RunIterator = struct {
|
||||||
// joiners will show the joiners allowing you to modify the
|
// joiners will show the joiners allowing you to modify the
|
||||||
// emoji.
|
// emoji.
|
||||||
if (!cell.hasGrapheme()) {
|
if (!cell.hasGrapheme()) {
|
||||||
if (self.cursor_x) |cursor_x| {
|
if (self.opts.cursor_x) |cursor_x| {
|
||||||
// Exactly: self.i is the cursor and we iterated once. This
|
// Exactly: self.i is the cursor and we iterated once. This
|
||||||
// means that we started exactly at the cursor and did at
|
// means that we started exactly at the cursor and did at
|
||||||
// exactly one iteration. Why exactly one? Because we may
|
// exactly one iteration. Why exactly one? Because we may
|
||||||
|
|
@ -227,7 +223,7 @@ pub const RunIterator = struct {
|
||||||
|
|
||||||
// Otherwise we need a fallback character. Prefer the
|
// Otherwise we need a fallback character. Prefer the
|
||||||
// official replacement character.
|
// official replacement character.
|
||||||
if (try self.grid.getIndex(
|
if (try self.opts.grid.getIndex(
|
||||||
alloc,
|
alloc,
|
||||||
0xFFFD, // replacement char
|
0xFFFD, // replacement char
|
||||||
font_style,
|
font_style,
|
||||||
|
|
@ -235,7 +231,7 @@ pub const RunIterator = struct {
|
||||||
)) |idx| break :font_info .{ .idx = idx, .fallback = 0xFFFD };
|
)) |idx| break :font_info .{ .idx = idx, .fallback = 0xFFFD };
|
||||||
|
|
||||||
// Fallback to space
|
// Fallback to space
|
||||||
if (try self.grid.getIndex(
|
if (try self.opts.grid.getIndex(
|
||||||
alloc,
|
alloc,
|
||||||
' ',
|
' ',
|
||||||
font_style,
|
font_style,
|
||||||
|
|
@ -273,7 +269,7 @@ pub const RunIterator = struct {
|
||||||
@intCast(cluster),
|
@intCast(cluster),
|
||||||
);
|
);
|
||||||
if (cell.hasGrapheme()) {
|
if (cell.hasGrapheme()) {
|
||||||
const cps = self.row.grapheme(cell).?;
|
const cps = self.opts.row.grapheme(cell).?;
|
||||||
for (cps) |cp| {
|
for (cps) |cp| {
|
||||||
// Do not send presentation modifiers
|
// Do not send presentation modifiers
|
||||||
if (cp == 0xFE0E or cp == 0xFE0F) continue;
|
if (cp == 0xFE0E or cp == 0xFE0F) continue;
|
||||||
|
|
@ -298,7 +294,7 @@ pub const RunIterator = struct {
|
||||||
.hash = hasher.final(),
|
.hash = hasher.final(),
|
||||||
.offset = @intCast(self.i),
|
.offset = @intCast(self.i),
|
||||||
.cells = @intCast(j - self.i),
|
.cells = @intCast(j - self.i),
|
||||||
.grid = self.grid,
|
.grid = self.opts.grid,
|
||||||
.font_index = current_font,
|
.font_index = current_font,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +322,7 @@ pub const RunIterator = struct {
|
||||||
cell.codepoint() == 0 or
|
cell.codepoint() == 0 or
|
||||||
cell.codepoint() == terminal.kitty.graphics.unicode.placeholder)
|
cell.codepoint() == terminal.kitty.graphics.unicode.placeholder)
|
||||||
{
|
{
|
||||||
return try self.grid.getIndex(
|
return try self.opts.grid.getIndex(
|
||||||
alloc,
|
alloc,
|
||||||
' ',
|
' ',
|
||||||
style,
|
style,
|
||||||
|
|
@ -336,7 +332,7 @@ pub const RunIterator = struct {
|
||||||
|
|
||||||
// Get the font index for the primary codepoint.
|
// Get the font index for the primary codepoint.
|
||||||
const primary_cp: u32 = cell.codepoint();
|
const primary_cp: u32 = cell.codepoint();
|
||||||
const primary = try self.grid.getIndex(
|
const primary = try self.opts.grid.getIndex(
|
||||||
alloc,
|
alloc,
|
||||||
primary_cp,
|
primary_cp,
|
||||||
style,
|
style,
|
||||||
|
|
@ -349,7 +345,7 @@ pub const RunIterator = struct {
|
||||||
|
|
||||||
// If this is a grapheme, we need to find a font that supports
|
// If this is a grapheme, we need to find a font that supports
|
||||||
// all of the codepoints in the grapheme.
|
// all of the codepoints in the grapheme.
|
||||||
const cps = self.row.grapheme(cell) orelse return primary;
|
const cps = self.opts.row.grapheme(cell) orelse return primary;
|
||||||
var candidates = try std.ArrayList(font.Collection.Index).initCapacity(alloc, cps.len + 1);
|
var candidates = try std.ArrayList(font.Collection.Index).initCapacity(alloc, cps.len + 1);
|
||||||
defer candidates.deinit();
|
defer candidates.deinit();
|
||||||
candidates.appendAssumeCapacity(primary);
|
candidates.appendAssumeCapacity(primary);
|
||||||
|
|
@ -365,7 +361,7 @@ pub const RunIterator = struct {
|
||||||
// to support the base presentation, since it is common for emoji
|
// to support the base presentation, since it is common for emoji
|
||||||
// fonts to support the base emoji with emoji presentation but not
|
// fonts to support the base emoji with emoji presentation but not
|
||||||
// certain ZWJ-combined characters like the male and female signs.
|
// certain ZWJ-combined characters like the male and female signs.
|
||||||
const idx = try self.grid.getIndex(
|
const idx = try self.opts.grid.getIndex(
|
||||||
alloc,
|
alloc,
|
||||||
cp,
|
cp,
|
||||||
style,
|
style,
|
||||||
|
|
@ -376,11 +372,11 @@ pub const RunIterator = struct {
|
||||||
|
|
||||||
// We need to find a candidate that has ALL of our codepoints
|
// We need to find a candidate that has ALL of our codepoints
|
||||||
for (candidates.items) |idx| {
|
for (candidates.items) |idx| {
|
||||||
if (!self.grid.hasCodepoint(idx, primary_cp, presentation)) continue;
|
if (!self.opts.grid.hasCodepoint(idx, primary_cp, presentation)) continue;
|
||||||
for (cps) |cp| {
|
for (cps) |cp| {
|
||||||
// Ignore Emoji ZWJs
|
// Ignore Emoji ZWJs
|
||||||
if (cp == 0xFE0E or cp == 0xFE0F or cp == 0x200D) continue;
|
if (cp == 0xFE0E or cp == 0xFE0F or cp == 0x200D) continue;
|
||||||
if (!self.grid.hasCodepoint(idx, cp, null)) break;
|
if (!self.opts.grid.hasCodepoint(idx, cp, null)) break;
|
||||||
} else {
|
} else {
|
||||||
// If the while completed, then we have a candidate that
|
// If the while completed, then we have a candidate that
|
||||||
// supports all of our codepoints.
|
// supports all of our codepoints.
|
||||||
|
|
|
||||||
|
|
@ -61,17 +61,11 @@ pub const Shaper = struct {
|
||||||
/// for a Shaper struct since they share state.
|
/// for a Shaper struct since they share state.
|
||||||
pub fn runIterator(
|
pub fn runIterator(
|
||||||
self: *Shaper,
|
self: *Shaper,
|
||||||
group: *font.GroupCache,
|
opts: font.shape.RunOptions,
|
||||||
row: terminal.Screen.Row,
|
|
||||||
selection: ?terminal.Selection,
|
|
||||||
cursor_x: ?usize,
|
|
||||||
) font.shape.RunIterator {
|
) font.shape.RunIterator {
|
||||||
return .{
|
return .{
|
||||||
.hooks = .{ .shaper = self },
|
.hooks = .{ .shaper = self },
|
||||||
.group = group,
|
.opts = opts,
|
||||||
.row = row,
|
|
||||||
.selection = selection,
|
|
||||||
.cursor_x = cursor_x,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||||
font_thicken_strength: u8,
|
font_thicken_strength: u8,
|
||||||
font_features: std.ArrayListUnmanaged([:0]const u8),
|
font_features: std.ArrayListUnmanaged([:0]const u8),
|
||||||
font_styles: font.CodepointResolver.StyleStatus,
|
font_styles: font.CodepointResolver.StyleStatus,
|
||||||
|
font_shaping_break: configpkg.FontShapingBreak,
|
||||||
cursor_color: ?terminal.color.RGB,
|
cursor_color: ?terminal.color.RGB,
|
||||||
cursor_invert: bool,
|
cursor_invert: bool,
|
||||||
cursor_opacity: f64,
|
cursor_opacity: f64,
|
||||||
|
|
@ -578,6 +579,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||||
.font_thicken_strength = config.@"font-thicken-strength",
|
.font_thicken_strength = config.@"font-thicken-strength",
|
||||||
.font_features = font_features.list,
|
.font_features = font_features.list,
|
||||||
.font_styles = font_styles,
|
.font_styles = font_styles,
|
||||||
|
.font_shaping_break = config.@"font-shaping-break",
|
||||||
|
|
||||||
.cursor_color = if (!cursor_invert and config.@"cursor-color" != null)
|
.cursor_color = if (!cursor_invert and config.@"cursor-color" != null)
|
||||||
config.@"cursor-color".?.toTerminalRGB()
|
config.@"cursor-color".?.toTerminalRGB()
|
||||||
|
|
@ -2467,13 +2469,15 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterator of runs for shaping.
|
// Iterator of runs for shaping.
|
||||||
var run_iter = self.font_shaper.runIterator(
|
var run_iter_opts: font.shape.RunOptions = .{
|
||||||
self.font_grid,
|
.grid = self.font_grid,
|
||||||
screen,
|
.screen = screen,
|
||||||
row,
|
.row = row,
|
||||||
row_selection,
|
.selection = row_selection,
|
||||||
if (shape_cursor) screen.cursor.x else null,
|
.cursor_x = if (shape_cursor) screen.cursor.x else null,
|
||||||
);
|
};
|
||||||
|
run_iter_opts.applyBreakConfig(self.config.font_shaping_break);
|
||||||
|
var run_iter = self.font_shaper.runIterator(run_iter_opts);
|
||||||
var shaper_run: ?font.shape.TextRun = try run_iter.next(self.alloc);
|
var shaper_run: ?font.shape.TextRun = try run_iter.next(self.alloc);
|
||||||
var shaper_cells: ?[]const font.shape.Cell = null;
|
var shaper_cells: ?[]const font.shape.Cell = null;
|
||||||
var shaper_cells_i: usize = 0;
|
var shaper_cells_i: usize = 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue