Compare commits

...

2 Commits

Author SHA1 Message Date
fufesou
d5568d9188 fix(terminal): windows&macos, charset utf-8
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-29 10:11:25 +08:00
fufesou
1745bab204 fix(terminal): schedule frame before flushing buffered output
Signed-off-by: fufesou <linlong1266@gmail.com>
2026-04-28 20:46:47 +08:00
3 changed files with 66 additions and 5 deletions

View File

@@ -458,6 +458,7 @@ class TerminalModel with ChangeNotifier {
_markViewReady();
}
});
WidgetsBinding.instance.ensureVisualUpdate();
}
void _markViewReady() {

View File

@@ -318,6 +318,35 @@ pub fn get_default_shell() -> String {
std::env::var("COMSPEC").unwrap_or_else(|_| "cmd.exe".to_string())
}
fn utf8_shell_args(shell: &str) -> Vec<String> {
let name = std::path::Path::new(shell)
.file_name()
.and_then(|name| name.to_str())
.unwrap_or(shell)
.to_ascii_lowercase();
if name == "cmd.exe" || name == "cmd" {
return vec!["/K".to_string(), "chcp 65001 >NUL".to_string()];
}
if name == "pwsh.exe" || name == "pwsh" || name == "powershell.exe" {
return vec![
"-NoLogo".to_string(),
"-NoExit".to_string(),
"-Command".to_string(),
"chcp.com 65001 > $null; [Console]::InputEncoding = [System.Text.Encoding]::UTF8; [Console]::OutputEncoding = [System.Text.Encoding]::UTF8".to_string(),
];
}
Vec::new()
}
pub fn configure_utf8_shell_command(shell: &str, cmd: &mut CommandBuilder) {
for arg in utf8_shell_args(shell) {
cmd.arg(arg);
}
}
/// Get the SID of the user from a token.
/// Returns a Vec<u8> containing the SID bytes.
pub fn get_user_sid_from_token(user_token: UserToken) -> Result<Vec<u8>> {
@@ -831,7 +860,8 @@ pub fn run_terminal_helper(args: &[String]) -> Result<()> {
let shell = get_default_shell();
log::debug!("Using shell: {}", shell);
let cmd = CommandBuilder::new(&shell);
let mut cmd = CommandBuilder::new(&shell);
configure_utf8_shell_command(&shell, &mut cmd);
let mut child = pty_pair
.slave
.spawn_command(cmd)

View File

@@ -20,10 +20,11 @@ use std::{
// Windows-specific imports from terminal_helper module
#[cfg(target_os = "windows")]
use super::terminal_helper::{
create_named_pipe_server, encode_helper_message, encode_resize_message,
is_helper_process_running, launch_terminal_helper_with_token, wait_for_pipe_connection,
HelperProcessGuard, OwnedHandle, SendableHandle, WinCloseHandle, WinTerminateProcess,
WinWaitForSingleObject, MSG_TYPE_DATA, PIPE_CONNECTION_TIMEOUT_MS, WIN_WAIT_OBJECT_0,
configure_utf8_shell_command, create_named_pipe_server, encode_helper_message,
encode_resize_message, is_helper_process_running, launch_terminal_helper_with_token,
wait_for_pipe_connection, HelperProcessGuard, OwnedHandle, SendableHandle, WinCloseHandle,
WinTerminateProcess, WinWaitForSingleObject, MSG_TYPE_DATA, PIPE_CONNECTION_TIMEOUT_MS,
WIN_WAIT_OBJECT_0,
};
const MAX_OUTPUT_BUFFER_SIZE: usize = 1024 * 1024; // 1MB per terminal
@@ -133,6 +134,26 @@ fn get_default_shell() -> String {
}
}
#[cfg(target_os = "macos")]
fn locale_value_is_utf8(value: &str) -> bool {
let value = value.to_ascii_uppercase();
value.contains("UTF-8") || value.contains("UTF8")
}
#[cfg(target_os = "macos")]
fn should_force_process_utf8_ctype() -> bool {
if let Ok(value) = std::env::var("LC_ALL") {
return !locale_value_is_utf8(&value);
}
if let Ok(value) = std::env::var("LC_CTYPE") {
return !locale_value_is_utf8(&value);
}
if let Ok(value) = std::env::var("LANG") {
return !locale_value_is_utf8(&value);
}
true
}
pub fn is_service_specified_user(service_id: &str) -> Option<bool> {
get_service(service_id).map(|s| s.lock().unwrap().is_specified_user)
}
@@ -1146,6 +1167,9 @@ impl TerminalServiceProxy {
#[allow(unused_mut)]
let mut cmd = CommandBuilder::new(&shell);
#[cfg(target_os = "windows")]
configure_utf8_shell_command(&shell, &mut cmd);
// macOS-specific terminal configuration
// 1. Use login shell (-l) to load user's shell profile (~/.zprofile, ~/.bash_profile)
// This ensures PATH includes Homebrew paths (/opt/homebrew/bin, /usr/local/bin)
@@ -1166,6 +1190,12 @@ impl TerminalServiceProxy {
};
cmd.env("TERM", term);
log::debug!("Set TERM={} for macOS PTY", term);
if should_force_process_utf8_ctype() {
cmd.env_remove("LC_ALL");
cmd.env("LC_CTYPE", "UTF-8");
log::debug!("Set LC_CTYPE=UTF-8 for macOS PTY");
}
}
// Note: On Windows with user_token, we use helper mode (handle_open_with_helper)