Add VT sequences input support ##windows (#16747)

* Add VT sequences input support ##windows

* Fix radare2 immediately exiting when console is redirected to pipe
* Hack to get viewport size under MinTTY
* Fix mouse when VT input disabled and buffer scrolled
* Fix line wrapping when VT output disabled

* Fix build on VS2017

* Fix for comments

* fix some weirdness

* Fix losing echo after exiting
This commit is contained in:
GustavoLCR 2020-05-03 06:31:52 -03:00 committed by GitHub
parent 502b4b0f52
commit 153de56173
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 254 additions and 126 deletions

View File

@ -134,7 +134,7 @@ static void __break_signal(int sig) {
static inline void __cons_write_ll(const char *buf, int len) {
#if __WINDOWS__
if (I.ansicon) {
if (I.vtmode) {
(void) write (I.fdout, buf, len);
} else {
if (I.fdout == 1) {
@ -471,17 +471,21 @@ R_API void r_cons_enable_highlight(const bool enable) {
}
R_API bool r_cons_enable_mouse(const bool enable) {
#if __UNIX__
const char *click = enable
? "\x1b[?1000;1006;1015h"
: "\x1b[?1001r" "\x1b[?1000l";
#if __WINDOWS__
if (I.vtmode == 2) {
#endif
const char *click = enable
? "\x1b[?1000;1006;1015h"
: "\x1b[?1001r"
"\x1b[?1000l";
// : "\x1b[?1000;1006;1015l";
// const char *old = enable ? "\x1b[?1001s" "\x1b[?1000h" : "\x1b[?1001r" "\x1b[?1000l";
bool enabled = I.mouse;
I.mouse = enable;
write (2, click, strlen (click));
return enabled;
#elif __WINDOWS__
// const char *old = enable ? "\x1b[?1001s" "\x1b[?1000h" : "\x1b[?1001r" "\x1b[?1000l";
bool enabled = I.mouse;
I.mouse = enable;
write (2, click, strlen (click));
return enabled;
#if __WINDOWS__
}
DWORD mode, mouse;
HANDLE h;
bool enabled = I.mouse;
@ -537,7 +541,9 @@ R_API RCons *r_cons_new() {
I.num = NULL;
I.null = 0;
#if __WINDOWS__
I.ansicon = r_cons_is_ansicon ();
I.vtmode = r_cons_is_vtcompat ();
#else
I.vtmode = 2;
#endif
#if EMSCRIPTEN
/* do nothing here :? */
@ -659,7 +665,7 @@ R_API void r_cons_fill_line() {
R_API void r_cons_clear_line(int std_err) {
#if __WINDOWS__
if (I.ansicon) {
if (I.vtmode) {
fprintf (std_err? stderr: stdout,"%s", R_CONS_CLEAR_LINE);
} else {
char white[1024];
@ -962,7 +968,7 @@ R_API void r_cons_visual_flush() {
if (!I.null) {
/* TODO: this ifdef must go in the function body */
#if __WINDOWS__
if (I.ansicon) {
if (I.vtmode) {
r_cons_visual_write (I.context->buffer);
} else {
r_cons_w32_print (I.context->buffer, I.context->buffer_len, true);
@ -997,7 +1003,7 @@ R_API void r_cons_print_fps (int col) {
col = 12;
}
#ifdef __WINDOWS__
if (I.ansicon) {
if (I.vtmode) {
eprintf ("\x1b[0;%dH[%d FPS] \n", w - col, fps);
} else {
r_cons_w32_gotoxy (2, w - col, 0);
@ -1279,17 +1285,75 @@ R_API bool r_cons_isatty() {
return false;
}
#if __WINDOWS__
static int __xterm_get_cur_pos(int *xpos) {
int ypos = 0;
const char *get_pos = R_CONS_GET_CURSOR_POSITION;
if (write (I.fdout, get_pos, sizeof (get_pos)) < 1) {
return 0;
}
int ch = r_cons_readchar ();
if (ch != 0x1b) {
while (ch = r_cons_readchar_timeout (25)) {
if (ch < 1) {
return 0;
}
if (ch == 0x1b) {
break;
}
}
}
(void)r_cons_readchar ();
char pos[16] = { 0 };
size_t i;
for (i = 0; i < sizeof (pos); i++) {
if ((ch = r_cons_readchar ()) == ';') {
break;
}
pos[i] = ch;
}
ypos = atoi (pos);
pos[0] = '\0';
for (i = 0; i < sizeof (pos); i++) {
if ((ch = r_cons_readchar ()) == 'R') {
break;
}
pos[i] = ch;
}
*xpos = atoi (pos);
return ypos;
}
static bool __xterm_get_size(void) {
if (write (I.fdout, R_CONS_CURSOR_SAVE, sizeof (R_CONS_CURSOR_SAVE)) < 1) {
return false;
}
(void)write (I.fdout, "\x1b[999;999H", sizeof ("\x1b[999;999H"));
I.rows = __xterm_get_cur_pos (&I.columns);
(void)write (I.fdout, R_CONS_CURSOR_RESTORE, sizeof (R_CONS_CURSOR_RESTORE));
return true;
}
#endif
// XXX: if this function returns <0 in rows or cols expect MAYHEM
R_API int r_cons_get_size(int *rows) {
#if __WINDOWS__
CONSOLE_SCREEN_BUFFER_INFO csbi;
bool ret = GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &csbi);
I.columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
I.rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
if (!ret || (I.columns == -1 && I.rows == 0)) {
// Stdout is probably redirected so we set default values
I.columns = 80;
I.rows = 23;
if (ret) {
I.columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
I.rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
} else {
if (I.term_xterm) {
ret = __xterm_get_size ();
}
if (!ret || (I.columns == -1 && I.rows == 0)) {
// Stdout is probably redirected so we set default values
I.columns = 80;
I.rows = 23;
}
}
#elif EMSCRIPTEN
I.columns = 80;
@ -1361,11 +1425,31 @@ R_API int r_cons_get_size(int *rows) {
}
#if __WINDOWS__
R_API bool r_cons_is_ansicon(void) {
R_API int r_cons_is_vtcompat(void) {
DWORD major;
DWORD minor;
DWORD release = 0;
bool win_support = false;
char *wt_session = r_sys_getenv ("WT_SESSION");
if (wt_session) {
free (wt_session);
return 2;
}
char *term = r_sys_getenv ("TERM");
if (term) {
if (strstr (term, "xterm")) {
I.term_xterm = 1;
free (term);
return 2;
}
I.term_xterm = 0;
free (term);
}
char *ansicon = r_sys_getenv ("ANSICON");
if (ansicon) {
free (ansicon);
return 1;
}
bool win_support = 0;
RSysInfo *info = r_sys_info ();
if (info && info->version) {
char *dot = strtok (info->version, ".");
@ -1378,22 +1462,17 @@ R_API bool r_cons_is_ansicon(void) {
if (major > 10
|| (major == 10 && minor > 0)
|| (major == 10 && minor == 0 && release >= 1703)) {
win_support = true;
win_support = 1;
}
}
r_sys_info_free (info);
char *ansicon = r_sys_getenv ("ANSICON");
if (ansicon) {
free (ansicon);
win_support = true;
}
return win_support;
}
#endif
R_API void r_cons_show_cursor(int cursor) {
#if __WINDOWS__
if (I.ansicon) {
if (I.vtmode) {
#endif
write (1, cursor ? "\x1b[?25h" : "\x1b[?25l", 6);
#if __WINDOWS__
@ -1446,9 +1525,17 @@ R_API void r_cons_set_raw(bool is_raw) {
}
#elif __WINDOWS__
if (is_raw) {
SetConsoleMode (h, I.term_raw);
if (I.term_xterm) {
r_sandbox_system ("stty raw -echo", 1);
} else {
SetConsoleMode (h, I.term_raw);
}
} else {
SetConsoleMode (h, I.term_buf);
if (I.term_xterm) {
r_sandbox_system ("stty -raw echo", 1);
} else {
SetConsoleMode (h, I.term_buf);
}
}
#else
#warning No raw console supported for this platform
@ -1503,7 +1590,7 @@ R_API void r_cons_set_cup(int enable) {
write (2, code, strlen (code));
fflush (stdout);
#elif __WINDOWS__
if (I.ansicon) {
if (I.vtmode) {
if (enable) {
const char *code =
"\x1b[?1049h" // xterm
@ -1793,7 +1880,7 @@ R_API void r_cons_cmd_help(const char *help[], bool use_color) {
}
R_API void r_cons_clear_buffer(void) {
#if __UNIX__
write (1, "\x1b" "c\x1b[3J", 6);
#endif
if (I.vtmode) {
write (1, "\x1b" "c\x1b[3J", 6);
}
}

View File

@ -259,7 +259,7 @@ static int r_line_readchar_utf8(ut8 *s, int slen) {
#if __WINDOWS__
static int r_line_readchar_win(ut8 *s, int slen) { // this function handle the input in console mode
INPUT_RECORD irInBuf;
INPUT_RECORD irInBuf = { { 0 } };
BOOL ret, bCtrl = FALSE;
DWORD mode, out;
char buf[5] = {0};
@ -275,13 +275,17 @@ static int r_line_readchar_win(ut8 *s, int slen) { // this function handle the i
}
return 1;
}
h = GetStdHandle (STD_INPUT_HANDLE);
DWORD new_mode = I.vtmode == 2 ? ENABLE_VIRTUAL_TERMINAL_INPUT : 0;
GetConsoleMode (h, &mode);
SetConsoleMode (h, 0); // RAW
SetConsoleMode (h, new_mode);
do_it_again:
bed = r_cons_sleep_begin ();
ret = ReadConsoleInput (h, &irInBuf, 1, &out);
if (r_cons_singleton()->term_xterm) {
ret = ReadFile (h, buf, 1, &out, NULL);
} else {
ret = ReadConsoleInput (h, &irInBuf, 1, &out);
}
r_cons_sleep_end (bed);
if (ret < 1) {
return 0;
@ -1530,12 +1534,16 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) {
break;
case 27: // esc-5b-41-00-00 alt/meta key
#if __WINDOWS__
memmove (buf, buf + 1, strlen (buf));
if (!buf[0]) {
buf[0] = -1;
if (I.vtmode != 2) {
memmove (buf, buf + 1, strlen (buf));
if (!buf[0]) {
buf[0] = -1;
}
} else {
#endif
buf[0] = r_cons_readchar_timeout (50);
#if __WINDOWS__
}
#else
buf[0] = r_cons_readchar_timeout (50);
#endif
switch (buf[0]) {
case 127: // alt+bkspace
@ -1590,29 +1598,29 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) {
}
break;
default:
#if !__WINDOWS__
buf[1] = r_cons_readchar_timeout (50);
if (buf[1] == -1) {
r_cons_break_pop ();
return NULL;
if (I.vtmode == 2) {
buf[1] = r_cons_readchar_timeout (50);
if (buf[1] == -1) {
r_cons_break_pop ();
return NULL;
}
}
#endif
if (buf[0] == 0x5b) { // [
switch (buf[1]) {
case '3': // supr
case '3': // supr
__delete_next_char ();
#if !__WINDOWS__
buf[1] = r_cons_readchar ();
if (buf[1] == -1) {
r_cons_break_pop ();
return NULL;
if (I.vtmode == 2) {
buf[1] = r_cons_readchar ();
if (buf[1] == -1) {
r_cons_break_pop ();
return NULL;
}
}
#endif
break;
case '5': // pag up
#if !__WINDOWS__
buf[1] = r_cons_readchar ();
#endif
if (I.vtmode == 2) {
buf[1] = r_cons_readchar ();
}
if (I.hud) {
I.hud->top_entry_n -= (rows - 1);
if (I.hud->top_entry_n < 0) {
@ -1625,9 +1633,9 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) {
}
break;
case '6': // pag down
#if !__WINDOWS__
buf[1] = r_cons_readchar ();
#endif
if (I.vtmode == 2) {
buf[1] = r_cons_readchar ();
}
if (I.hud) {
I.hud->top_entry_n += (rows - 1);
if (I.hud->top_entry_n >= I.hud->current_entry_n) {
@ -1693,18 +1701,21 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) {
__move_cursor_left ();
break;
case 0x31: // control + arrow
#if __WINDOWS__
ch = buf[2];
#else
ch = r_cons_readchar ();
if (ch == 0x7e) { // HOME in screen/tmux
// corresponding END is 0x34 below (the 0x7e is ignored there)
I.buffer.index = 0;
break;
if (I.vtmode == 2) {
ch = r_cons_readchar ();
if (ch == 0x7e) { // HOME in screen/tmux
// corresponding END is 0x34 below (the 0x7e is ignored there)
I.buffer.index = 0;
break;
}
r_cons_readchar ();
}
#if __WINDOWS__
else {
ch = buf[2];
}
r_cons_readchar ();
int fkey = ch - '0';
#endif
int fkey = ch - '0';
switch (ch) {
case 0x41:
// first
@ -1739,15 +1750,11 @@ R_API const char *r_line_readline_cb(RLineReadCallback cb, void *user) {
}
break;
default:
#if __WINDOWS__
// ...
#else
{
if (I.vtmode == 2) {
if (I.cb_fkey) {
I.cb_fkey (I.user, fkey);
}
}
#endif
break;
}
r_cons_set_raw (1);

View File

@ -98,29 +98,31 @@ static bool is_arrow;
R_API int r_cons_arrow_to_hjkl(int ch) {
#if __WINDOWS__
if (is_arrow) {
switch (ch) {
case VK_DOWN: // key down
ch = bCtrl ? 'J' : 'j';
break;
case VK_RIGHT: // key right
ch = bCtrl ? 'L' : 'l';
break;
case VK_UP: // key up
ch = bCtrl ? 'K' : 'k';
break;
case VK_LEFT: // key left
ch = bCtrl ? 'H' : 'h';
break;
case VK_PRIOR: // key home
ch = 'K';
break;
case VK_NEXT: // key end
ch = 'J';
break;
if (I->vtmode != 2) {
if (is_arrow) {
switch (ch) {
case VK_DOWN: // key down
ch = bCtrl ? 'J' : 'j';
break;
case VK_RIGHT: // key right
ch = bCtrl ? 'L' : 'l';
break;
case VK_UP: // key up
ch = bCtrl ? 'K' : 'k';
break;
case VK_LEFT: // key left
ch = bCtrl ? 'H' : 'h';
break;
case VK_PRIOR: // key home
ch = 'K';
break;
case VK_NEXT: // key end
ch = 'J';
break;
}
}
return I->mouse_event && (ut8)ch == UT8_MAX ? 0 : ch;
}
return I->mouse_event && (ut8)ch == UT8_MAX ? 0 : ch;
#endif
I->mouse_event = 0;
/* emacs */
@ -416,14 +418,18 @@ static int __cons_readchar_w32(ut32 usec) {
is_arrow = false;
DWORD mode, out;
HANDLE h;
INPUT_RECORD irInBuf;
INPUT_RECORD irInBuf = { { 0 } };
CONSOLE_SCREEN_BUFFER_INFO info = { { 0 } };
bool resize = false;
bool click_n_drag = false;
void *bed;
I->mouse_event = 0;
h = GetStdHandle (STD_INPUT_HANDLE);
GetConsoleMode (h, &mode);
SetConsoleMode (h, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS);
DWORD newmode = I->vtmode == 2
? ENABLE_VIRTUAL_TERMINAL_INPUT
: ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS;
SetConsoleMode (h, newmode);
do {
bed = r_cons_sleep_begin ();
if (usec) {
@ -432,8 +438,12 @@ static int __cons_readchar_w32(ut32 usec) {
return -1;
}
}
ret = ReadConsoleInput (h, &irInBuf, 1, &out);
r_cons_enable_mouse (true);
if (I->term_xterm) {
ret = ReadFile (h, &ch, 1, &out, NULL);
} else {
ret = ReadConsoleInput (h, &irInBuf, 1, &out);
}
r_cons_sleep_end (bed);
if (ret) {
if (irInBuf.EventType == MOUSE_EVENT) {
@ -453,7 +463,9 @@ static int __cons_readchar_w32(ut32 usec) {
}
switch (irInBuf.Event.MouseEvent.dwButtonState) {
case FROM_LEFT_1ST_BUTTON_PRESSED:
r_cons_set_click (irInBuf.Event.MouseEvent.dwMousePosition.X + 1, irInBuf.Event.MouseEvent.dwMousePosition.Y + 1);
GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
int rel_y = irInBuf.Event.MouseEvent.dwMousePosition.Y - info.srWindow.Top;
r_cons_set_click (irInBuf.Event.MouseEvent.dwMousePosition.X + 1, rel_y + 1);
ch = UT8_MAX;
break;
case RIGHTMOST_BUTTON_PRESSED:
@ -532,7 +544,9 @@ static int __cons_readchar_w32(ut32 usec) {
resize = false;
}
}
FlushConsoleInputBuffer (h);
if (I->vtmode != 2 && !I->term_xterm) {
FlushConsoleInputBuffer (h);
}
} while (ch == 0);
SetConsoleMode (h, mode);
return ch;
@ -593,10 +607,10 @@ R_API int r_cons_readchar() {
memmove (readbuffer, readbuffer + 1, readbuffer_length);
return ch;
}
r_cons_set_raw (1);
#if __WINDOWS__
return __cons_readchar_w32 (0);
#else
r_cons_set_raw (1);
void *bed = r_cons_sleep_begin ();
// Blocks until either stdin has something to read or a signal happens.

View File

@ -20,7 +20,9 @@ R_API RLine *r_line_new(void) {
I.kill_ring = r_list_newf (NULL);
I.kill_ring_ptr = -1;
#if __WINDOWS__
I.ansicon = r_cons_is_ansicon ();
I.vtmode = r_cons_is_vtcompat ();
#else
I.vtmode = 2;
#endif
if (!r_line_dietline_init ()) {
eprintf ("error: r_line_dietline_init\n");

View File

@ -24,6 +24,10 @@ R_API void r_cons_w32_clear(void) {
static CONSOLE_SCREEN_BUFFER_INFO csbi;
COORD startCoords;
DWORD dummy;
if (I->vtmode) {
r_cons_strcat (Color_RESET R_CONS_CLEAR_SCREEN);
return;
}
if (I->is_wine == 1) {
write (1, "\033[0;0H\033[0m\033[2J", 6 + 4 + 4);
}
@ -50,6 +54,10 @@ R_API void r_cons_w32_gotoxy(int fd, int x, int y) {
COORD coord;
coord.X = x;
coord.Y = y;
if (I->vtmode) {
r_cons_printf ("\x1b[%d;%dH", y, x);
return;
}
if (I->is_wine == 1) {
write (fd, "\x1b[0;0H", 6);
}
@ -403,7 +411,7 @@ R_API int r_cons_win_vhprintf(DWORD hdl, bool vmode, const char *fmt, va_list ap
FILE *con = hdl == STD_OUTPUT_HANDLE ? stdout : stderr;
if (!strchr (fmt, '%')) {
size_t len = strlen (fmt);
if (I->ansicon) {
if (I->vtmode) {
return fwrite (fmt, 1, len, con);
}
return r_cons_w32_hprint (hdl, fmt, len, vmode);
@ -414,7 +422,7 @@ R_API int r_cons_win_vhprintf(DWORD hdl, bool vmode, const char *fmt, va_list ap
char *buf = calloc (1, num_chars);
if (buf) {
(void)vsnprintf (buf, num_chars, fmt, ap);
if (I->ansicon) {
if (I->vtmode) {
ret = fwrite (buf, 1, num_chars - 1, con);
} else {
ret = r_cons_w32_hprint (hdl, buf, num_chars - 1, vmode);

View File

@ -2089,26 +2089,37 @@ static bool cb_scrhighlight(void *user, void *data) {
}
#if __WINDOWS__
static bool scr_ansicon(void *user, void *data) {
static bool scr_vtmode(void *user, void *data) {
RConfigNode *node = (RConfigNode *) data;
if (!strcmp (node->value, "true")) {
if (r_str_is_true (node->value)) {
node->i_value = 1;
}
r_line_singleton ()->ansicon = r_cons_singleton ()->ansicon = node->i_value;
HANDLE streams[] = { GetStdHandle (STD_OUTPUT_HANDLE), GetStdHandle (STD_ERROR_HANDLE) };
node->i_value = node->i_value > 2 ? 2 : node->i_value;
r_line_singleton ()->vtmode = r_cons_singleton ()->vtmode = node->i_value;
DWORD mode;
HANDLE input = GetStdHandle (STD_INPUT_HANDLE);
GetConsoleMode (input, &mode);
if (node->i_value == 2) {
SetConsoleMode (input, mode & ENABLE_VIRTUAL_TERMINAL_INPUT);
r_cons_singleton ()->term_raw = ENABLE_VIRTUAL_TERMINAL_INPUT;
} else {
SetConsoleMode (input, mode & ~ENABLE_VIRTUAL_TERMINAL_INPUT);
r_cons_singleton ()->term_raw = 0;
}
HANDLE streams[] = { GetStdHandle (STD_OUTPUT_HANDLE), GetStdHandle (STD_ERROR_HANDLE) };
int i;
if (node->i_value == 1) { // scr.ansicon=2 to show esc seqs (for debugging) if using non-ConEmu-hosted cmd.exe
if (node->i_value > 0) {
for (i = 0; i < R_ARRAY_SIZE (streams); i++) {
GetConsoleMode (streams[i], &mode);
SetConsoleMode (streams[i],
mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
}
} else {
for (i = 0; i < R_ARRAY_SIZE (streams); i++) {
GetConsoleMode (streams[i], &mode);
SetConsoleMode (streams[i],
mode & ~ENABLE_VIRTUAL_TERMINAL_PROCESSING);
mode & ~ENABLE_VIRTUAL_TERMINAL_PROCESSING & ~ENABLE_WRAP_AT_EOL_OUTPUT);
}
}
return true;
@ -3518,8 +3529,8 @@ R_API int r_core_config_init(RCore *core) {
SETBPREF ("scr.slow", "true", "Do slow stuff on visual mode like RFlag.get_at(true)");
SETCB ("scr.prompt.popup", "false", &cb_scr_prompt_popup, "Show widget dropdown for autocomplete");
#if __WINDOWS__
SETICB ("scr.ansicon", r_cons_singleton ()->ansicon,
&scr_ansicon, "Use ANSICON mode or not on Windows");
SETICB ("scr.vtmode", r_cons_singleton ()->vtmode,
&scr_vtmode, "Use VT sequences on Windows (0: Disable, 1: Output, 2: Input & Output)");
#endif
#if __ANDROID__
SETBPREF ("scr.responsive", "true", "Auto-adjust Visual depending on screen (e.g. unset asm.bytes)");

View File

@ -40,6 +40,9 @@ extern "C" {
# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
# endif
# ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
# define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
# endif
#else
#include <unistd.h>
#endif
@ -494,7 +497,7 @@ typedef struct r_cons_t {
#if __UNIX__
struct termios term_raw, term_buf;
#elif __WINDOWS__
DWORD term_raw, term_buf;
DWORD term_raw, term_buf, term_xterm;
#endif
RNum *num;
/* Pager (like more or less) to use if the output doesn't fit on the
@ -510,9 +513,7 @@ typedef struct r_cons_t {
const char **vline;
int refcnt;
R_DEPRECATE bool newline;
#if __WINDOWS__
int ansicon;
#endif
int vtmode;
bool flush;
bool use_utf8; // use utf8 features
bool use_utf8_curvy; // use utf8 curved corners
@ -827,7 +828,7 @@ R_API int r_cons_pipe_open(const char *file, int fdn, int append);
R_API void r_cons_pipe_close(int fd);
#if __WINDOWS__
R_API bool r_cons_is_ansicon(void);
R_API int r_cons_is_vtcompat(void);
R_API void r_cons_w32_clear(void);
R_API void r_cons_w32_gotoxy(int fd, int x, int y);
R_API int r_cons_w32_print(const char *ptr, int len, bool vmode);
@ -1070,9 +1071,7 @@ struct r_line_t {
RLineHud *hud;
RList *sdbshell_hist;
RListIter *sdbshell_hist_iter;
#if __WINDOWS__
int ansicon;
#endif
int vtmode;
}; /* RLine */
#ifdef R_API