Skip to content

Commit

Permalink
Reset REPL console mode to permit safely allowing tty, vt sequences o…
Browse files Browse the repository at this point in the history
…n Windows (#36598)

On Windows, when launching external processes, we cannot control what assumption they make on the
console mode. We thus forcibly reset the console mode at the start of the prompt to ensure they do
not leave the console mode in a corrupt state.
  • Loading branch information
musm authored Jul 21, 2020
1 parent 07616a4 commit 34ba868
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 3 deletions.
4 changes: 1 addition & 3 deletions src/support/libsupportinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ static int isInitialized = 0;
void libsupport_init(void)
{
if (!isInitialized) {
#ifdef _OS_WINDOWS_
SetConsoleCP(1252); // ANSI Latin1; Western European (Windows)
#endif

setlocale(LC_ALL, ""); // set to user locale
setlocale(LC_NUMERIC, "C"); // use locale-independent numeric formats

Expand Down
31 changes: 31 additions & 0 deletions stdlib/REPL/src/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1272,8 +1272,39 @@ function write_prompt(terminal, p::Prompt)
return width
end

# On Windows, when launching external processes, we cannot control what assumption they make on the
# console mode. We thus forcibly reset the console mode at the start of the prompt to ensure they do
# not leave the console mode in a corrupt state.
# FIXME: remove when pseudo-tty are implemented for child processes
if Sys.iswindows()
function _console_mode()
hOutput = ccall(:GetStdHandle, stdcall, Ptr{Cvoid}, (UInt32,), -11 % UInt32) # STD_OUTPUT_HANDLE
dwMode = Ref{UInt32}()
ccall(:GetConsoleMode, stdcall, Int32, (Ref{Cvoid}, Ref{UInt32}), hOutput, dwMode)
return dwMode[]
end
const default_console_mode_ref = Ref{UInt32}()
const default_console_mode_assigned = Ref(false)
function get_default_console_mode()
if default_console_mode_assigned[] == false
default_console_mode_assigned[] = true
default_console_mode_ref[] = _console_mode()
end
return default_console_mode_ref[]
end
function _reset_console_mode()
mode = _console_mode()
if mode !== get_default_console_mode()
hOutput = ccall(:GetStdHandle, stdcall, Ptr{Cvoid}, (UInt32,), -11 % UInt32) # STD_OUTPUT_HANDLE
ccall(:SetConsoleMode, stdcall, Int32, (Ptr{Cvoid}, UInt32), hOutput, default_console_mode_ref[])
end
nothing
end
end

# returns the width of the written prompt
function write_prompt(terminal, s::Union{AbstractString,Function})
@static Sys.iswindows() && _reset_console_mode()
promptstr = prompt_string(s)
write(terminal, promptstr)
return textwidth(promptstr)
Expand Down

1 comment on commit 34ba868

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily package evaluation, I will reply here when finished:

@nanosoldier runtests(ALL, isdaily = true)

Please sign in to comment.