Improve ansi escape code support on windows
This commit is contained in:
parent
2c7e8bb137
commit
fb7138614d
@ -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; \
|
||||
|
||||
@ -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);
|
||||
|
||||
160
src/win/tty.c
160
src/win/tty.c
@ -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. */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user