diff --git a/Cargo.toml b/Cargo.toml index f765a271..0185ea0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ byteorder = "1.2.1" dirs = "1.0.2" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["wincon", "handleapi", "fileapi"] } +winapi = { version = "0.3", features = ["consoleapi", "wincon", "handleapi", "fileapi"] } [features] default=[] diff --git a/src/terminfo/mod.rs b/src/terminfo/mod.rs index d9d17bc4..9cfe40cc 100644 --- a/src/terminfo/mod.rs +++ b/src/terminfo/mod.rs @@ -18,6 +18,10 @@ use std::io; use std::io::BufReader; use std::path::Path; + +#[cfg(windows)] +use win; + use Attr; use color; use Terminal; @@ -67,6 +71,17 @@ impl TermInfo { } }) }); + + #[cfg(windows)] + { + if term_name.is_none() && win::supports_ansi() { + // Microsoft people seem to be fine with pretending to be xterm: + // https://github.com/Microsoft/WSL/issues/1446 + // The basic ANSI fallback terminal will be uses. + return TermInfo::from_name("xterm"); + } + } + if let Some(term_name) = term_name { return TermInfo::from_name(term_name); } else { diff --git a/src/win.rs b/src/win.rs index 71c82789..58d3a93f 100644 --- a/src/win.rs +++ b/src/win.rs @@ -14,25 +14,26 @@ extern crate winapi; -use std::io::prelude::*; +use color; use std::io; +use std::io::prelude::*; use std::ops::Deref; use std::ptr; use Attr; use Error; use Result; use Terminal; -use color; -use win::winapi::um::wincon::{SetConsoleCursorPosition, SetConsoleTextAttribute, BACKGROUND_INTENSITY}; -use win::winapi::um::wincon::{FillConsoleOutputCharacterW, GetConsoleScreenBufferInfo, COORD}; -use win::winapi::um::wincon::FillConsoleOutputAttribute; use win::winapi::shared::minwindef::{DWORD, WORD}; -use win::winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE}; +use win::winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; use win::winapi::um::fileapi::{CreateFileA, OPEN_EXISTING}; +use win::winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE}; +use win::winapi::um::wincon::FillConsoleOutputAttribute; +use win::winapi::um::wincon::{FillConsoleOutputCharacterW, GetConsoleScreenBufferInfo, COORD}; +use win::winapi::um::wincon::{SetConsoleCursorPosition, SetConsoleTextAttribute}; +use win::winapi::um::wincon::{BACKGROUND_INTENSITY, ENABLE_VIRTUAL_TERMINAL_PROCESSING}; use win::winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE}; - /// Console info which can be used by a Terminal implementation /// which uses the Win32 Console API. pub struct WinConsoleInfo { @@ -116,7 +117,7 @@ impl Deref for HandleWrapper { } } -// Just get a handle to the current console buffer whatever it is +/// Just get a handle to the current console buffer whatever it is fn conout() -> io::Result { let name = b"CONOUT$\0"; let handle = unsafe { @@ -137,6 +138,25 @@ fn conout() -> io::Result { } } +unsafe fn set_flag(handle: HANDLE, flag: DWORD) -> io::Result<()> { + let mut curr_mode: DWORD = 0; + if GetConsoleMode(handle, &mut curr_mode) == 0 { + return Err(io::Error::last_os_error()); + } + + if SetConsoleMode(handle, curr_mode | flag) == 0 { + return Err(io::Error::last_os_error()); + } + return Ok(()); +} + +/// Check if console supports ansi codes (should succeed on Windows 10) +pub fn supports_ansi() -> bool { + conout() + .and_then(|handle| unsafe { set_flag(*handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING) }) + .is_ok() +} + // This test will only pass if it is running in an actual console, probably #[test] fn test_conout() { @@ -183,7 +203,7 @@ impl WinConsole { }; if self.info.secure { - fg = bg; + fg = bg; } let mut accum: WORD = 0; @@ -205,10 +225,7 @@ impl WinConsole { /// Create a new WinConsole with the given WinConsoleInfo and out pub fn new_with_consoleinfo(out: T, info: WinConsoleInfo) -> WinConsole { - WinConsole { - buf: out, - info, - } + WinConsole { buf: out, info } } /// Returns `Err` whenever the terminal cannot be created for some