fix(settings): emit Windows font family names as UTF-8 (#12602)
* fix(settings): emit Windows font family names as UTF-8 Windows PowerShell 5.1 can write localized font names with the console code page while Node always decodes stdout as UTF-8, which garbles Korean and other non-ASCII family names in the font picker. Force UTF-8 OutputEncoding before enumerating InstalledFontCollection (#12590). * test(settings): assert UTF-8 pin precedes Windows font enumeration Lock script order so OutputEncoding is set before InstalledFontCollection enumeration, preventing a silent regression of the mojibake fix. * refactor(settings): cut the Windows font UTF-8 pin to the standard shape `$OutputEncoding` only governs bytes piped to a native executable's stdin; this script pipes to ForEach-Object, so it was inert. Drop it, and drop the script-builder export whose only consumer was a test — the one-shot `-Command` shape now matches windows-foreground-process-rows and ssh-browse, while the BOM-less `UTF8Encoding::new($false)` spelling matches powershell-osc133-bootstrap and antigravity/hook-service. The test reaches the script through the public listSystemFontFamilies path and pins the assignment as the script's first statement, so it fails on removal, on a stdout write above it, and on a swapped encoding. --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
This commit is contained in:
parent
3ec48a74d5
commit
371cc26ca1
|
|
@ -67,6 +67,25 @@ describe('listSystemFontFamilies', () => {
|
|||
killMock.mockReset()
|
||||
})
|
||||
|
||||
it('sets UTF-8 stdout encoding as the first statement of the Windows font script', async () => {
|
||||
await withPlatform('win32', async () => {
|
||||
execFileMock.mockImplementation((_cmd, _args, _opts, cb) => {
|
||||
cb(null, 'Consolas\n')
|
||||
return { kill: killMock }
|
||||
})
|
||||
const { listSystemFontFamilies } = await import('./system-fonts')
|
||||
await listSystemFontFamilies()
|
||||
|
||||
const args = (execFileMock.mock.calls[0]?.[1] ?? []) as string[]
|
||||
const script = args[args.indexOf('-Command') + 1] ?? ''
|
||||
// Why: match the whole statement, not a substring — anything emitted above it
|
||||
// still leaves in the OEM code page, and a swapped encoding must not slip by.
|
||||
expect(script.trim().split(/\r?\n/)[0]).toBe(
|
||||
'[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('falls back when the platform font command never exits', async () => {
|
||||
vi.useFakeTimers()
|
||||
execFileMock.mockReturnValue({ kill: killMock })
|
||||
|
|
|
|||
|
|
@ -77,7 +77,10 @@ function listLinuxFonts(): Promise<string[]> {
|
|||
}
|
||||
|
||||
function listWindowsFonts(): Promise<string[]> {
|
||||
// Why: PowerShell 5.1 emits redirected stdout in the OEM code page; pin UTF-8
|
||||
// before the first name is written or localized families arrive as mojibake (#12590).
|
||||
const script = `
|
||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
$fonts = New-Object System.Drawing.Text.InstalledFontCollection
|
||||
$fonts.Families | ForEach-Object { $_.Name }
|
||||
|
|
|
|||
Loading…
Reference in New Issue