Skip to content

Commit

Permalink
win32: use native ANSI sequence processing, if possible
Browse files Browse the repository at this point in the history
Windows 10 version 1511 (also known as Anniversary Update), according to
https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
introduced native support for ANSI sequence processing. This allows
using colors from the entire 24-bit color range.

All we need to do is test whether the console's "virtual processing
support" can be enabled. If it can, we do not even need to start the
`console_thread` to handle ANSI sequences.

Or, almost all we need to do: When `console_thread()` does its work, it
uses the Unicode-aware `write_console()` function to write to the Win32
Console, which supports Git for Windows' implicit convention that all
text that is written is encoded in UTF-8. The same is not necessarily
true if native ANSI sequence processing is used, as the output is then
subject to the current code page. Let's ensure that the code page is set
to `CP_UTF8` as long as Git writes to it.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
dscho committed Sep 18, 2024
1 parent f8b122e commit f1898a0
Showing 1 changed file with 46 additions and 0 deletions.
46 changes: 46 additions & 0 deletions compat/winansi.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,49 @@ static void detect_msys_tty(int fd)

#endif

static HANDLE std_console_handle;
static DWORD std_console_mode = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
static UINT std_console_code_page = CP_UTF8;

static void reset_std_console(void)
{
if (std_console_mode != ENABLE_VIRTUAL_TERMINAL_PROCESSING)
SetConsoleMode(std_console_handle, std_console_mode);
if (std_console_code_page != CP_UTF8)
SetConsoleOutputCP(std_console_code_page);
}

static int enable_virtual_processing(void)
{
std_console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (std_console_handle == INVALID_HANDLE_VALUE ||
!GetConsoleMode(std_console_handle, &std_console_mode)) {
std_console_handle = GetStdHandle(STD_ERROR_HANDLE);
if (std_console_handle == INVALID_HANDLE_VALUE ||
!GetConsoleMode(std_console_handle, &std_console_mode))
return 0;
}

std_console_code_page = GetConsoleOutputCP();
if (std_console_code_page != CP_UTF8)
SetConsoleOutputCP(CP_UTF8);
if (!std_console_code_page)
std_console_code_page = CP_UTF8;

atexit(reset_std_console);

if (std_console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
return 1;

if (!SetConsoleMode(std_console_handle,
std_console_mode |
ENABLE_PROCESSED_OUTPUT |
ENABLE_VIRTUAL_TERMINAL_PROCESSING))
return 0;

return 1;
}

/*
* Wrapper for isatty(). Most calls in the main git code
* call isatty(1 or 2) to see if the instance is interactive
Expand Down Expand Up @@ -629,6 +672,9 @@ void winansi_init(void)
return;
}

if (enable_virtual_processing())
return;

/* create a named pipe to communicate with the console thread */
if (swprintf(name, ARRAY_SIZE(name) - 1, L"\\\\.\\pipe\\winansi%lu",
GetCurrentProcessId()) < 0)
Expand Down

0 comments on commit f1898a0

Please sign in to comment.