Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] compat: give conjoining Hangul jamo zero Unicode 9 width
- X-seq: zsh-workers 55230
- From: Link Kim <link@xxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: [PATCH] compat: give conjoining Hangul jamo zero Unicode 9 width
- Date: Wed, 28 Oct 2026 03:02:37 -0500
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:to:subject:message-id:date:from :mime-version:dkim-signature; bh=1IewfQBHg212nH3wVRaOzdTtzJbeikPjcedEvMyJCRM=; fh=SbTlPuNNxBzTkRlwWtqw/TXBY0HvGvtE97RpPp3sJPM=; b=syXiFTrBr6hVPOL37EqGEsKNwzXoTuMGK4hQoySLtcn3Vz0S9qVPSYdfbiGlyi+Ewp UwIBfeRnMEQfxmDVRMT6xuvNR3uL+k80NQQ6tOMjU3uyhhTmE5SJlz6HoNyLMpNJi7qn JJfMIpwjrkccvvs/4jERB4VLOvDnQa4NWRjY0YaXqIh2pa8UO8F4+ZvCrr+q1wJ9KmSz 60JfCE5JXkl9DuQ1optPS+Up45LX4uJbCWqZ8rVSizQhAZgUmy4amjc2KEb+Yjvbr807 ytikwiZjDSgFd6XQvlYgL0iVy0nyMO2mGPU+kNsOeqvL0qb8crOnCthb08qyH/wXIbiB fgcw==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1793174559; cv=none; d=google.com; s=arc-20260327; b=smQrkOipW2q5XbmU4rP+dlGkBgt1uqKuKS4hy1wJWRK3lXxOMlOcAzfeajTZtZGMd3 rkLM6dGKq37SnS+dnckJ36vWAqH9YNqbBPpHH2XerC9iw0rEYuuqfuiXIcgqO23XKyfC WGKdfjgqbumCcY0ZpV6MQwxHCCzEufCkb+saf37/ELkvNXVfCbHw9wboE6lIuTnUhEo6 BG/Bp3U35zaQE1OGvn1L4Dlqotwh0oSBplQZjhJX2IW5OuKtF8gtsSnozG91Y3v+MA4S 7iiYOb7S0FnJTBaR0XpU87JRt4P4miAiktBwHC7w+S5pePMMQy1mgdX4omMh6TL8Fdq3 W2GA==
- Archived-at: <https://zsh.org/workers/55230>
- List-id: <zsh-workers.zsh.org>
From: Hangil Kim <uoneway@xxxxxxxxx>
With --enable-unicode9, wcwidth9() assigns width 1 to medial and final
Hangul jamo. An NFD syllable consequently occupies more columns in ZLE's
model than it does in the terminal. For example, the five code points
U+1103 U+1162 U+1107 U+1169 U+11AB occupy four terminal columns, but zsh
counts seven. Recalling and clearing such a history entry repeatedly
moves the input into the prompt and leaves stale characters behind.
Return zero for positive widths in the Hangul medial/final jamo ranges,
including Jamo Extended-B. Preserve negative widths for unassigned code
points and retain the existing widths of leading and compatibility jamo.
Add Unicode 9 regression tests for NFC/NFD padding, assigned jamo range
boundaries, and the non-printable classification of reserved Extended-B
code points. Gate these table-specific expectations on --enable-unicode9
rather than prescribing the widths supplied by an arbitrary system libc.
---
Based on upstream master 7e57394d42e20160158364929c7bf68f7969f72b.
Minimal non-interactive reproducer, after configuring with
--enable-multibyte --enable-unicode9 and building Src/zsh:
LC_ALL=en_US.UTF-8 ./Src/zsh -f <<'EOF'
setopt multibyte
s=$'\u1103\u1162\u1107\u1169\u11ab'
p=${(ml:8::.:)s}
print ${#${p%%$s}}
EOF
Expected: 4 padding columns. Before the patch: 1.
For an interactive reproduction, start zsh -f in a UTF-8 locale, enable
combiningchars, and run:
print -s -- $'echo "/tmp/\u1103\u1162\u1107\u1169\u11ab.xlsx"'
Recall and clear that history entry with Up/Down repeatedly. With the
unpatched Unicode 9 build, the input drifts three columns into the prompt
on each cycle. The patched build remains aligned.
Validation on macOS 27.2 arm64:
- Added D07multibyte cases reproduce the width errors before the fix.
- make TESTNUM=D07 check passes with --enable-unicode9.
- The same suite passes with --disable-unicode9; the three new tests
are skipped because they specifically exercise the built-in table.
- An isolated real ZLE/PTY replay through Herdr 0.9.3's VT core passes
24/24 cursor checks and preserves all 3/3 history command byte strings.
- Direct u9_wcwidth checks confirm the reserved Extended-B code points
U+D7C7, U+D7CA, U+D7FC, and U+D7FF still return -1.
Please Cc me on replies.
Src/compat.c | 14 ++++++++---
Test/D07multibyte.ztst | 56 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/Src/compat.c b/Src/compat.c
index 918d98e..38b3f0a 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -759,10 +759,16 @@ strtoul(nptr, endptr, base)
int
u9_wcwidth(wchar_t ucs)
{
- int w = wcwidth9(ucs);
- if (w < -1)
- return 1;
- return w;
+ int w = wcwidth9(ucs);
+
+ /* Medial and final Hangul jamo add no columns to a syllable.
+ * Preserve negative widths for unassigned code points. */
+ if (w > 0 && ((ucs >= 0x1160 && ucs <= 0x11ff) ||
+ (ucs >= 0xd7b0 && ucs <= 0xd7ff)))
+ return 0;
+ if (w < -1)
+ return 1;
+ return w;
}
/**/
diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index 28cb9d9..43ecc63 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -349,6 +349,62 @@
0:Multibyte characters in printf widths
> főo
+ [[ $(<$ZTST_testdir/../config.h) == *'#define ENABLE_UNICODE9 1'* ]] ||
+ ZTST_skip='requires --enable-unicode9'
+ () {
+ local hangul padded
+ for hangul in $'\ub300\ubcf8' $'\u1103\u1162\u1107\u1169\u11ab'; do
+ padded=${(ml:8::.:)hangul}
+ print ${#${padded%%$hangul}}
+ padded=${(mr:8::.:)hangul}
+ print ${#${padded#$hangul}}
+ done
+ }
+0:NFC and decomposed Hangul have equal widths with --enable-unicode9
+>4
+>4
+>4
+>4
+
+ [[ $(<$ZTST_testdir/../config.h) == *'#define ENABLE_UNICODE9 1'* ]] ||
+ ZTST_skip='requires --enable-unicode9'
+ () {
+ local jamo padded
+ for jamo in $'\u1100' $'\u115f' $'\u1160' $'\u1161' \
+ $'\u11a8' $'\u11ff' $'\ud7b0' $'\ud7c6' \
+ $'\ud7cb' $'\ud7fb' $'\u3131' $'\uffa1'; do
+ padded=${(ml:4::.:)jamo}
+ print $(( 4 - ${#${padded%%$jamo}} ))
+ done
+ }
+0:Only medial and final Hangul jamo have zero display width
+>2
+>2
+>0
+>0
+>0
+>0
+>0
+>0
+>0
+>0
+>2
+>1
+
+ [[ $(<$ZTST_testdir/../config.h) == *'#define ENABLE_UNICODE9 1'* ]] ||
+ ZTST_skip='requires --enable-unicode9'
+ () {
+ local unassigned
+ for unassigned in $'\ud7c7' $'\ud7ca' $'\ud7fc' $'\ud7ff'; do
+ print -r -- ${(q+)unassigned}
+ done
+ }
+0:Unassigned Hangul Jamo Extended-B code points remain non-printable
+>$'\ud7c7'
+>$'\ud7ca'
+>$'\ud7fc'
+>$'\ud7ff'
+
# TODO?: POSIX requires that printf should always compute width and
# precision of '%s' conversion in bytes, while zsh computes them in
# characters if multi-byte locale is in use.
--
2.54.0 (Apple Git-157)
Messages sorted by:
Reverse Date,
Date,
Thread,
Author