mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Update calculation of char width to respect CJK chars correctly (#11262)
This commit is contained in:
@@ -2781,7 +2781,36 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
}
|
||||
|
||||
return str.Length - offset - escapeSequenceAdjustment;
|
||||
int length = 0;
|
||||
foreach (char c in str)
|
||||
{
|
||||
length += LengthInBufferCells(c);
|
||||
}
|
||||
|
||||
return length - offset - escapeSequenceAdjustment;
|
||||
}
|
||||
|
||||
internal static int LengthInBufferCells(char c)
|
||||
{
|
||||
// The following is based on http://www.cl.cam.ac.uk/~mgk25/c/wcwidth.c
|
||||
// which is derived from https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
|
||||
bool isWide = c >= 0x1100 &&
|
||||
(c <= 0x115f || /* Hangul Jamo init. consonants */
|
||||
c == 0x2329 || c == 0x232a ||
|
||||
((uint)(c - 0x2e80) <= (0xa4cf - 0x2e80) &&
|
||||
c != 0x303f) || /* CJK ... Yi */
|
||||
((uint)(c - 0xac00) <= (0xd7a3 - 0xac00)) || /* Hangul Syllables */
|
||||
((uint)(c - 0xf900) <= (0xfaff - 0xf900)) || /* CJK Compatibility Ideographs */
|
||||
((uint)(c - 0xfe10) <= (0xfe19 - 0xfe10)) || /* Vertical forms */
|
||||
((uint)(c - 0xfe30) <= (0xfe6f - 0xfe30)) || /* CJK Compatibility Forms */
|
||||
((uint)(c - 0xff00) <= (0xff60 - 0xff00)) || /* Fullwidth Forms */
|
||||
((uint)(c - 0xffe0) <= (0xffe6 - 0xffe0)));
|
||||
|
||||
// We can ignore these ranges because .Net strings use surrogate pairs
|
||||
// for this range and we do not handle surrogage pairs.
|
||||
// (c >= 0x20000 && c <= 0x2fffd) ||
|
||||
// (c >= 0x30000 && c <= 0x3fffd)
|
||||
return 1 + (isWide ? 1 : 0);
|
||||
}
|
||||
|
||||
#if !UNIX
|
||||
@@ -2950,33 +2979,6 @@ namespace Microsoft.PowerShell
|
||||
|
||||
#endregion helper
|
||||
|
||||
#region
|
||||
|
||||
internal static int LengthInBufferCells(char c)
|
||||
{
|
||||
// The following is based on http://www.cl.cam.ac.uk/~mgk25/c/wcwidth.c
|
||||
// which is derived from https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
|
||||
|
||||
bool isWide = c >= 0x1100 &&
|
||||
(c <= 0x115f || /* Hangul Jamo init. consonants */
|
||||
c == 0x2329 || c == 0x232a ||
|
||||
(c >= 0x2e80 && c <= 0xa4cf &&
|
||||
c != 0x303f) || /* CJK ... Yi */
|
||||
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
|
||||
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
|
||||
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
|
||||
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
|
||||
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
|
||||
(c >= 0xffe0 && c <= 0xffe6));
|
||||
// We can ignore these ranges because .Net strings use surrogate pairs
|
||||
// for this range and we do not handle surrogage pairs.
|
||||
// (c >= 0x20000 && c <= 0x2fffd) ||
|
||||
// (c >= 0x30000 && c <= 0x3fffd)
|
||||
return 1 + (isWide ? 1 : 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendInput
|
||||
|
||||
internal static void MimicKeyPress(INPUT[] inputs)
|
||||
|
||||
@@ -29,7 +29,14 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
|
||||
|
||||
internal virtual int Length(string str, int offset)
|
||||
{
|
||||
return str.Length - offset;
|
||||
int length = 0;
|
||||
|
||||
foreach (char c in str)
|
||||
{
|
||||
length += LengthInBufferCells(c);
|
||||
}
|
||||
|
||||
return length - offset;
|
||||
}
|
||||
|
||||
internal virtual int Length(char character) { return 1; }
|
||||
@@ -58,6 +65,29 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
|
||||
|
||||
#region Helpers
|
||||
|
||||
protected static int LengthInBufferCells(char c)
|
||||
{
|
||||
// The following is based on http://www.cl.cam.ac.uk/~mgk25/c/wcwidth.c
|
||||
// which is derived from https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
|
||||
bool isWide = c >= 0x1100 &&
|
||||
(c <= 0x115f || /* Hangul Jamo init. consonants */
|
||||
c == 0x2329 || c == 0x232a ||
|
||||
((uint)(c - 0x2e80) <= (0xa4cf - 0x2e80) &&
|
||||
c != 0x303f) || /* CJK ... Yi */
|
||||
((uint)(c - 0xac00) <= (0xd7a3 - 0xac00)) || /* Hangul Syllables */
|
||||
((uint)(c - 0xf900) <= (0xfaff - 0xf900)) || /* CJK Compatibility Ideographs */
|
||||
((uint)(c - 0xfe10) <= (0xfe19 - 0xfe10)) || /* Vertical forms */
|
||||
((uint)(c - 0xfe30) <= (0xfe6f - 0xfe30)) || /* CJK Compatibility Forms */
|
||||
((uint)(c - 0xff00) <= (0xff60 - 0xff00)) || /* Fullwidth Forms */
|
||||
((uint)(c - 0xffe0) <= (0xffe6 - 0xffe0)));
|
||||
|
||||
// We can ignore these ranges because .Net strings use surrogate pairs
|
||||
// for this range and we do not handle surrogage pairs.
|
||||
// (c >= 0x20000 && c <= 0x2fffd) ||
|
||||
// (c >= 0x30000 && c <= 0x3fffd)
|
||||
return 1 + (isWide ? 1 : 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a string and a number of display cells, it computes how many
|
||||
/// characters would fit starting from the beginning or end of the string.
|
||||
|
||||
@@ -159,4 +159,24 @@ Describe "Format-List DRT basic functionality" -Tags "CI" {
|
||||
$result | Should -Match "Name\s*:\s*test.txt"
|
||||
$result | Should -Match "Length\s*:\s*5"
|
||||
}
|
||||
|
||||
It "Format-List should work with double byte wide chars" {
|
||||
$obj = [pscustomobject]@{
|
||||
"哇" = "62";
|
||||
"dbda" = "KM";
|
||||
"消息" = "千"
|
||||
}
|
||||
|
||||
$expected = @"
|
||||
|
||||
哇 : 62
|
||||
dbda : KM
|
||||
消息 : 千
|
||||
|
||||
|
||||
|
||||
"@
|
||||
|
||||
$obj | Format-List | Out-String | Should -BeExactly $expected
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,4 +812,23 @@ A Name B
|
||||
$output = [pscustomobject] @{ one = 1 } | Format-Table @{ l='one'; e='one'; width=10; alignment='center' } | Out-String
|
||||
$output.Replace("`r","").Replace(" ",".").Replace("`n","^") | Should -BeExactly $expectedTable.Replace("`r","").Replace(" ",".").Replace("`n","^")
|
||||
}
|
||||
|
||||
It "Should be formatted correctly with double byte wide chars" {
|
||||
$obj = [pscustomobject]@{
|
||||
"哇" = "62";
|
||||
"dbda" = "KM";
|
||||
"消息" = "千"
|
||||
}
|
||||
|
||||
$expected = @"
|
||||
|
||||
哇 dbda 消息
|
||||
-- ---- ----
|
||||
62 KM 千
|
||||
|
||||
|
||||
"@
|
||||
|
||||
$obj | Format-Table | Out-String | Should -BeExactly $expected
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user