Enable Windows terminal VT output
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s

This commit is contained in:
DuProcess
2026-07-16 20:39:07 -04:00
parent 9969971605
commit 8fae0d8bf9
+68 -3
View File
@@ -10232,15 +10232,71 @@ fn save_cache(path: &std::path::Path, cred: &CachedCredential) -> Result<()> {
Ok(()) Ok(())
} }
struct RawMode; struct RawMode {
#[cfg(windows)]
console_modes: WindowsConsoleModeGuard,
}
impl RawMode { impl RawMode {
fn enter() -> Result<Self> { fn enter() -> Result<Self> {
flush_local_terminal_input(); flush_local_terminal_input();
enable_raw_mode()?; enable_raw_mode()?;
let raw = Self {
#[cfg(windows)]
console_modes: WindowsConsoleModeGuard::enter(),
};
flush_local_terminal_input(); flush_local_terminal_input();
drain_local_terminal_input(); drain_local_terminal_input();
Ok(Self) Ok(raw)
}
}
#[cfg_attr(not(any(test, windows)), allow(dead_code))]
fn windows_vt_output_mode(mode: u32) -> u32 {
const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004;
mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING
}
#[cfg(windows)]
struct WindowsConsoleModeGuard {
output: Option<(windows_sys::Win32::Foundation::HANDLE, u32)>,
}
#[cfg(windows)]
impl WindowsConsoleModeGuard {
fn enter() -> Self {
unsafe {
use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE;
use windows_sys::Win32::System::Console::{
GetConsoleMode, GetStdHandle, STD_OUTPUT_HANDLE, SetConsoleMode,
};
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
if handle.is_null() || handle == INVALID_HANDLE_VALUE {
return Self { output: None };
}
let mut original = 0u32;
if GetConsoleMode(handle, &mut original) == 0 {
return Self { output: None };
}
let desired = windows_vt_output_mode(original);
if desired != original {
let _ = SetConsoleMode(handle, desired);
}
Self {
output: Some((handle, original)),
}
}
}
fn restore(&self) {
if let Some((handle, mode)) = self.output {
unsafe {
use windows_sys::Win32::System::Console::SetConsoleMode;
let _ = SetConsoleMode(handle, mode);
}
}
} }
} }
@@ -10304,6 +10360,8 @@ impl Drop for RawMode {
let mut stdout = std::io::stdout(); let mut stdout = std::io::stdout();
let _ = stdout.write_all(TERMINAL_CLEANUP); let _ = stdout.write_all(TERMINAL_CLEANUP);
let _ = stdout.flush(); let _ = stdout.flush();
#[cfg(windows)]
self.console_modes.restore();
let _ = disable_raw_mode(); let _ = disable_raw_mode();
} }
} }
@@ -10369,7 +10427,7 @@ mod tests {
vscode_command_candidates, vscode_safe_alias, wake_repaint_retry_deadline, vscode_command_candidates, vscode_safe_alias, wake_repaint_retry_deadline,
windows_command_word, windows_deferred_update_script, windows_effective_url_script, windows_command_word, windows_deferred_update_script, windows_effective_url_script,
windows_mode_from_readonly, windows_readonly_from_mode, windows_update_script, windows_mode_from_readonly, windows_readonly_from_mode, windows_update_script,
windows_url_reachable_script, windows_url_reachable_script, windows_vt_output_mode,
}; };
use dosh::config::{ClientConfig, CommandExtension, HostConfig}; use dosh::config::{ClientConfig, CommandExtension, HostConfig};
use dosh::native::EnvVar; use dosh::native::EnvVar;
@@ -10478,6 +10536,13 @@ mod tests {
assert!(!windows_readonly_from_mode(0o755)); assert!(!windows_readonly_from_mode(0o755));
} }
#[test]
fn windows_vt_output_mode_enables_ansi_sequences() {
assert_eq!(windows_vt_output_mode(0), 0x0004);
assert_eq!(windows_vt_output_mode(0x0001), 0x0005);
assert_eq!(windows_vt_output_mode(0x0005), 0x0005);
}
#[test] #[test]
fn cleanup_stream_state_removes_all_per_stream_state_only_for_target() { fn cleanup_stream_state_removes_all_per_stream_state_only_for_target() {
let stream_id = 42; let stream_id = 42;