Index: win32/win32.c =================================================================== --- win32/win32.c (revision 35600) +++ win32/win32.c (working copy) @@ -5847,6 +5848,10 @@ rb_w32_write_console(uintptr_t strarg, i HANDLE handle; DWORD dwMode, reslen; VALUE str = strarg; + rb_encoding *utf16 = rb_enc_find("UTF-16LE"); + char *ptr; + long len; + static WORD attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; if (disable) return -1L; handle = (HANDLE)_osfhnd(fd); @@ -5854,14 +5859,201 @@ rb_w32_write_console(uintptr_t strarg, i !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE")) return -1L; - str = rb_str_encode(str, rb_enc_from_encoding(rb_enc_find("UTF-16LE")), + str = rb_str_encode(str, rb_enc_from_encoding(utf16), ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil); - if (!WriteConsoleW(handle, (LPWSTR)RSTRING_PTR(str), RSTRING_LEN(str)/2, - &reslen, NULL)) { - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - disable = TRUE; - return -1L; + ptr = RSTRING_PTR(str); + len = RSTRING_LEN(str); + while (len > 0) { + long pos = rb_memsearch(L"\x1B[", 4, ptr, len, utf16); + long curlen = pos < 0 ? len : pos; + if (curlen > 0) { + if (!WriteConsoleW(handle, (LPWSTR)ptr, curlen/2, &reslen, NULL)) { + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + disable = TRUE; + return -1L; + } + ptr += curlen; + len -= curlen; + } + if (pos >= 0) { + int seq = -1; + int rev = 0; + ptr += 4; + len -= 4; + while (len > 1) { + WCHAR w = *(LPWSTR)ptr; + if (w == L';' || w == L'm') { + ptr += 2; + len -= 2; + switch (seq) { + case 0: + attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + rev = 0; + break; + case 4: +#ifndef COMMON_LVB_UNDERSCORE +#define COMMON_LVB_UNDERSCORE 0x8000 +#endif + attr |= COMMON_LVB_UNDERSCORE; + break; + case 7: + rev = 1; + break; + + case 30: + attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); + case 17: + case 31: + attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED; + break; + case 18: + case 32: + attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN; + break; + case 19: + case 33: + attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + case 20: + case 34: + attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE; + break; + case 21: + case 35: + attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED; + break; + case 22: + case 36: + attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN; + break; + case 23: + case 37: + attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + + case 40: + attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED); + case 41: + attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED; + break; + case 42: + attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN; + break; + case 43: + attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; + break; + case 44: + attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE; + break; + case 45: + attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED; + break; + case 46: + attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN; + break; + case 47: + attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; + break; + } + if (rev) { + WORD attr2 = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED) | ((attr & (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)) << 4) | ((attr & (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)) >> 4); + SetConsoleTextAttribute(handle, attr2); + } + else { + SetConsoleTextAttribute(handle, attr); + } + if (w == L'm') { + break; + } + seq = -1; + } + else if (w == L'A') { + CONSOLE_SCREEN_BUFFER_INFO csbi; + ptr += 2; + len -= 2; + if (GetConsoleScreenBufferInfo(handle, &csbi)) { + csbi.dwCursorPosition.Y -= (seq < 0 ? 1 : seq); + if (csbi.dwCursorPosition.Y >= 0) { + SetConsoleCursorPosition(handle, csbi.dwCursorPosition); + } + } + seq = -1; + } + else if (w == L'B') { + CONSOLE_SCREEN_BUFFER_INFO csbi; + ptr += 2; + len -= 2; + if (GetConsoleScreenBufferInfo(handle, &csbi)) { + csbi.dwCursorPosition.Y += (seq < 0 ? 1 : seq); + if (csbi.dwCursorPosition.Y < csbi.dwSize.Y) { + SetConsoleCursorPosition(handle, csbi.dwCursorPosition); + } + } + seq = -1; + } + else if (w == L'C') { + CONSOLE_SCREEN_BUFFER_INFO csbi; + ptr += 2; + len -= 2; + if (GetConsoleScreenBufferInfo(handle, &csbi)) { + csbi.dwCursorPosition.X += (seq < 0 ? 1 : seq); + if (csbi.dwCursorPosition.X < csbi.dwSize.X) { + SetConsoleCursorPosition(handle, csbi.dwCursorPosition); + } + } + seq = -1; + } + else if (w == L'D') { + CONSOLE_SCREEN_BUFFER_INFO csbi; + ptr += 2; + len -= 2; + if (GetConsoleScreenBufferInfo(handle, &csbi)) { + csbi.dwCursorPosition.X -= (seq < 0 ? 1 : seq); + if (csbi.dwCursorPosition.X >= 0) { + SetConsoleCursorPosition(handle, csbi.dwCursorPosition); + } + } + seq = -1; + } + else if (w == L'K') { + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD pos; + DWORD written; + ptr += 2; + len -= 2; + if (GetConsoleScreenBufferInfo(handle, &csbi)) { + switch (seq) { + case 0: /* erase after cursor */ + case -1: + FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written); + break; + case 1: /* erase before cursor */ + pos.X = 0; + pos.Y = csbi.dwCursorPosition.Y; + FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written); + break; + case 2: /* erase entire line */ + pos.X = 0; + pos.Y = csbi.dwCursorPosition.Y; + FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written); + break; + } + } + seq = -1; + break; + } + else if (w >= L'0' && w <= L'9') { + ptr += 2; + len -= 2; + seq = (seq < 0 ? 0 : seq * 10) + w - L'0'; + } + else { + break; + } + } + } } + RB_GC_GUARD(str); return (long)reslen; }