Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/integrations/terminal/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ export class Terminal extends BaseTerminal {
// VTE must be disabled because it prevents the prompt command from executing
// See https://wiki.gnome.org/Apps/Terminal/VTE
VTE_VERSION: "0",

// Ensure UTF-8 encoding for proper Unicode character display
// This fixes issues with non-ASCII characters (Cyrillic, Chinese, Hindi, etc.)
// being displayed as "?" or diamond symbols in terminal output
LANG: "en_US.UTF-8",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Forcing LANG/LC_ALL to en_US.UTF-8 overrides user locale and can emit locale warnings on systems without that locale. Consider not overriding when already set and prefer a safer default like C.UTF-8; also avoid setting these on Windows where they don't influence the console code page.

LC_ALL: "en_US.UTF-8",
}

// Set Oh My Zsh shell integration if enabled
Expand Down
22 changes: 16 additions & 6 deletions src/integrations/terminal/TerminalProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,21 @@ export class TerminalProcess extends BaseTerminalProcess {
(defaultWindowsShellProfile === null ||
(defaultWindowsShellProfile as string)?.toLowerCase().includes("powershell"))

if (isPowerShell) {
let commandToExecute = command
let commandToExecute = command

// On Windows, prepend chcp 65001 to set UTF-8 code page for proper Unicode support
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] chcp 65001 is executed before every command; the code page persists for the session, so this is redundant overhead. Consider setting it once per terminal session and caching a flag to skip subsequent calls.

// This fixes issues with non-ASCII characters being displayed as "?" or diamond symbols
if (process.platform === "win32") {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] PowerShell detection relies on terminal.integrated.defaultProfile and may not match the active terminal shell at runtime. If mismatched, the PowerShell-style redirection ($null) will fail in CMD. Derive from terminal.state.shell.id/executable (when available) and only fall back to the setting.

if (isPowerShell) {
// PowerShell syntax: use semicolon to chain commands and redirect output to null
commandToExecute = `chcp 65001 > $null ; ${command}`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] chcp 65001 sets the console code page, but PowerShell may still output non‑UTF‑8 without $OutputEncoding being set. Setting both $OutputEncoding and [Console]::OutputEncoding improves reliability for Unicode output.

} else {
// CMD syntax: use && to chain commands and redirect output to nul
commandToExecute = `chcp 65001 > nul && ${command}`
}
}

if (isPowerShell) {
// Only add the PowerShell counter workaround if enabled
if (Terminal.getPowershellCounter()) {
commandToExecute += ` ; "(Roo/PS Workaround: ${this.terminal.cmdCounter++})" > $null`
Expand All @@ -126,12 +138,10 @@ export class TerminalProcess extends BaseTerminalProcess {
if (Terminal.getCommandDelay() > 0) {
commandToExecute += ` ; start-sleep -milliseconds ${Terminal.getCommandDelay()}`
}

terminal.shellIntegration.executeCommand(commandToExecute)
} else {
terminal.shellIntegration.executeCommand(command)
}

terminal.shellIntegration.executeCommand(commandToExecute)

this.isHot = true

// Wait for stream to be available
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ describe("TerminalRegistry", () => {
PAGER,
VTE_VERSION: "0",
PROMPT_EOL_MARK: "",
LANG: "en_US.UTF-8",
LC_ALL: "en_US.UTF-8",
},
})
})
Expand All @@ -69,6 +71,8 @@ describe("TerminalRegistry", () => {
PROMPT_COMMAND: "sleep 0.05",
VTE_VERSION: "0",
PROMPT_EOL_MARK: "",
LANG: "en_US.UTF-8",
LC_ALL: "en_US.UTF-8",
},
})
} finally {
Expand All @@ -91,6 +95,8 @@ describe("TerminalRegistry", () => {
VTE_VERSION: "0",
PROMPT_EOL_MARK: "",
ITERM_SHELL_INTEGRATION_INSTALLED: "Yes",
LANG: "en_US.UTF-8",
LC_ALL: "en_US.UTF-8",
},
})
} finally {
Expand All @@ -112,6 +118,8 @@ describe("TerminalRegistry", () => {
VTE_VERSION: "0",
PROMPT_EOL_MARK: "",
POWERLEVEL9K_TERM_SHELL_INTEGRATION: "true",
LANG: "en_US.UTF-8",
LC_ALL: "en_US.UTF-8",
},
})
} finally {
Expand Down