feat(tui): 控制台列宽表(第一轮第一块)
整个 TUI 的地基:位置、对齐、边框都靠它。而它算错了**不会报错** —— 表现只是菜单右边框歪一点、光标偏一列,所以每条边界都在断言里钉住。 为什么必须自己算:.Length 是 UTF-16 code unit 的个数(汉字 1 个 char、2 列);而 $Host.UI.RawUI.LengthInBufferCells 在 PowerShell 7 上对、在 5.1 上错(实测 中文 返回 2、字体边框字符 返回 6),且不抛错 —— 这种"一边对一边错"的 API 比两边都错更危险。 表里三个边界是实测踩过的:半角片假名 U+FF61–FF9F 是 1 列(不能划进全角区);全角拉丁 U+FF00–FF60 是 2 列;emoji 是代理对,按一个码点算。 验收:断言 8 条(含空串与控制字符);test.ps1 9/9 全绿(5.1 与 7)。
This commit is contained in:
1 parent
60f2ae3e0f
commit
8a0924330a
23 files changed
+86
-19
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# ZERO-DEPENDENCY PowerShell TUI PROTOTYPE (works on 5.1 and 7.x)
|
# ZERO-DEPENDENCY PowerShell TUI PROTOTYPE (works on 5.1 and 7.x)
|
||||||
# ASCII-only source so 5.1 (which reads non-BOM files as ANSI) parses it.
|
# ASCII-only source so 5.1 (which reads non-BOM files as ANSI) parses it.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile)
|
param([Parameter(Mandatory=$true)][string]$OutFile)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s) }
|
function L($s) { $lines.Add($s) }
|
||||||
function MK([int[]]$cp) { -join ($cp | ForEach-Object { [char]$_ }) }
|
function MK([int[]]$cp) { -join ($cp | ForEach-Object { [char]$_ }) }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$out = Join-Path $env:TEMP 'console-probe.txt'
|
$out = Join-Path $env:TEMP 'console-probe.txt'
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s) }
|
function L($s) { $lines.Add($s) }
|
||||||
$src = @"
|
$src = @"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile)
|
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile)
|
||||||
$o = New-Object System.Collections.Specialized.OrderedDictionary
|
$o = New-Object System.Collections.Specialized.OrderedDictionary
|
||||||
$src = @"
|
$src = @"
|
||||||
using System;
|
using System;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile, [int]$WatchSeconds = 3)
|
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile, [int]$WatchSeconds = 3)
|
||||||
$o = New-Object System.Collections.Specialized.OrderedDictionary
|
$o = New-Object System.Collections.Specialized.OrderedDictionary
|
||||||
$src = @"
|
$src = @"
|
||||||
using System;
|
using System;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
L ("PSVersion: " + $PSVersionTable.PSVersion + " IsOutputRedirected=" + [Console]::IsOutputRedirected)
|
L ("PSVersion: " + $PSVersionTable.PSVersion + " IsOutputRedirected=" + [Console]::IsOutputRedirected)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 5)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 5)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
function Braino([string]$m) { return $null }
|
function Braino([string]$m) { return $null }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 5)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 5)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version + " Redirected=" + [Console]::IsOutputRedirected)
|
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version + " Redirected=" + [Console]::IsOutputRedirected)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s) }
|
function L($s) { $lines.Add($s) }
|
||||||
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version)
|
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 4)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 4)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version)
|
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$outFile = $args[0]
|
$outFile = $args[0]
|
||||||
if (-not $outFile) { $outFile = Join-Path $env:TEMP 'noconsole-probe.txt' }
|
if (-not $outFile) { $outFile = Join-Path $env:TEMP 'noconsole-probe.txt' }
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); Write-Host $s }
|
function L($s) { $lines.Add($s); Write-Host $s }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 5)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 5)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version + " Redirected=" + [Console]::IsOutputRedirected)
|
L ("PSVersion: " + $PSVersionTable.PSVersion + " CLR " + [System.Environment]::Version + " Redirected=" + [Console]::IsOutputRedirected)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 6)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 6)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
function Asm([string]$n) { return [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq $n } | Select-Object -First 1 }
|
function Asm([string]$n) { return [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq $n } | Select-Object -First 1 }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
L ("PSVersion: " + $PSVersionTable.PSVersion)
|
L ("PSVersion: " + $PSVersionTable.PSVersion)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 6)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 6)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
function Asm([string]$n) { return [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq $n } | Select-Object -First 1 }
|
function Asm([string]$n) { return [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq $n } | Select-Object -First 1 }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 6)
|
param([Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$true)][string]$Work, [int]$HoldSeconds = 6)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
function L($s) { $lines.Add($s); [System.IO.File]::WriteAllLines($OutFile, $lines, (New-Object System.Text.UTF8Encoding($false))) }
|
||||||
function Asm([string]$n) { return [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq $n } | Select-Object -First 1 }
|
function Asm([string]$n) { return [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq $n } | Select-Object -First 1 }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$OutFile)
|
param([Parameter(Mandatory=$true)][string]$OutFile)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s) }
|
function L($s) { $lines.Add($s) }
|
||||||
L ("PSVersion: " + $PSVersionTable.PSVersion + " PSEdition: " + $PSVersionTable.PSEdition)
|
L ("PSVersion: " + $PSVersionTable.PSVersion + " PSEdition: " + $PSVersionTable.PSEdition)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile, [int]$WatchSeconds = 2)
|
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile, [int]$WatchSeconds = 2)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s) }
|
function L($s) { $lines.Add($s) }
|
||||||
$zh = [string]::Concat([char]0x4E2D, [char]0x6587)
|
$zh = [string]::Concat([char]0x4E2D, [char]0x6587)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile, [int]$WatchSeconds = 2)
|
param([Parameter(Mandatory=$true)][string]$HostLabel, [Parameter(Mandatory=$true)][string]$OutFile, [int]$WatchSeconds = 2)
|
||||||
$lines = New-Object System.Collections.Generic.List[string]
|
$lines = New-Object System.Collections.Generic.List[string]
|
||||||
function L($s) { $lines.Add($s) }
|
function L($s) { $lines.Add($s) }
|
||||||
function MK([int[]]$cp) { -join ($cp | ForEach-Object { [char]$_ }) }
|
function MK([int[]]$cp) { -join ($cp | ForEach-Object { [char]$_ }) }
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
CompatiblePSEditions = @('Desktop', 'Core')
|
CompatiblePSEditions = @('Desktop', 'Core')
|
||||||
|
|
||||||
FunctionsToExport = @(
|
FunctionsToExport = @(
|
||||||
|
'Get-BakNRetCellWidth',
|
||||||
'Write-BakNRetRunSummary',
|
'Write-BakNRetRunSummary',
|
||||||
'Save-BakNRetItemRecord',
|
'Save-BakNRetItemRecord',
|
||||||
'New-BakNRetItemRecord',
|
'New-BakNRetItemRecord',
|
||||||
|
|||||||
@@ -144,7 +144,10 @@
|
|||||||
|
|
||||||
. (Join-Path $PSScriptRoot 'Public\Write-BakNRetRunSummary.ps1')
|
. (Join-Path $PSScriptRoot 'Public\Write-BakNRetRunSummary.ps1')
|
||||||
|
|
||||||
|
. (Join-Path $PSScriptRoot 'Public\Get-BakNRetCellWidth.ps1')
|
||||||
|
|
||||||
Export-ModuleMember -Function @(
|
Export-ModuleMember -Function @(
|
||||||
|
'Get-BakNRetCellWidth',
|
||||||
'Write-BakNRetRunSummary',
|
'Write-BakNRetRunSummary',
|
||||||
'Save-BakNRetItemRecord',
|
'Save-BakNRetItemRecord',
|
||||||
'New-BakNRetItemRecord',
|
'New-BakNRetItemRecord',
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
function Get-BakNRetCellWidth {
|
||||||
|
<#>
|
||||||
|
.SYNOPSIS
|
||||||
|
算一个字符串在控制台上占多少**列**(不是多少个字符)。
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
为什么必须自己算:
|
||||||
|
* `[string].Length` 是 UTF-16 code unit 的个数 —— 一个汉字是 1 个 char 但占 2 列;
|
||||||
|
* `$Host.UI.RawUI.LengthInBufferCells` 在 PowerShell 7 上是对的,但在 **Windows
|
||||||
|
PowerShell 5.1 上会给出错的答案**:实测 `'中文'` 返回 2(把宽字符当单列)、字体边框字符
|
||||||
|
返回 6(把 1 列的当宽字符)。更糟的是它**不报错** —— 算错的表现只是菜单右边框歪一点、
|
||||||
|
光标定位偏一列,而那种错没人会当场发现,所以只能用断言钉住。
|
||||||
|
|
||||||
|
表里三个容易搞错的边界(断言里都有):
|
||||||
|
* 半角片假名 U+FF61–FF9F 是**半角**(1 列),不能划进全角区;
|
||||||
|
* 全角拉丁(U+FF00–FF60)是 2 列;
|
||||||
|
* emoji 是代理对(两个 char、一个码点),按一个码点算。
|
||||||
|
#>
|
||||||
|
param([Parameter(Mandatory = $true)][AllowEmptyString()][string]$Text)
|
||||||
|
|
||||||
|
# East-Asian-Wide 区。半角片假名(U+FF61–FF9F)刻意不在表里。
|
||||||
|
$wideRanges = @(
|
||||||
|
@(0x1100, 0x115F), @(0x2E80, 0x303E), @(0x3041, 0x33FF), @(0x3400, 0x4DBF),
|
||||||
|
@(0x4E00, 0x9FFF), @(0xA000, 0xA4CF), @(0xAC00, 0xD7A3), @(0xF900, 0xFAFF),
|
||||||
|
@(0xFE30, 0xFE6F), @(0xFF00, 0xFF60), @(0xFFE0, 0xFFE6),
|
||||||
|
@(0x1F300, 0x1F64F), @(0x1F900, 0x1F9FF), @(0x20000, 0x2FFFD), @(0x30000, 0x3FFFD)
|
||||||
|
)
|
||||||
|
|
||||||
|
$width = 0
|
||||||
|
$index = 0
|
||||||
|
while ($index -lt $Text.Length) {
|
||||||
|
$codePoint = [int]$Text[$index]
|
||||||
|
# 代理对:合成一个码点,并按一个字符推进
|
||||||
|
if ($codePoint -ge 0xD800 -and $codePoint -le 0xDBFF -and ($index + 1) -lt $Text.Length) {
|
||||||
|
$low = [int]$Text[$index + 1]
|
||||||
|
if ($low -ge 0xDC00 -and $low -le 0xDFFF) {
|
||||||
|
$codePoint = 0x10000 + (($codePoint - 0xD800) * 0x400) + ($low - 0xDC00)
|
||||||
|
$index++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$index++
|
||||||
|
# 控制字符不占显示宽度
|
||||||
|
if ($codePoint -lt 0x20 -or $codePoint -eq 0x7F) { continue }
|
||||||
|
$cell = 1
|
||||||
|
foreach ($range in $wideRanges) {
|
||||||
|
if ($codePoint -ge $range[0] -and $codePoint -le $range[1]) { $cell = 2; break }
|
||||||
|
}
|
||||||
|
$width += $cell
|
||||||
|
}
|
||||||
|
return $width
|
||||||
|
}
|
||||||
@@ -1420,6 +1420,18 @@ Test-Case '结果汇总:分类列出成功/跳过/失败,带原因与失败
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test-Case '控制台列宽:中文 2 列、半角片假名 1 列、emoji 按一个码点算、控制字符 0 列' {
|
||||||
|
# 这张表算错了不会报错,只会让菜单右边框歪一点 —— 所以每条边界都钉一个断言。
|
||||||
|
Assert-Equal 8 (Get-BakNRetCellWidth -Text '12345678') '8 个 ASCII = 8 列'
|
||||||
|
Assert-Equal 4 (Get-BakNRetCellWidth -Text '中文') '2 个汉字 = 4 列(.Length 是 2)'
|
||||||
|
Assert-Equal 3 (Get-BakNRetCellWidth -Text ([string]::new([char[]]@(0x250C, 0x2500, 0x2510)))) '字体边框字符 = 1 列/个(5.1 的 LengthInBufferCells 在这里会返回 6)'
|
||||||
|
Assert-Equal 4 (Get-BakNRetCellWidth -Text ([string]::new([char[]]@(0xFF21, 0xFF22)))) '全角拉丁 = 2 列/个'
|
||||||
|
Assert-Equal 2 (Get-BakNRetCellWidth -Text ([string]::new([char[]]@(0xFF71, 0xFF72)))) '半角片假名 = 1 列/个(不能划进全角区)'
|
||||||
|
Assert-Equal 2 (Get-BakNRetCellWidth -Text ([char]::ConvertFromUtf32(0x1F600))) 'emoji = 一个码点 2 列'
|
||||||
|
Assert-Equal 0 (Get-BakNRetCellWidth -Text ([string]::new([char[]]@(9, 10)))) '控制字符 = 0 列'
|
||||||
|
Assert-Equal 0 (Get-BakNRetCellWidth -Text '') '空串 = 0 列'
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
Remove-Item -LiteralPath $itemSandbox -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -LiteralPath $itemSandbox -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
|||||||
Reference in new issue
Block a user