Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
Improve ansi escape code support on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
piscisaureus committed Oct 21, 2011
1 parent 2c7e8bb commit fb71386
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 21 deletions.
4 changes: 3 additions & 1 deletion include/uv-private/uv-win.h
Expand Up @@ -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; \
Expand Down
42 changes: 22 additions & 20 deletions src/win/internal.h
Expand Up @@ -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);
Expand Down
160 changes: 160 additions & 0 deletions src/win/tty.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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. */
Expand Down

0 comments on commit fb71386

Please sign in to comment.