refactor(desktop): extract terminalLcCtype so the Linux locale rule is testable

The picked fix inlined the platform ternary inside terminalShellEnv(), which
reads process.platform and can only be exercised by booting Electron. Lift it
into a pure terminalLcCtype(env, platform) that takes the platform as data
(root AGENTS.md: never fake the host OS) and pin the contract with one vitest:
Linux reuses LANG, falls back to C.UTF-8, respects an explicit LC_CTYPE; macOS
keeps the bare "UTF-8" it accepts. Red on origin/main (helper absent), green here.
This commit is contained in:
teknium1
2026-09-12 07:06:41 -07:00
committed by Teknium
parent 6f8d975fe7
commit 5b0103ffdc
2 changed files with 33 additions and 4 deletions
+16 -4
View File
@@ -31,6 +31,21 @@ export interface TerminalIpcApi {
disposeAllTerminalSessions: () => void
}
// macOS accepts the bare charset name "UTF-8" as a locale; glibc does not, so
// every Linux pane would print `bash: warning: setlocale: LC_CTYPE: cannot
// change locale (UTF-8)`. Reuse the user's LANG there, else the glibc-guaranteed
// C.UTF-8. Pure: the platform arrives as data so tests need not fake the host.
export function terminalLcCtype(
env: { LANG?: string; LC_CTYPE?: string },
platform: NodeJS.Platform = process.platform
): string {
if (env.LC_CTYPE) {
return env.LC_CTYPE
}
return platform === 'darwin' ? 'UTF-8' : env.LANG || 'C.UTF-8'
}
export function registerTerminalIpc({
isWindows,
findOnPath,
@@ -156,10 +171,7 @@ export function registerTerminalIpc({
delete env.COLORFGBG
env.COLORTERM = 'truecolor'
// macOS accepts the bare charset name "UTF-8"; glibc does not, and bash
// warns: setlocale: LC_CTYPE: cannot change locale (UTF-8). Prefer LANG or C.UTF-8 on Linux.
env.LC_CTYPE =
env.LC_CTYPE || (process.platform === 'darwin' ? 'UTF-8' : env.LANG || 'C.UTF-8')
env.LC_CTYPE = terminalLcCtype(env)
env.TERM = 'xterm-256color'
env.TERM_PROGRAM = 'Hermes'
env.TERM_PROGRAM_VERSION = app.getVersion()
@@ -0,0 +1,17 @@
import assert from 'node:assert/strict'
import { test, vi } from 'vitest'
// terminal-ipc.ts imports the Electron and native PTY modules at module scope;
// neither loads under plain node, and this test only needs the pure locale helper.
vi.mock('electron', () => ({ app: {}, ipcMain: {} }))
vi.mock('node-pty', () => ({ default: {} }))
import { terminalLcCtype } from './terminal-ipc'
test('terminalLcCtype never hands glibc the bare "UTF-8" locale on Linux', () => {
assert.equal(terminalLcCtype({ LANG: 'en_US.UTF-8' }, 'linux'), 'en_US.UTF-8')
assert.equal(terminalLcCtype({}, 'linux'), 'C.UTF-8')
assert.equal(terminalLcCtype({ LANG: 'en_US.UTF-8', LC_CTYPE: 'de_DE.UTF-8' }, 'linux'), 'de_DE.UTF-8')
assert.equal(terminalLcCtype({ LANG: 'en_US.UTF-8' }, 'darwin'), 'UTF-8')
})