This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Improve ansi escape code support on windows

  • Loading branch information...
piscisaureus committed Oct 21, 2011
1 parent 2c7e8bb commit fb7138614daa42f737799833d45eb4ea3268c8a7
Showing with 185 additions and 21 deletions.
  1. +3 −1 include/uv-private/uv-win.h
  2. +22 −20 src/win/internal.h
  3. +160 −0 src/win/tty.c
@@ -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
@@ -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
@@ -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. */

0 comments on commit fb71386

Please sign in to comment.