support terminal colors for cmd.exe and msys pty

See #302
This commit is contained in:
Andrew Kelley 2017-10-02 01:37:05 -04:00
parent b3f3db46be
commit 0a4283b38b
3 changed files with 164 additions and 12 deletions

View File

@ -10,12 +10,6 @@
#include <stdio.h>
#define RED "\x1b[31;1m"
#define GREEN "\x1b[32;1m"
#define CYAN "\x1b[36;1m"
#define WHITE "\x1b[37;1m"
#define RESET "\x1b[0m"
enum ErrType {
ErrTypeError,
ErrTypeNote,
@ -27,12 +21,26 @@ static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type)
size_t col = err->column_start + 1;
const char *text = buf_ptr(err->msg);
if (color == ErrColorOn || (color == ErrColorAuto && os_stderr_tty())) {
bool is_tty = os_stderr_tty();
if (color == ErrColorOn || (color == ErrColorAuto && is_tty)) {
if (err_type == ErrTypeError) {
fprintf(stderr, WHITE "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": " RED "error:" WHITE " %s" RESET "\n", path, line, col, text);
os_stderr_set_color(TermColorWhite);
fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col);
os_stderr_set_color(TermColorRed);
fprintf(stderr, "error:");
os_stderr_set_color(TermColorWhite);
fprintf(stderr, " %s", text);
os_stderr_set_color(TermColorReset);
fprintf(stderr, "\n");
} else if (err_type == ErrTypeNote) {
fprintf(stderr, WHITE "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": " CYAN "note:" WHITE " %s" RESET "\n", path, line, col, text);
os_stderr_set_color(TermColorWhite);
fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col);
os_stderr_set_color(TermColorCyan);
fprintf(stderr, "note:");
os_stderr_set_color(TermColorWhite);
fprintf(stderr, " %s", text);
os_stderr_set_color(TermColorReset);
fprintf(stderr, "\n");
} else {
zig_unreachable();
}
@ -41,7 +49,10 @@ static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type)
for (size_t i = 0; i < err->column_start; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, GREEN "^" RESET "\n");
os_stderr_set_color(TermColorGreen);
fprintf(stderr, "^");
os_stderr_set_color(TermColorReset);
fprintf(stderr, "\n");
} else {
if (err_type == ErrTypeError) {
fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": error: %s\n", path, line, col, text);

View File

@ -639,9 +639,68 @@ int os_get_cwd(Buf *out_cwd) {
#endif
}
#if defined(ZIG_OS_WINDOWS)
#define is_wprefix(s, prefix) \
(wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0)
static bool is_stderr_cyg_pty(void) {
HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
if (stderr_handle == INVALID_HANDLE_VALUE)
return false;
HANDLE h;
int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH;
FILE_NAME_INFO *nameinfo;
WCHAR *p = NULL;
// Cygwin/msys's pty is a pipe.
if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) {
return 0;
}
nameinfo = (FILE_NAME_INFO *)allocate<char>(size);
if (nameinfo == NULL) {
return 0;
}
// Check the name of the pipe:
// '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master'
if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) {
nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0';
p = nameinfo->FileName;
if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */
p += 8;
} else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */
p += 6;
} else {
p = NULL;
}
if (p != NULL) {
while (*p && isxdigit(*p)) /* Skip 16-digit hexadecimal. */
++p;
if (is_wprefix(p, L"-pty")) {
p += 4;
} else {
p = NULL;
}
}
if (p != NULL) {
while (*p && isdigit(*p)) /* Skip pty number. */
++p;
if (is_wprefix(p, L"-from-master")) {
//p += 12;
} else if (is_wprefix(p, L"-to-master")) {
//p += 10;
} else {
p = NULL;
}
}
}
free(nameinfo);
return (p != NULL);
}
#endif
bool os_stderr_tty(void) {
#if defined(ZIG_OS_WINDOWS)
return _isatty(_fileno(stderr)) != 0;
return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty();
#elif defined(ZIG_OS_POSIX)
return isatty(STDERR_FILENO) != 0;
#else
@ -859,3 +918,76 @@ int os_self_exe_path(Buf *out_path) {
#endif
return ErrorFileNotFound;
}
#define VT_RED "\x1b[31;1m"
#define VT_GREEN "\x1b[32;1m"
#define VT_CYAN "\x1b[36;1m"
#define VT_WHITE "\x1b[37;1m"
#define VT_RESET "\x1b[0m"
static void set_color_posix(TermColor color) {
switch (color) {
case TermColorRed:
fprintf(stderr, VT_RED);
break;
case TermColorGreen:
fprintf(stderr, VT_GREEN);
break;
case TermColorCyan:
fprintf(stderr, VT_CYAN);
break;
case TermColorWhite:
fprintf(stderr, VT_WHITE);
break;
case TermColorReset:
fprintf(stderr, VT_RESET);
break;
}
}
void os_stderr_set_color(TermColor color) {
#if defined(ZIG_OS_WINDOWS)
if (is_stderr_cyg_pty()) {
set_color_posix(color);
return;
}
HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
if (stderr_handle == INVALID_HANDLE_VALUE)
zig_panic("unable to get stderr handle");
fflush(stderr);
DWORD ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
if (color != TermColorReset) {
DWORD mode_flags = 0;
GetConsoleMode(stderr_handle, &mode_flags);
mode_flags |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(stderr_handle, mode_flags);
}
DWORD chars_written;
switch (color) {
case TermColorRed:
WriteConsole(stderr_handle, VT_RED, strlen(VT_RED), &chars_written, NULL);
break;
case TermColorGreen:
WriteConsole(stderr_handle, VT_GREEN, strlen(VT_GREEN), &chars_written, NULL);
break;
case TermColorCyan:
WriteConsole(stderr_handle, VT_CYAN, strlen(VT_CYAN), &chars_written, NULL);
break;
case TermColorWhite:
WriteConsole(stderr_handle, VT_WHITE, strlen(VT_WHITE), &chars_written, NULL);
break;
case TermColorReset:
{
WriteConsole(stderr_handle, VT_RESET, strlen(VT_RESET), &chars_written, NULL);
DWORD mode_flags = 0;
GetConsoleMode(stderr_handle, &mode_flags);
mode_flags &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(stderr_handle, mode_flags);
break;
}
}
#else
set_color_posix(color);
#endif
}

View File

@ -15,6 +15,14 @@
#include <stdio.h>
#include <inttypes.h>
enum TermColor {
TermColorRed,
TermColorGreen,
TermColorCyan,
TermColorWhite,
TermColorReset,
};
enum TerminationId {
TerminationIdClean,
TerminationIdSignaled,
@ -53,6 +61,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents);
int os_get_cwd(Buf *out_cwd);
bool os_stderr_tty(void);
void os_stderr_set_color(TermColor color);
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
int os_delete_file(Buf *path);