deps: Update uucode to latest (#9678)

This updates uucode to the latest version, with the following changes:
b309dfb4e2...31655fba3c

For this PR, the new `uucode` version has two changes that contribute to
the diff:

* The `grapheme_break` now includes `emoji_modifier` and
`emoji_modifier_base`, so we don't need to grab those from
`is_emoji_modifier` and `is_emoji_modifier_base`.
* The `wcwidth` calculation has been split into `wcwidth_standalone`
(width of a code point when it's the only code point in a grapheme) and
`wcwidth_zero_in_grapheme` (whether the code point is _not_ contributing
to the width of a multi-code-point grapheme). To keep the current
Ghostty behavior for this PR, this sets `width` to 0 if
`wcwidth_zero_in_grapheme`, but with the exception of
`is_emoji_modifier` (see comment).
* While this PR isn't affected by it, take a look at
[wcwidth.zig](https://github.com/jacobsandlund/uucode/blob/main/src/x/config_x/wcwidth.zig)
for the considerations that went into determining the width of a code
point, along with many comments.
* See
[x/grapheme.zig](https://github.com/jacobsandlund/uucode/blob/main/src/x/grapheme.zig)
for the calculation of the width of a grapheme based on the width of the
code points with exceptions, again with many comments.
* See
[resources/wcwidth](https://github.com/jacobsandlund/uucode/tree/main/resources/wcwidth)
for a comparison of other unicode libraries calculation of "wcwidth".

PRs will follow this in a moment to also take advantage of the new
`uucode` version for:

* Better grapheme segmentation
* Correct VS15/VS16 handling
* More correct cell width calculation (especially certain scripts such
as Devanagari)
pull/9679/head^2
Mitchell Hashimoto 2025-11-24 07:31:22 -08:00 committed by GitHub
commit 38fbbba8e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 26 additions and 31 deletions

View File

@ -38,9 +38,9 @@
.lazy = true, .lazy = true,
}, },
.uucode = .{ .uucode = .{
// TODO: currently the use-llvm branch because its broken on self-hosted // jacobsandlund/uucode
.url = "https://github.com/jacobsandlund/uucode/archive/b309dfb4e25a38201d7b300b201a698e02283862.tar.gz", .url = "https://github.com/jacobsandlund/uucode/archive/31655fba3c638229989cc524363ef5e3c7b580c1.tar.gz",
.hash = "uucode-0.1.0-ZZjBPl_mQwDHQowHOzXwgTPhAqcFekfYpAeUfeHZNCl3", .hash = "uucode-0.1.0-ZZjBPicPTQDlG6OClzn2bPu7ICkkkyWrTB6aRsBr-A1E",
}, },
.zig_wayland = .{ .zig_wayland = .{
// codeberg ifreund/zig-wayland // codeberg ifreund/zig-wayland

6
build.zig.zon.json generated
View File

@ -114,10 +114,10 @@
"url": "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732", "url": "git+https://github.com/jacobsandlund/uucode#5f05f8f83a75caea201f12cc8ea32a2d82ea9732",
"hash": "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8=" "hash": "sha256-sHPh+TQSdUGus/QTbj7KSJJkTuNTrK4VNmQDjS30Lf8="
}, },
"uucode-0.1.0-ZZjBPl_mQwDHQowHOzXwgTPhAqcFekfYpAeUfeHZNCl3": { "uucode-0.1.0-ZZjBPicPTQDlG6OClzn2bPu7ICkkkyWrTB6aRsBr-A1E": {
"name": "uucode", "name": "uucode",
"url": "https://github.com/jacobsandlund/uucode/archive/b309dfb4e25a38201d7b300b201a698e02283862.tar.gz", "url": "https://github.com/jacobsandlund/uucode/archive/31655fba3c638229989cc524363ef5e3c7b580c1.tar.gz",
"hash": "sha256-jvko1MdWr1OG4P58KjdB1JMnWy4EbrO3xIkV8fiQkC0=" "hash": "sha256-SzpYGhgG4B6Luf8eT35sKLobCxjmwEuo1Twk0jeu9g4="
}, },
"vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS": { "vaxis-0.5.1-BWNV_LosCQAGmCCNOLljCIw6j6-yt53tji6n6rwJ2BhS": {
"name": "vaxis", "name": "vaxis",

6
build.zig.zon.nix generated
View File

@ -267,11 +267,11 @@ in
}; };
} }
{ {
name = "uucode-0.1.0-ZZjBPl_mQwDHQowHOzXwgTPhAqcFekfYpAeUfeHZNCl3"; name = "uucode-0.1.0-ZZjBPicPTQDlG6OClzn2bPu7ICkkkyWrTB6aRsBr-A1E";
path = fetchZigArtifact { path = fetchZigArtifact {
name = "uucode"; name = "uucode";
url = "https://github.com/jacobsandlund/uucode/archive/b309dfb4e25a38201d7b300b201a698e02283862.tar.gz"; url = "https://github.com/jacobsandlund/uucode/archive/31655fba3c638229989cc524363ef5e3c7b580c1.tar.gz";
hash = "sha256-jvko1MdWr1OG4P58KjdB1JMnWy4EbrO3xIkV8fiQkC0="; hash = "sha256-SzpYGhgG4B6Luf8eT35sKLobCxjmwEuo1Twk0jeu9g4=";
}; };
} }
{ {

2
build.zig.zon.txt generated
View File

@ -28,7 +28,7 @@ https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae
https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
https://github.com/jacobsandlund/uucode/archive/b309dfb4e25a38201d7b300b201a698e02283862.tar.gz https://github.com/jacobsandlund/uucode/archive/31655fba3c638229989cc524363ef5e3c7b580c1.tar.gz
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20251110-150531-d5f3d53/ghostty-themes.tgz https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20251110-150531-d5f3d53/ghostty-themes.tgz
https://github.com/natecraddock/zf/archive/3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz https://github.com/natecraddock/zf/archive/3c52637b7e937c5ae61fd679717da3e276765b23.tar.gz
https://github.com/rockorager/libvaxis/archive/7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz https://github.com/rockorager/libvaxis/archive/7dbb9fd3122e4ffad262dd7c151d80d863b68558.tar.gz

View File

@ -139,9 +139,9 @@
}, },
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/jacobsandlund/uucode/archive/b309dfb4e25a38201d7b300b201a698e02283862.tar.gz", "url": "https://github.com/jacobsandlund/uucode/archive/31655fba3c638229989cc524363ef5e3c7b580c1.tar.gz",
"dest": "vendor/p/uucode-0.1.0-ZZjBPl_mQwDHQowHOzXwgTPhAqcFekfYpAeUfeHZNCl3", "dest": "vendor/p/uucode-0.1.0-ZZjBPicPTQDlG6OClzn2bPu7ICkkkyWrTB6aRsBr-A1E",
"sha256": "8ef928d4c756af5386e0fe7c2a3741d493275b2e046eb3b7c48915f1f890902d" "sha256": "4b3a581a1806e01e8bb9ff1e4f7e6c28ba1b0b18e6c04ba8d53c24d237aef60e"
}, },
{ {
"type": "archive", "type": "archive",

View File

@ -19,23 +19,23 @@ fn computeWidth(
_ = backing; _ = backing;
_ = tracking; _ = tracking;
// Emoji modifiers are technically width 0 because they're joining // This condition is to get the previous behavior of uucode's `wcwidth`,
// points. But we handle joining via grapheme break and don't use width // returning the width of a code point in a grapheme cluster but with the
// there. If a emoji modifier is standalone, we want it to take up // exception to treat emoji modifiers as width 2 so they can be displayed
// two columns. // in isolation. PRs to follow will take advantage of the new uucode
if (data.is_emoji_modifier) { // `wcwidth_standalone` vs `wcwidth_zero_in_grapheme` split.
assert(data.wcwidth == 0); if (data.wcwidth_zero_in_grapheme and !data.is_emoji_modifier) {
data.wcwidth = 2; data.width = 0;
return; } else {
data.width = @min(2, data.wcwidth_standalone);
} }
data.width = @intCast(@min(2, @max(0, data.wcwidth)));
} }
const width = config.Extension{ const width = config.Extension{
.inputs = &.{ .inputs = &.{
"wcwidth_standalone",
"wcwidth_zero_in_grapheme",
"is_emoji_modifier", "is_emoji_modifier",
"wcwidth",
}, },
.compute = &computeWidth, .compute = &computeWidth,
.fields = &.{ .fields = &.{
@ -90,8 +90,6 @@ pub const tables = [_]config.Table{
width.field("width"), width.field("width"),
d.field("grapheme_break"), d.field("grapheme_break"),
is_symbol.field("is_symbol"), is_symbol.field("is_symbol"),
d.field("is_emoji_modifier"),
d.field("is_emoji_modifier_base"),
d.field("is_emoji_vs_text"), d.field("is_emoji_vs_text"),
d.field("is_emoji_vs_emoji"), d.field("is_emoji_vs_emoji"),
}, },

View File

@ -11,11 +11,6 @@ const GraphemeBoundaryClass = @import("props.zig").GraphemeBoundaryClass;
fn graphemeBoundaryClass(cp: u21) GraphemeBoundaryClass { fn graphemeBoundaryClass(cp: u21) GraphemeBoundaryClass {
if (cp > uucode.config.max_code_point) return .invalid; if (cp > uucode.config.max_code_point) return .invalid;
// We special-case modifier bases because we should not break
// if a modifier isn't next to a base.
if (uucode.get(.is_emoji_modifier, cp)) return .emoji_modifier;
if (uucode.get(.is_emoji_modifier_base, cp)) return .extended_pictographic_base;
return switch (uucode.get(.grapheme_break, cp)) { return switch (uucode.get(.grapheme_break, cp)) {
.extended_pictographic => .extended_pictographic, .extended_pictographic => .extended_pictographic,
.l => .L, .l => .L,
@ -27,6 +22,8 @@ fn graphemeBoundaryClass(cp: u21) GraphemeBoundaryClass {
.zwj => .zwj, .zwj => .zwj,
.spacing_mark => .spacing_mark, .spacing_mark => .spacing_mark,
.regional_indicator => .regional_indicator, .regional_indicator => .regional_indicator,
.emoji_modifier => .emoji_modifier,
.emoji_modifier_base => .extended_pictographic_base,
.zwnj, .zwnj,
.indic_conjunct_break_extend, .indic_conjunct_break_extend,