use Handle;
#[cfg(windows)]
use winapi;
#[cfg(windows)]
use kernel32;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TerminalMode {
Redir,
Term,
#[cfg(windows)]
Cygwin,
#[cfg(windows)]
Console,
#[cfg(windows)]
Win10,
}
impl TerminalMode {
#[cfg(not(windows))]
pub(super) fn from_handle(handle: Handle) -> TerminalMode {
match unsafe { ::libc::isatty(handle.fd()) } {
0 => TerminalMode::Redir,
_ => TerminalMode::Term,
}
}
#[cfg(windows)]
pub(super) fn from_handle(handle: Handle) -> TerminalMode {
match handle.console_mode() {
ConsoleMode::Legacy => return TerminalMode::Console,
ConsoleMode::Win10 => return TerminalMode::Win10,
ConsoleMode::None => (),
}
let hndl = unsafe { kernel32::GetStdHandle(handle as winapi::DWORD) };
match msys_cygwin(hndl) {
Some(true) => TerminalMode::Cygwin,
_ => TerminalMode::Redir,
}
}
}
#[cfg(windows)]
fn msys_cygwin(hndl: winapi::HANDLE) -> Option<bool> {
use std::os::windows::ffi::OsStringExt;
let sz = ::std::mem::size_of::<winapi::FILE_NAME_INFO>();
let mut raw_info = vec![0u8; sz + winapi::MAX_PATH];
let ok = unsafe {
kernel32::GetFileInformationByHandleEx(
hndl,
winapi::FILE_INFO_BY_HANDLE_CLASS(2),
raw_info.as_mut_ptr() as winapi::LPVOID,
raw_info.len() as winapi::DWORD,
)
};
if ok == 0 {
return None;
}
let file_info =
unsafe { *(raw_info[0..sz].as_ptr() as *const winapi::FILE_NAME_INFO) };
let name = &raw_info[sz..sz + file_info.FileNameLength as usize];
let name = unsafe {
::std::slice::from_raw_parts(
name.as_ptr() as *const winapi::WCHAR,
name.len() / 2,
)
};
let name = ::std::ffi::OsString::from_wide(name);
let name = name.to_string_lossy();
if name.starts_with("\\cygwin-") || name.starts_with("\\msys-") {
Some(true)
} else {
Some(false)
}
}
#[cfg(windows)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConsoleMode {
None,
Legacy,
Win10,
}
#[cfg(windows)]
impl Default for ConsoleMode {
fn default() -> ConsoleMode {
ConsoleMode::None
}
}
#[cfg(windows)]
const ENABLE_VIRTUAL_TERMINAL_PROCESSING: winapi::DWORD = 0x0004;
#[cfg(windows)]
const ENABLE_VIRTUAL_TERMINAL_INPUT: winapi::DWORD = 0x0200;
#[cfg(windows)]
impl ConsoleMode {
pub(super) fn from_out_handle(hndl: winapi::HANDLE) -> ConsoleMode {
if hndl == winapi::INVALID_HANDLE_VALUE {
return ConsoleMode::None;
}
unsafe {
let mut mode: winapi::DWORD = 0;
if 0 == kernel32::GetConsoleMode(hndl, &mut mode) {
return ConsoleMode::None;
}
if (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0 {
return ConsoleMode::Win10;
}
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if 0 == kernel32::SetConsoleMode(hndl, mode) {
ConsoleMode::Legacy
} else {
ConsoleMode::Win10
}
}
}
pub(super) fn from_in_handle(hndl: winapi::HANDLE) -> ConsoleMode {
if hndl == winapi::INVALID_HANDLE_VALUE {
return ConsoleMode::None;
}
unsafe {
let mut mode: winapi::DWORD = 0;
if 0 == kernel32::GetConsoleMode(hndl, &mut mode) {
return ConsoleMode::None;
}
if (mode & ENABLE_VIRTUAL_TERMINAL_INPUT) != 0 {
return ConsoleMode::Win10;
}
let newmode = mode | ENABLE_VIRTUAL_TERMINAL_INPUT;
if 0 == kernel32::SetConsoleMode(hndl, newmode) {
kernel32::SetConsoleMode(hndl, mode);
ConsoleMode::Legacy
} else {
kernel32::SetConsoleMode(hndl, mode);
ConsoleMode::Win10
}
}
}
}