Skip to content

Commit 6fa79c8

Browse files
committed
win32: use native ANSI sequence processing, if possible
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 <[email protected]>
1 parent 38993b5 commit 6fa79c8

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

compat/winansi.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,49 @@ static void detect_msys_tty(int fd)
593593

594594
#endif
595595

596+
static HANDLE std_console_handle;
597+
static DWORD std_console_mode = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
598+
static UINT std_console_code_page = CP_UTF8;
599+
600+
static void reset_std_console(void)
601+
{
602+
if (std_console_mode != ENABLE_VIRTUAL_TERMINAL_PROCESSING)
603+
SetConsoleMode(std_console_handle, std_console_mode);
604+
if (std_console_code_page != CP_UTF8)
605+
SetConsoleOutputCP(std_console_code_page);
606+
}
607+
608+
static int enable_virtual_processing(void)
609+
{
610+
std_console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
611+
if (std_console_handle == INVALID_HANDLE_VALUE ||
612+
!GetConsoleMode(std_console_handle, &std_console_mode)) {
613+
std_console_handle = GetStdHandle(STD_ERROR_HANDLE);
614+
if (std_console_handle == INVALID_HANDLE_VALUE ||
615+
!GetConsoleMode(std_console_handle, &std_console_mode))
616+
return 0;
617+
}
618+
619+
std_console_code_page = GetConsoleOutputCP();
620+
if (std_console_code_page != CP_UTF8)
621+
SetConsoleOutputCP(CP_UTF8);
622+
if (!std_console_code_page)
623+
std_console_code_page = CP_UTF8;
624+
625+
atexit(reset_std_console);
626+
627+
if (std_console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
628+
return 1;
629+
630+
if (!SetConsoleMode(std_console_handle,
631+
std_console_mode |
632+
ENABLE_PROCESSED_OUTPUT |
633+
ENABLE_VIRTUAL_TERMINAL_PROCESSING))
634+
return 0;
635+
636+
return 1;
637+
}
638+
596639
/*
597640
* Wrapper for isatty(). Most calls in the main git code
598641
* call isatty(1 or 2) to see if the instance is interactive
@@ -631,6 +674,9 @@ void winansi_init(void)
631674
return;
632675
}
633676

677+
if (enable_virtual_processing())
678+
return;
679+
634680
/* create a named pipe to communicate with the console thread */
635681
if (swprintf(name, ARRAY_SIZE(name) - 1, L"\\\\.\\pipe\\winansi%lu",
636682
GetCurrentProcessId()) < 0)

0 commit comments

Comments
 (0)