From 19303a75fce05450741d759fa9d094fbe401774f Mon Sep 17 00:00:00 2001 From: Mohammad AlSaleh Date: Wed, 22 Aug 2018 21:13:18 +0300 Subject: [PATCH 1/3] win: Add conout_supports_ansi() Signed-off-by: Mohammad AlSaleh --- Cargo.toml | 2 +- src/win.rs | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) 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/win.rs b/src/win.rs index 71c82789..e4e9c4e7 100644 --- a/src/win.rs +++ b/src/win.rs @@ -24,7 +24,9 @@ use Result; use Terminal; use color; -use win::winapi::um::wincon::{SetConsoleCursorPosition, SetConsoleTextAttribute, BACKGROUND_INTENSITY}; +use win::winapi::um::wincon::{SetConsoleCursorPosition, SetConsoleTextAttribute}; +use win::winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; +use win::winapi::um::wincon::{ENABLE_VIRTUAL_TERMINAL_PROCESSING, BACKGROUND_INTENSITY}; use win::winapi::um::wincon::{FillConsoleOutputCharacterW, GetConsoleScreenBufferInfo, COORD}; use win::winapi::um::wincon::FillConsoleOutputAttribute; use win::winapi::shared::minwindef::{DWORD, WORD}; @@ -116,8 +118,7 @@ impl Deref for HandleWrapper { } } -// Just get a handle to the current console buffer whatever it is -fn conout() -> io::Result { +fn conout_with_flag(flag: Option) -> io::Result { let name = b"CONOUT$\0"; let handle = unsafe { CreateFileA( @@ -133,10 +134,36 @@ fn conout() -> io::Result { if handle == INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else { + if let Some(flag) = flag { + let mut curr_mode: DWORD = 0; + unsafe { + if GetConsoleMode(handle, &mut curr_mode) == 0 { + let err = Err(io::Error::last_os_error()); + drop(HandleWrapper::new(handle)); + return err; + } + + if SetConsoleMode(handle, curr_mode | flag) == 0 { + let err = Err(io::Error::last_os_error()); + drop(HandleWrapper::new(handle)); + return err; + } + } + } Ok(HandleWrapper::new(handle)) } } +/// Check if console supports ansi codes (should succeed on Windows 10) +pub fn conout_supports_ansi() -> bool { + conout_with_flag(Some(ENABLE_VIRTUAL_TERMINAL_PROCESSING)).is_ok() +} + +// Just get a handle to the current console buffer whatever it is +fn conout() -> io::Result { + conout_with_flag(None) +} + // This test will only pass if it is running in an actual console, probably #[test] fn test_conout() { From f4400b104e65e0ff7b5747e9f771c6b3f02782d1 Mon Sep 17 00:00:00 2001 From: Mohammad AlSaleh Date: Sat, 3 Nov 2018 02:07:53 +0200 Subject: [PATCH 2/3] Pretend to be xterm if Windows console supports ansi Windows people seem to be fine with this: https://github.com/Microsoft/WSL/issues/1446 I still think a precise terminfo file with the list of supported sequences documented in the below link would be ideal: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences But I didn't find such a file. And I don't know how to generate one easily. Signed-off-by: Mohammad AlSaleh --- src/terminfo/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/terminfo/mod.rs b/src/terminfo/mod.rs index d9d17bc4..6fd78fca 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::conout_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 { From 67a1d78a8cacc1657137433c16ec31715407de90 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 9 Jan 2019 12:30:25 -0800 Subject: [PATCH 3/3] separate conout_supports_ansi and conout And rename to `supports_ansi`. --- src/terminfo/mod.rs | 2 +- src/win.rs | 64 +++++++++++++++++++-------------------------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/terminfo/mod.rs b/src/terminfo/mod.rs index 6fd78fca..9cfe40cc 100644 --- a/src/terminfo/mod.rs +++ b/src/terminfo/mod.rs @@ -74,7 +74,7 @@ impl TermInfo { #[cfg(windows)] { - if term_name.is_none() && win::conout_supports_ansi() { + 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. diff --git a/src/win.rs b/src/win.rs index e4e9c4e7..58d3a93f 100644 --- a/src/win.rs +++ b/src/win.rs @@ -14,27 +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}; -use win::winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; -use win::winapi::um::wincon::{ENABLE_VIRTUAL_TERMINAL_PROCESSING, 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 { @@ -118,7 +117,8 @@ impl Deref for HandleWrapper { } } -fn conout_with_flag(flag: Option) -> io::Result { +/// Just get a handle to the current console buffer whatever it is +fn conout() -> io::Result { let name = b"CONOUT$\0"; let handle = unsafe { CreateFileA( @@ -134,34 +134,27 @@ fn conout_with_flag(flag: Option) -> io::Result { if handle == INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else { - if let Some(flag) = flag { - let mut curr_mode: DWORD = 0; - unsafe { - if GetConsoleMode(handle, &mut curr_mode) == 0 { - let err = Err(io::Error::last_os_error()); - drop(HandleWrapper::new(handle)); - return err; - } - - if SetConsoleMode(handle, curr_mode | flag) == 0 { - let err = Err(io::Error::last_os_error()); - drop(HandleWrapper::new(handle)); - return err; - } - } - } Ok(HandleWrapper::new(handle)) } } -/// Check if console supports ansi codes (should succeed on Windows 10) -pub fn conout_supports_ansi() -> bool { - conout_with_flag(Some(ENABLE_VIRTUAL_TERMINAL_PROCESSING)).is_ok() +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(()); } -// Just get a handle to the current console buffer whatever it is -fn conout() -> io::Result { - conout_with_flag(None) +/// 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 @@ -210,7 +203,7 @@ impl WinConsole { }; if self.info.secure { - fg = bg; + fg = bg; } let mut accum: WORD = 0; @@ -232,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