Improve ansi escape code support on windows

This commit is contained in:
Bert Belder 2011-10-20 19:23:57 -07:00
parent 2c7e8bb137
commit fb7138614d
3 changed files with 185 additions and 21 deletions

View File

@ -313,7 +313,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
/* ansi parser state */ \
unsigned char ansi_parser_state; \
unsigned char ansi_csi_argc; \
unsigned short ansi_csi_argv[4];
unsigned short ansi_csi_argv[4]; \
COORD saved_position; \
WORD saved_attributes;
#define UV_TIMER_PRIVATE_FIELDS \
RB_ENTRY(uv_timer_s) tree_entry; \

View File

@ -44,28 +44,30 @@ void uv_process_timers(uv_loop_t* loop);
*/
/* Private uv_handle flags */
#define UV_HANDLE_CLOSING 0x0001
#define UV_HANDLE_CLOSED 0x0002
#define UV_HANDLE_BOUND 0x0004
#define UV_HANDLE_LISTENING 0x0008
#define UV_HANDLE_CONNECTION 0x0010
#define UV_HANDLE_CONNECTED 0x0020
#define UV_HANDLE_READING 0x0040
#define UV_HANDLE_ACTIVE 0x0040
#define UV_HANDLE_EOF 0x0080
#define UV_HANDLE_SHUTTING 0x0100
#define UV_HANDLE_SHUT 0x0200
#define UV_HANDLE_ENDGAME_QUEUED 0x0400
#define UV_HANDLE_BIND_ERROR 0x1000
#define UV_HANDLE_IPV6 0x2000
#define UV_HANDLE_PIPESERVER 0x4000
#define UV_HANDLE_READ_PENDING 0x8000
#define UV_HANDLE_UV_ALLOCED 0x10000
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x20000
#define UV_HANDLE_ZERO_READ 0x40000
#define UV_HANDLE_TTY_RAW 0x80000
#define UV_HANDLE_CLOSING 0x000001
#define UV_HANDLE_CLOSED 0x000002
#define UV_HANDLE_BOUND 0x000004
#define UV_HANDLE_LISTENING 0x000008
#define UV_HANDLE_CONNECTION 0x000010
#define UV_HANDLE_CONNECTED 0x000020
#define UV_HANDLE_READING 0x000040
#define UV_HANDLE_ACTIVE 0x000040
#define UV_HANDLE_EOF 0x000080
#define UV_HANDLE_SHUTTING 0x000100
#define UV_HANDLE_SHUT 0x000200
#define UV_HANDLE_ENDGAME_QUEUED 0x000400
#define UV_HANDLE_BIND_ERROR 0x001000
#define UV_HANDLE_IPV6 0x002000
#define UV_HANDLE_PIPESERVER 0x004000
#define UV_HANDLE_READ_PENDING 0x008000
#define UV_HANDLE_UV_ALLOCED 0x010000
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x020000
#define UV_HANDLE_ZERO_READ 0x040000
#define UV_HANDLE_TTY_RAW 0x080000
#define UV_HANDLE_EMULATE_IOCP 0x100000
#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x200000
#define UV_HANDLE_TTY_SAVED_POSITION 0x400000
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x800000
void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle);
void uv_process_endgames(uv_loop_t* loop);

View File

@ -898,6 +898,64 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
}
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
const COORD origin = {0, 0};
const WORD char_attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_RED;
CONSOLE_SCREEN_BUFFER_INFO info;
DWORD count, written;
if (*error != ERROR_SUCCESS) {
return -1;
}
/* Reset original text attributes. */
if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
*error = GetLastError();
return -1;
}
/* Move the cursor position to (0, 0). */
if (!SetConsoleCursorPosition(handle->handle, origin)) {
*error = GetLastError();
return -1;
}
/* Clear the screen buffer. */
retry:
if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
*error = GetLastError();
return -1;
}
count = info.dwSize.X * info.dwSize.Y;
if (!(FillConsoleOutputCharacterW(handle->handle,
L'\x20',
count,
origin,
&written) &&
FillConsoleOutputAttribute(handle->handle,
char_attrs,
written,
origin,
&written))) {
if (GetLastError() == ERROR_INVALID_PARAMETER) {
/* The console may be resized - retry */
goto retry;
} else {
*error = GetLastError();
return -1;
}
}
/* Move the virtual window up to the top. */
uv_tty_virtual_offset = 0;
uv_tty_update_virtual_window(&info);
return 0;
}
static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
DWORD* error) {
unsigned short argc = handle->ansi_csi_argc;
@ -1084,6 +1142,76 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
}
static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
DWORD* error) {
CONSOLE_SCREEN_BUFFER_INFO info;
if (*error != ERROR_SUCCESS) {
return -1;
}
if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
*error = GetLastError();
return -1;
}
uv_tty_update_virtual_window(&info);
handle->saved_position.X = info.dwCursorPosition.X;
handle->saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
if (save_attributes) {
handle->saved_attributes = info.wAttributes &
(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
}
return 0;
}
static int uv_tty_restore_state(uv_tty_t* handle,
unsigned char restore_attributes, DWORD* error) {
CONSOLE_SCREEN_BUFFER_INFO info;
WORD new_attributes;
if (*error != ERROR_SUCCESS) {
return -1;
}
if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
if (uv_tty_move_caret(handle,
handle->saved_position.X,
0,
handle->saved_position.Y,
0,
error) != 0) {
return -1;
}
}
if (restore_attributes &&
(handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
*error = GetLastError();
return -1;
}
new_attributes = info.wAttributes;
new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
new_attributes |= handle->saved_attributes;
if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
*error = GetLastError();
return -1;
}
}
return 0;
}
static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t bufs[], int bufcnt,
DWORD* error) {
/* We can only write 8k characters at a time. Windows can't handle */
@ -1204,6 +1332,26 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t bufs[], int bufcnt,
/* Ignore double escape. */
continue;
case 'c':
/* Full console reset. */
uv_tty_reset(handle, error);
ansi_parser_state = ANSI_NORMAL;
continue;
case '7':
/* Save the cursor position and text attributes. */
FLUSH_TEXT();
uv_tty_save_state(handle, 1, error);
ansi_parser_state = ANSI_NORMAL;
continue;
case '8':
/* Restore the cursor position and text attributes */
FLUSH_TEXT();
uv_tty_restore_state(handle, 1, error);
ansi_parser_state = ANSI_NORMAL;
continue;
default:
if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
/* Single-char control. */
@ -1360,6 +1508,18 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t bufs[], int bufcnt,
FLUSH_TEXT();
uv_tty_set_style(handle, error);
break;
case 's':
/* Save the cursor position. */
FLUSH_TEXT();
uv_tty_save_state(handle, 0, error);
break;
case 'u':
/* Restore the cursor position */
FLUSH_TEXT();
uv_tty_restore_state(handle, 0, error);
break;
}
/* Sequence ended - go back to normal state. */