mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
terminal: swap codepointwidth implementations
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
# - "ascii", uniform random ASCII bytes
|
# - "ascii", uniform random ASCII bytes
|
||||||
# - "utf8", uniform random unicode characters, encoded as utf8
|
# - "utf8", uniform random unicode characters, encoded as utf8
|
||||||
# - "rand", pure random data, will contain many invalid code sequences.
|
# - "rand", pure random data, will contain many invalid code sequences.
|
||||||
DATA="ascii"
|
DATA="utf8"
|
||||||
SIZE="25000000"
|
SIZE="25000000"
|
||||||
|
|
||||||
# Add additional arguments
|
# Add additional arguments
|
||||||
|
@ -187,12 +187,15 @@ static_assert(std::size(eaw_gte) == std::size(eaw_lte));
|
|||||||
static_assert(std::size(zero_gte) == std::size(zero_lte));
|
static_assert(std::size(zero_gte) == std::size(zero_lte));
|
||||||
static_assert(std::size(nsm_gte) == std::size(nsm_lte));
|
static_assert(std::size(nsm_gte) == std::size(nsm_lte));
|
||||||
|
|
||||||
|
/// Vectorized implementation of Unicode display width. Determining width
|
||||||
|
/// unfortunately requires many small range checks, so we test some fast paths
|
||||||
|
/// and otherwise try to do N (vector lane width) range checks at a time.
|
||||||
template <class D>
|
template <class D>
|
||||||
int8_t CodepointWidthImpl(D d, T input) {
|
int8_t CodepointWidthImpl(D d, T input) {
|
||||||
// If the input is ASCII, then we return 1. We do NOT check for
|
// If the input is ASCII, then we return 1. We do NOT check for
|
||||||
// control characters because we assume that the input has already
|
// control characters because we assume that the input has already
|
||||||
// been checked for that case.
|
// been checked for that case.
|
||||||
if (input < 0xFF) {
|
if (input <= 0xFF) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,14 +204,6 @@ int8_t CodepointWidthImpl(D d, T input) {
|
|||||||
const hn::Vec<D> input_vec = Set(d, input);
|
const hn::Vec<D> input_vec = Set(d, input);
|
||||||
|
|
||||||
{
|
{
|
||||||
// Thes are the ranges (inclusive) of the codepoints that are DEFINITELY
|
|
||||||
// width 2. We will check as many in parallel as possible.
|
|
||||||
//
|
|
||||||
// The zero padding is so that we can always load aligned directly into
|
|
||||||
// a vector register of any size up to 16 bytes (AVX512).
|
|
||||||
//
|
|
||||||
// Ranges: two-em dash, gbp.isRegionalIndicator, CJK...
|
|
||||||
//
|
|
||||||
// NOTE: 0x2E3B is technically width 3 but for our terminal we only
|
// NOTE: 0x2E3B is technically width 3 but for our terminal we only
|
||||||
// handle up to width 2 as wide so we will treat it as width 2.
|
// handle up to width 2 as wide so we will treat it as width 2.
|
||||||
HWY_ALIGN constexpr T gte_keys[] = {
|
HWY_ALIGN constexpr T gte_keys[] = {
|
||||||
@ -233,7 +228,6 @@ int8_t CodepointWidthImpl(D d, T input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Definitely width 0
|
|
||||||
HWY_ALIGN constexpr T gte_keys[] = {
|
HWY_ALIGN constexpr T gte_keys[] = {
|
||||||
0x1160, 0x2060, 0xFFF0, 0xE0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0x1160, 0x2060, 0xFFF0, 0xE0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,7 @@ const ziglyph = @import("ziglyph");
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const simd = @import("../simd/main.zig");
|
||||||
|
|
||||||
const ansi = @import("ansi.zig");
|
const ansi = @import("ansi.zig");
|
||||||
const modes = @import("modes.zig");
|
const modes = @import("modes.zig");
|
||||||
@ -869,10 +870,13 @@ pub fn print(self: *Terminal, c: u21) !void {
|
|||||||
|
|
||||||
// Determine the width of this character so we can handle
|
// Determine the width of this character so we can handle
|
||||||
// non-single-width characters properly.
|
// non-single-width characters properly.
|
||||||
const width: usize = @intCast(@min(
|
const width: usize = @intCast(simd.codepointWidth(c));
|
||||||
@max(0, ziglyph.display_width.codePointWidth(c, .half)),
|
|
||||||
2,
|
// Old implementation, 3x slower on ASCII, 2x slower on CJK, etc.
|
||||||
));
|
// const width: usize = @intCast(@min(
|
||||||
|
// @max(0, ziglyph.display_width.codePointWidth(c, .half)),
|
||||||
|
// 2,
|
||||||
|
// ));
|
||||||
|
|
||||||
// Note: it is possible to have a width of "3" and a width of "-1"
|
// Note: it is possible to have a width of "3" and a width of "-1"
|
||||||
// from ziglyph. We should look into those cases and handle them
|
// from ziglyph. We should look into those cases and handle them
|
||||||
@ -2304,31 +2308,6 @@ test "Terminal: print over wide spacer tail" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Terminal: zero width chars with grapheme clustering can be put in their own cell" {
|
|
||||||
var t = try init(testing.allocator, 5, 5);
|
|
||||||
defer t.deinit(testing.allocator);
|
|
||||||
|
|
||||||
// Enable grapheme clustering
|
|
||||||
t.modes.set(.grapheme_cluster, true);
|
|
||||||
|
|
||||||
try t.print('x');
|
|
||||||
try t.print(0x7F); // zero-width control character
|
|
||||||
|
|
||||||
{
|
|
||||||
const str = try t.plainString(testing.allocator);
|
|
||||||
defer testing.allocator.free(str);
|
|
||||||
try testing.expectEqualStrings("x", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
const row = t.screen.getRow(.{ .screen = 0 });
|
|
||||||
{
|
|
||||||
const cell = row.getCell(0);
|
|
||||||
try testing.expectEqual(@as(u32, 'x'), cell.char);
|
|
||||||
try testing.expect(!cell.attrs.wide);
|
|
||||||
try testing.expect(!cell.attrs.grapheme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "Terminal: VS15 to make narrow character" {
|
test "Terminal: VS15 to make narrow character" {
|
||||||
var t = try init(testing.allocator, 5, 5);
|
var t = try init(testing.allocator, 5, 5);
|
||||||
defer t.deinit(testing.allocator);
|
defer t.deinit(testing.allocator);
|
||||||
|
Reference in New Issue
Block a user