Skip to content

Commit e0021de

Browse files
Yury Samkevichfacebook-github-bot
authored andcommitted
implement interactive terminal for windows
Summary: Implementation of interactive terminal, that never was implemented for windows. First we remember console mode and disable `ENABLE_ECHO_INPUT` and `ENABLE_LINE_INPUT` to get input as soon as one or more characters are available. (see [documentation](https://learn.microsoft.com/en-us/windows/console/setconsolemode)) When disabling interactive terminal we simply restore original console mode Reviewed By: ezgicicek Differential Revision: D69985905 fbshipit-source-id: fb381766c1d2961f7e132ccf9cce87510d0acc3f
1 parent 460a3e6 commit e0021de

File tree

1 file changed

+46
-2
lines changed

1 file changed

+46
-2
lines changed

app/buck2_client_ctx/src/console_interaction_stream.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,58 @@ mod interactive_terminal {
111111

112112
#[cfg(windows)]
113113
mod interactive_terminal {
114-
pub struct InteractiveTerminal;
114+
use std::io::IsTerminal;
115+
use std::os::windows::io::AsRawHandle;
116+
117+
use buck2_error::BuckErrorContext;
118+
use winapi::shared::minwindef::DWORD;
119+
use winapi::um::consoleapi::GetConsoleMode;
120+
use winapi::um::consoleapi::SetConsoleMode;
121+
use winapi::um::wincon::ENABLE_ECHO_INPUT;
122+
use winapi::um::wincon::ENABLE_LINE_INPUT;
123+
use winapi::um::winnt::HANDLE;
124+
125+
fn get_console_mode(handle: HANDLE) -> buck2_error::Result<DWORD> {
126+
let mut mode: DWORD = 0;
127+
if unsafe { GetConsoleMode(handle, &mut mode) } != 0 {
128+
Ok(mode)
129+
} else {
130+
Err(std::io::Error::last_os_error()).buck_error_context("Failed to get console mode")
131+
}
132+
}
133+
134+
fn set_console_mode(handle: HANDLE, mode: DWORD) -> buck2_error::Result<()> {
135+
if unsafe { SetConsoleMode(handle, mode) != 0 } {
136+
Ok(())
137+
} else {
138+
Err(std::io::Error::last_os_error()).buck_error_context("Failed to set console mode")
139+
}
140+
}
141+
142+
pub struct InteractiveTerminal {
143+
mode: DWORD,
144+
}
115145

116146
impl InteractiveTerminal {
117147
pub fn enable() -> buck2_error::Result<Option<Self>> {
118-
Ok(None)
148+
let handle = std::io::stdin().as_raw_handle();
149+
150+
if !std::io::stdin().is_terminal()
151+
|| !std::io::stdout().is_terminal()
152+
|| !std::io::stderr().is_terminal()
153+
{
154+
return Ok(None);
155+
}
156+
157+
let mode = get_console_mode(handle)?;
158+
// Switch to non-canonical mode to get input immediately, and disable echo.
159+
set_console_mode(handle, mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))?;
160+
Ok(Some(Self { mode }))
119161
}
120162

121163
pub fn disable(&mut self) -> buck2_error::Result<()> {
164+
let handle = std::io::stdin().as_raw_handle();
165+
set_console_mode(handle, self.mode)?;
122166
Ok(())
123167
}
124168
}

0 commit comments

Comments
 (0)