Skip to content

Commit 4efcdc6

Browse files
committed
windows: roll back console state if terminal set fails partway
1 parent bddc609 commit 4efcdc6

1 file changed

Lines changed: 43 additions & 18 deletions

File tree

src/terminal/windows.rs

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -428,28 +428,53 @@ impl WindowsTerminal {
428428
let original_output_mode = output.get_mode()?;
429429
let original_input_cp = input.get_code_page()?;
430430
let original_output_cp = output.get_code_page()?;
431-
if mode == InputReaderMode::Vte {
432-
input.set_code_page(CP_UTF8)?;
433-
output.set_code_page(CP_UTF8)?;
434-
}
435431

436-
// Enable VT processing for the output handle.
437-
let desired_output_mode = original_output_mode
438-
| Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING
439-
| Console::DISABLE_NEWLINE_AUTO_RETURN;
440-
if output.set_mode(desired_output_mode).is_err() {
441-
bail!("virtual terminal processing could not be enabled for the output handle");
442-
}
432+
// Switch the console to UTF-8 + VT modes. Each step mutates global console state, and a
433+
// later step can fail. Because there is no `WindowsTerminal` yet, `Drop` won't run, so on
434+
// any failure we must roll back to the original values here.
435+
let reader = match (|| -> io::Result<EventReader> {
436+
if mode == InputReaderMode::Vte {
437+
input.set_code_page(CP_UTF8)?;
438+
output.set_code_page(CP_UTF8)?;
439+
}
443440

444-
if mode == InputReaderMode::Vte {
445-
// And now the input handle too.
446-
let desired_input_mode = original_input_mode | Console::ENABLE_VIRTUAL_TERMINAL_INPUT;
447-
if input.set_mode(desired_input_mode).is_err() {
448-
bail!("virtual terminal processing could not be enabled for the input handle");
441+
// Enable VT processing for the output handle.
442+
let desired_output_mode = original_output_mode
443+
| Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING
444+
| Console::DISABLE_NEWLINE_AUTO_RETURN;
445+
output.set_mode(desired_output_mode).map_err(|_| {
446+
io::Error::new(
447+
io::ErrorKind::Other,
448+
"virtual terminal processing could not be enabled for the output handle",
449+
)
450+
})?;
451+
452+
if mode == InputReaderMode::Vte {
453+
// And now the input handle too.
454+
let desired_input_mode =
455+
original_input_mode | Console::ENABLE_VIRTUAL_TERMINAL_INPUT;
456+
input.set_mode(desired_input_mode).map_err(|_| {
457+
io::Error::new(
458+
io::ErrorKind::Other,
459+
"virtual terminal processing could not be enabled for the input handle",
460+
)
461+
})?;
449462
}
450-
}
451463

452-
let reader = EventReader::new(WindowsEventSource::new(input.try_clone()?, mode)?);
464+
Ok(EventReader::new(WindowsEventSource::new(
465+
input.try_clone()?,
466+
mode,
467+
)?))
468+
})() {
469+
Ok(reader) => reader,
470+
Err(err) => {
471+
let _ = input.set_code_page(original_input_cp);
472+
let _ = output.set_code_page(original_output_cp);
473+
let _ = input.set_mode(original_input_mode);
474+
let _ = output.set_mode(original_output_mode);
475+
return Err(err);
476+
}
477+
};
453478

454479
Ok(Self {
455480
input,

0 commit comments

Comments
 (0)