param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile, [int]$WatchSeconds = 2) $lines = New-Object System.Collections.Generic.List[string] function L($s) { $lines.Add($s) } function MK([int[]]$cp) { -join ($cp | ForEach-Object { [char]$_ }) } $zh2 = MK @(0x4E2D, 0x6587) # 2 CJK $zh4 = MK @(0x4E2D, 0x6587, 0x5907, 0x4EFD) # 4 CJK $ascii8 = '12345678' $emoji = [char]::ConvertFromUtf32(0x1F600) $box3 = MK @(0x250C, 0x2500, 0x2510) # box drawing light $fullw = MK @(0xFF21, 0xFF22) # fullwidth latin A B $halfk = MK @(0xFF71, 0xFF72) # halfwidth katakana L "===== DISPLAY-WIDTH PROBE [$HostLabel] =====" L ("PSVersion : " + $PSVersionTable.PSVersion) L ("PSEdition : " + $PSVersionTable.PSEdition) L ("IsOutputRedirected : " + [Console]::IsOutputRedirected) L ("Console.OutputEncoding : " + [Console]::OutputEncoding.WebName + " (CP " + [Console]::OutputEncoding.CodePage + ")") L ("`$OutputEncoding : " + $OutputEncoding.WebName) try { L ("Console.WindowWidth : " + [Console]::WindowWidth) } catch { L ("Console.WindowWidth THREW") } try { L ("RawUI.WindowSize : " + $Host.UI.RawUI.WindowSize.Width + 'x' + $Host.UI.RawUI.WindowSize.Height) } catch { L ("RawUI.WindowSize THREW") } L "" L "--- .Length / Measure-Object -Character / CODEPOINTS ---" $cases = @( ,@('8 ASCII ', $ascii8) ,@('2 CJK ', $zh2) ,@('4 CJK ', $zh4) ,@('3 boxdraw ', $box3) ,@('1 emoji ', $emoji) ,@('2 fullwidth', $fullw) ,@('2 halfkana ', $halfk) ) foreach ($c in $cases) { $nm = $c[0]; $s = $c[1] $s = [string]$s $cps = ($s.ToCharArray() | ForEach-Object { 'U+{0:X4}' -f [int]$_ }) -join ' ' L (" $nm .Length=" + $s.Length + " Measure-Object-Character=" + (($s | Measure-Object -Character).Characters) + " cps=[$cps]") } L "" L "--- BUILT-IN DISPLAY-WIDTH FUNCTION? ---" $found = @() foreach ($c in (Get-Command -CommandType Cmdlet,Function -ErrorAction SilentlyContinue)) { if ($c.Name -match 'Width|Wide') { $found += ($c.Name + '(' + $c.CommandType + '/' + $c.Source + ')') } } L (" commands matching *Width*|*Wide* : " + $(if ($found.Count) { $found -join ', ' } else { 'NONE' })) L (" [System.Globalization.StringInfo]::ParseCombiningCharacters(2CJK).Count = " + [System.Globalization.StringInfo]::ParseCombiningCharacters($zh2).Count + " (text elements, not columns)") L "" L "--- MEASURED COLUMNS (cursor teleport to column 0 of row 12, write, read CursorLeft) ---" $skip = $false try { if ([Console]::IsOutputRedirected) { L " SKIPPED (redirected)"; $skip = $true } } catch { $skip = $true } if (-not $skip) { $row = 12 if ([Console]::BufferWidth -lt 40) { $row = 5 } $vis = [Console]::CursorVisible try { [Console]::CursorVisible = $false } catch {} foreach ($c in $cases) { $nm = $c[0]; $s = [string]$c[1] try { [Console]::SetCursorPosition(0, $row) [Console]::Write((' ' * 60)) [Console]::SetCursorPosition(0, $row) [Console]::Write($s) $col = [Console]::CursorLeft L (" write [$nm] at col 0 -> CursorLeft=" + $col + " => title column width = " + $col + " (.Length=" + $s.Length + ")") } catch { L (" write [$nm] THREW: " + $_.Exception.Message) } } try { [Console]::SetCursorPosition(0, $row); [Console]::Write((' ' * 60)); [Console]::SetCursorPosition(0, $row); [Console]::Write($zh2 + 'X'); [Console]::SetCursorPosition(0, $row + 1) } catch {} try { [Console]::CursorVisible = $vis } catch {} } [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) Write-Host ("[width-probe2 {0}] wrote {1}" -f $HostLabel, $OutFile) -ForegroundColor Yellow if ($WatchSeconds -gt 0) { Start-Sleep -Seconds $WatchSeconds }