Files
BakNRet/BakNRet/Public/Format-BakNRetPaddedText.ps1
T
Shuery d9d7967e64 feat(tui): 定位写与按列对齐(第一轮第三块)
Format-BakNRetPaddedText:按**列宽**补齐或裁剪,且绝不切开宽字符 —— 剩余宽度差 1 列而下一个字符要占 2 列时,停下用空格补那 1 列。返回的字符串保证恰好 N 列,这条不变式是画边框的基础(按 .Length 补会让边框歪,按 .Length 裁会把汉字劈成半个显示成乱码)。

Write-BakNRetAt:第一道闸门是 [Console]::IsOutputRedirected,**不是** $Host.UI.SupportsVirtualTerminal(实测后者无控制台时仍返回 True,而 SetCursorPosition 会抛异常)。没有控制台就完全不定位、只把文本写出去;坐标越界时跳过定位但仍写出文本 —— 计划任务与窄窗口不该让 TUI 崩掉,只是画得难看一点。颜色走 Write-Host -ForegroundColor(零 VT 依赖)。

验收:断言 10 条(含"裁剪后恰好 5 列且不是 4 个字符"这条关键判据);两版手工输出一致;test.ps1 9/9 全绿。
2026-09-27 15:52:34 +08:00

50 lines
1.7 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function Format-BakNRetPaddedText {
<#
.SYNOPSIS
把文本按**列宽**补齐或裁剪到指定宽度。
.DESCRIPTION
为什么不能用 `.PadRight()` / `.Substring()`:中文 1 个 char 占 2 列。按字符数补,边框会歪;
按字符数裁,会把一个汉字劈成半个、显示成乱码。
这里一律按 Get-BakNRetCellWidth 算,并且**绝不切开一个宽字符** —— 当剩余宽度差 1 列而下一个
字符要占 2 列时,就停下并用空格补上那 1 列。返回的字符串保证**恰好 Width 列**(Width ≤ 0 时
返回空串),这条不变式是画边框与对齐的基础。
#>
param(
[Parameter(Mandatory = $true)][AllowEmptyString()][string]$Text,
[Parameter(Mandatory = $true)][int]$Width
)
if ($Width -le 0) { return '' }
$textWidth = Get-BakNRetCellWidth -Text $Text
if ($textWidth -le $Width) {
return $Text + (' ' * ($Width - $textWidth))
}
# 超宽:按列裁剪,绝不切开代理对或宽字符
$kept = ''
$used = 0
$index = 0
while ($index -lt $Text.Length) {
$chunk = [string]$Text[$index]
$high = [int]$Text[$index]
if ($high -ge 0xD800 -and $high -le 0xDBFF -and ($index + 1) -lt $Text.Length) {
$low = [int]$Text[$index + 1]
if ($low -ge 0xDC00 -and $low -le 0xDFFF) {
$chunk = $Text.Substring($index, 2)
$index++
}
}
$index++
$chunkWidth = Get-BakNRetCellWidth -Text $chunk
if (($used + $chunkWidth) -gt $Width) { break }
$kept += $chunk
$used += $chunkWidth
}
return $kept + (' ' * ($Width - $used))
}